├── DB └── README.md ├── Procfile ├── photos ├── logo.jpg ├── help_msg.jpg ├── screen_1.png ├── logo_spot_deez.png ├── row-1-column-1.jpg ├── row-1-column-2.jpg ├── logo_spot_deez_fin.png ├── bot_about.md ├── bot_description.md └── bot_commands.md ├── req.txt ├── utils ├── converter_bytes.py ├── special_thread.py ├── utils_graphs.py ├── utils_users_bot.py ├── utils.py └── utils_data.py ├── .deez_settings.ini ├── Dockerfile ├── is_executing.py ├── docker-compose.yml ├── fly.toml ├── configs ├── set_configs.py ├── bot_settings.py └── customs.py ├── .github └── workflows │ └── docker-publish.yml ├── README.md ├── .gitignore ├── inlines ├── inline_keyboards.py └── inline_query_results.py ├── helpers ├── db_help.py └── download_help.py └── deez_bot.py /DB/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python /app/deez_bot.py 2 | -------------------------------------------------------------------------------- /photos/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/logo.jpg -------------------------------------------------------------------------------- /photos/help_msg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/help_msg.jpg -------------------------------------------------------------------------------- /photos/screen_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/screen_1.png -------------------------------------------------------------------------------- /photos/logo_spot_deez.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/logo_spot_deez.png -------------------------------------------------------------------------------- /photos/row-1-column-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/row-1-column-1.jpg -------------------------------------------------------------------------------- /photos/row-1-column-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/row-1-column-2.jpg -------------------------------------------------------------------------------- /photos/logo_spot_deez_fin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/Deezer-Bot/master/photos/logo_spot_deez_fin.png -------------------------------------------------------------------------------- /photos/bot_about.md: -------------------------------------------------------------------------------- 1 | BOT DEVELOPED BY @anonimia 2 | I think art should be free and music is such a beautiful art🤯🔥. -------------------------------------------------------------------------------- /req.txt: -------------------------------------------------------------------------------- 1 | deezloader 2 | python-telegram-bot==13.12 3 | pyrogram 4 | tgcrypto 5 | python-acrcloud 6 | libtmux 7 | matplotlib -------------------------------------------------------------------------------- /utils/converter_bytes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def convert_bytes_to(size, b_format): 4 | b_formats = ["kb", "mb", "gb", "tb"] 5 | index = b_formats.index(b_format) + 1 6 | in_bytes = 1000 ** index 7 | size /= in_bytes 8 | 9 | return size -------------------------------------------------------------------------------- /.deez_settings.ini: -------------------------------------------------------------------------------- 1 | [deez_login] 2 | mail = 3 | pwd = 4 | arl = 5 | 6 | [spot_login] 7 | mail = 8 | pwd = 9 | 10 | [pyrogram] 11 | api_id = 12 | api_hash = 13 | 14 | [telegram] 15 | bot_token = 16 | fsub_chat_id = 17 | fsub_chat_link = 18 | 19 | [acrcloud] 20 | key = 21 | secret = 22 | host = -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:slim 2 | 3 | RUN apt-get -y update 4 | RUN apt-get -y upgrade 5 | RUN apt-get install -y ffmpeg gcc 6 | 7 | WORKDIR /app 8 | 9 | COPY req.txt req.txt 10 | 11 | RUN pip install --upgrade pip 12 | RUN pip install -r req.txt 13 | 14 | COPY . /app 15 | 16 | 17 | CMD [ "python", "/app/deez_bot.py"] 18 | -------------------------------------------------------------------------------- /photos/bot_description.md: -------------------------------------------------------------------------------- 1 | Hello guys welcome in @DeezSpot_bot⚡️. 2 | DISCLAIMER: 3 | 1): DO NOT USE THIS BOT FOR YOUR OWN PURPOSE 4 | 2): I AM NOT RESPONSABLE FOR ANY ILLEGIT USAGE 5 | 3): The source code can be found here: 6 | a): https://github.com/An0nimia/DeezSpot_bot 7 | b): https://pypi.org/project/deezloader 8 | 4): ENJOY THE MUSIC ART🔥 -------------------------------------------------------------------------------- /photos/bot_commands.md: -------------------------------------------------------------------------------- 1 | start - Start this bot to have such a nice day :) 2 | settings - Set your settings 3 | quality - Set quality download 4 | managing_banned - ADMIN ONLY I AM LAZY 5 | add_banned - ADMIN ONLY I AM LAZY 6 | shazam - Let me listen this audio 7 | kill_dw - Kill current downloads💣 8 | info - Show me something about this bot 9 | reasons - WHY THIS BOT EXIST? 10 | help - SOMEBODY HELP ME👨‍🚒 11 | feedback - Have you questions?🙋‍♂️ 12 | donate - ONLY IF YOU ARE RICH🥺💸 13 | graphs - BOT STATS📊 -------------------------------------------------------------------------------- /is_executing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from os import popen 4 | from time import sleep 5 | from psutil import process_iter, AccessDenied 6 | 7 | interested = [ 8 | "pid", "name" 9 | ] 10 | 11 | script = "deez_bot.py" 12 | cmd = f"screen -S Deez_Bot_Anonimia python3 {script}" 13 | 14 | def bot_exist(): 15 | exist = False 16 | 17 | for proc in process_iter(interested): 18 | try: 19 | cmdline = " ".join( 20 | proc.cmdline() 21 | ) 22 | 23 | if ("python" in cmdline) and (script in cmdline): 24 | exist = True 25 | break 26 | except AccessDenied: 27 | pass 28 | 29 | return exist 30 | 31 | while True: 32 | exist = bot_exist() 33 | 34 | if exist: 35 | print(f"THE BOT IS RUNNING") 36 | else: 37 | print(f"THE BOT IS NOT RUNNING") 38 | 39 | if not exist: 40 | popen(cmd).read() 41 | 42 | sleep(4) -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | deezspot_bot: 6 | image: j0n4n/deezspot_bot 7 | container_name: deezspot_bot 8 | environment: 9 | MODE_BOT: 10 | WARNING_BANNING: 11 | USER_ERRORS: 12 | BUNKER_CHANNEL: 13 | OWL_CHANNEL: 14 | ROOT_ID: 15 | METHOD_SAVE: 16 | DOWNLOAD_DIR_MAX_SIZE: 17 | PROGRESS_STATUS_RATE: 18 | TIME_SLEEP: 19 | SECONDS_LIMITS_ALBUM: 20 | SECONDS_LIMITS_TRACK: 21 | UPLOAD_MAX_SIZE_USER: 22 | MAX_SONGS_PER_PLAYLIST: 23 | MAX_DOWNLOAD_USER: 24 | BOT_NAME: 25 | FORUM: 26 | EMAIL_DEE: 27 | PWD_DEE: 28 | EMAIL_SPO: 29 | PWD_SPO: 30 | BOT_TOKEN: 31 | ACRCLOUD_KEY: 32 | ACRCLOUD_SECRET: 33 | ACRCLOUD_HOST: 34 | API_ID: 35 | API_HASH: 36 | volumes: 37 | -./DB:/app/DB 38 | -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml file generated for deezspot_bot_docker on 2022-12-17T11:20:37+05:30 2 | 3 | app = "deezspot_bot_docker" 4 | kill_signal = "SIGINT" 5 | kill_timeout = 5 6 | processes = [] 7 | 8 | [build] 9 | image = "j0n4n/deezspot_bot_docker" 10 | 11 | [env] 12 | USER_ERRORS = "-" 13 | BUNKER_CHANNEL = "-" 14 | OWL_CHANNEL = "-" 15 | ROOT_ID = "" 16 | BOT_NAME = "@" 17 | EMAIL_DEE = "" 18 | PWD_DEE = "" 19 | EMAIL_SPO = "" 20 | PWD_SPO = "" 21 | BOT_TOKEN = "" 22 | API_ID = "" 23 | API_HASH = "" 24 | 25 | 26 | [experimental] 27 | allowed_public_ports = [] 28 | auto_rollback = true 29 | 30 | [[services]] 31 | http_checks = [] 32 | internal_port = 8080 33 | processes = ["app"] 34 | protocol = "tcp" 35 | script_checks = [] 36 | [services.concurrency] 37 | hard_limit = 25 38 | soft_limit = 20 39 | type = "connections" 40 | 41 | [[services.ports]] 42 | force_https = true 43 | handlers = ["http"] 44 | port = 80 45 | 46 | [[services.ports]] 47 | handlers = ["tls", "http"] 48 | port = 443 49 | 50 | [[services.tcp_checks]] 51 | grace_period = "1s" 52 | interval = "15s" 53 | restart_limit = 0 54 | timeout = "2s" 55 | 56 | -------------------------------------------------------------------------------- /utils/special_thread.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from inspect import isclass 4 | 5 | from ctypes import ( 6 | c_long, py_object, pythonapi 7 | ) 8 | 9 | from threading import ( 10 | Thread, ThreadError, _active 11 | ) 12 | 13 | def _async_raise(tid, exctype): 14 | if not isclass(exctype): 15 | raise TypeError("Only types can be raised (not instances)") 16 | 17 | res = pythonapi.PyThreadState_SetAsyncExc( 18 | c_long(tid), py_object(exctype) 19 | ) 20 | 21 | if res == 0: 22 | raise ValueError("invalid thread id") 23 | 24 | elif res != 1: 25 | pythonapi.PyThreadState_SetAsyncExc(tid, 0) 26 | 27 | raise SystemError("PyThreadState_SetAsyncExc failed") 28 | 29 | class magicThread(Thread): 30 | def _get_my_tid(self): 31 | if not self.is_alive(): 32 | raise ThreadError("the thread is not active") 33 | 34 | if hasattr(self, "_thread_id"): 35 | return self._thread_id 36 | 37 | for tid, tobj in _active.items(): 38 | if tobj is self: 39 | self._thread_id = tid 40 | return tid 41 | 42 | raise AssertionError("could not determine the thread's id") 43 | 44 | def raise_exc(self, exctype): 45 | _async_raise( 46 | self._get_my_tid(), exctype 47 | ) 48 | 49 | def kill(self): 50 | self.raise_exc(SystemExit) -------------------------------------------------------------------------------- /configs/set_configs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from pyrogram import Client 4 | from acrcloud import ACRcloud 5 | from telegram.ext import Updater 6 | from deezloader.deezloader import DeeLogin 7 | from deezloader.spotloader import SpoLogin 8 | from .bot_settings import user_session 9 | import os 10 | 11 | 12 | class SetConfigs: 13 | queues_started, queues_finished = 0, 0 14 | 15 | # __arl_token = os.environ.get("ARL_TOKEN") 16 | __email_dee = os.environ.get("EMAIL_DEE") 17 | __pwd_dee = os.environ.get("PWD_DEE") 18 | 19 | __email_spo = os.environ.get("EMAIL_SPO") 20 | __pwd_spo = os.environ.get("PWD_SPO") 21 | 22 | __bot_token = os.environ.get("BOT_TOKEN") 23 | 24 | __acrcloud_key = os.environ.get("ACRCLOUD_KEY") 25 | __acrcloud_secret = os.environ.get("ACRCLOUD_SECRET") 26 | __acrcloud_host = os.environ.get("ACRCLOUD_HOST") 27 | 28 | __api_id = int(os.environ.get("API_ID")) 29 | __api_hash = os.environ.get("API_HASH") 30 | 31 | __acrcloud_config = { 32 | "key": __acrcloud_key, 33 | "secret": __acrcloud_secret, 34 | "host": __acrcloud_host, 35 | } 36 | 37 | __fsub_chat_id = os.environ.get("FSUB_CHAT_ID") 38 | __fsub_chat_link = os.environ.get("FSUB_CHAT_LINK") 39 | 40 | @classmethod 41 | def __init__(cls, mode_bot): 42 | if mode_bot in [3, 4]: 43 | cls.create_zips = False 44 | else: 45 | cls.create_zips = True 46 | 47 | cls.tg_bot_api = Updater(token=cls.__bot_token) 48 | cls.tg_bot_id = cls.tg_bot_api.bot.name 49 | cls.__fsub_chat_id = int(cls.__fsub_chat_id) 50 | cls.__fsub_chat_link = cls.__fsub_chat_link 51 | 52 | cls.deez_api = DeeLogin( 53 | # arl = cls.__arl_token, 54 | email=cls.__email_dee, 55 | password=cls.__pwd_dee, 56 | ) 57 | 58 | if cls.__email_spo: 59 | cls.spot_api = SpoLogin(cls.__email_spo, cls.__pwd_spo) 60 | 61 | if cls.__acrcloud_key: 62 | cls.acrcloud_api = ACRcloud(cls.__acrcloud_config) 63 | 64 | cls.tg_user_api = Client( 65 | user_session, 66 | api_id=cls.__api_id, 67 | api_hash=cls.__api_hash, 68 | bot_token=cls.__bot_token, 69 | ) 70 | cls.tg_user_api.start() 71 | -------------------------------------------------------------------------------- /configs/bot_settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | from logging import ERROR, INFO 5 | from utils.converter_bytes import convert_bytes_to 6 | from telegram.constants import MAX_FILESIZE_DOWNLOAD 7 | 8 | def get_env(name, message, cast=str): 9 | if name in os.environ: 10 | return os.environ[name].strip() 11 | else: 12 | return message 13 | 14 | logs_path = "logs/" 15 | log_downloads = f"{logs_path}downloads.log" 16 | log_uploads = f"{logs_path}uploads.log" 17 | log_telegram = f"{logs_path}telegram.log" 18 | log_links = f"{logs_path}links.log" 19 | 20 | logger_names = [ 21 | ("telegram.ext.dispatcher", ERROR, log_telegram), 22 | ("uploads", INFO, log_uploads), 23 | ("downloads", ERROR, log_downloads), 24 | ("links", INFO, log_links) 25 | ] 26 | 27 | warning_for_banning = int(os.environ.get('WARNING_BANNING',4)) 28 | user_session = "my_account" 29 | user_errors = int(os.environ.get('USER_ERRORS')) 30 | bunker_channel = int(os.environ.get('BUNKER_CHANNEL')) 31 | owl_channel = int(os.environ.get('OWL_CHANNEL')) 32 | db_name = "DB/deez_bot.db" 33 | 34 | root_ids = inputs = { int(os.environ.get("ROOT_ID"))} 35 | 36 | output_songs = "Songs/" 37 | output_shazam = "Records/" 38 | recursive_quality = os.environ.get("RECURSIVE_QUALITY", True) 39 | recursive_download = os.environ.get("RECURSIVE_DOWNLOAD", True) 40 | make_zip = os.environ.get("MAKE_ZIP", True) 41 | method_save = int(os.environ.get('METHOD_SAVE',3)) 42 | is_thread = os.environ.get("IS_THREAD", True) 43 | download_dir_max_size = int(os.environ.get("DOWNLOAD_DIR_MAX_SIZE", 6)) #GB 44 | progress_status_rate = int(os.environ.get("PROGRESS_STATUS_RATE", 15)) 45 | 46 | supported_link = [ 47 | "www.deezer.com", "open.spotify.com", 48 | "deezer.com", "spotify.com", "deezer.page.link" 49 | ] 50 | 51 | time_sleep = int(os.environ.get("TIME_SLEEP", 8)) 52 | seconds_limits_album = int(os.environ.get("SECONDS_LIMITS_ALBUM", 30000)) #seconds 53 | seconds_limits_track = int(os.environ.get("SECONDS_LIMITS_TRACK", 7200)) 54 | upload_max_size_user = int(os.environ.get("UPLOAD_MAX_SIZE_USER", 2)) #GB 55 | max_song_per_playlist = int(os.environ.get("MAX_SONGS_PER_PLAYLIST", 200)) 56 | max_download_user = int(os.environ.get("MAX_DOWNLOAD_USER", 3)) 57 | 58 | recorded_file_max_size = int( 59 | convert_bytes_to( 60 | MAX_FILESIZE_DOWNLOAD, "mb" 61 | ) 62 | ) -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker Buildx master 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | jobs: 7 | docker: 8 | name: Build and push Docker image to GitHub Packages 9 | runs-on: ubuntu-latest 10 | steps: 11 | - 12 | name: Checkout 13 | uses: actions/checkout@v3 14 | - 15 | name: Set up QEMU 16 | uses: docker/setup-qemu-action@v2 17 | - 18 | name: Set up Docker Buildx 19 | id: buildx 20 | uses: docker/setup-buildx-action@v2 21 | 22 | - name: Short the sha to 7 characters only 23 | id: vars 24 | run: | 25 | echo ::set-output name=tag::$(echo ${GITHUB_SHA::10}) 26 | echo "outputs tags: ${{ steps.vars.outputs.tag }}" 27 | 28 | - 29 | name: Set build environment github.ref 30 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 31 | id: tag 32 | run: | 33 | echo ::set-output name=version::${GITHUB_REF/refs\/tags\//} 34 | echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} 35 | 36 | - 37 | name: Inspect builder 38 | run: | 39 | echo "Name: ${{ steps.buildx.outputs.name }}" 40 | echo "Endpoint: ${{ steps.buildx.outputs.endpoint }}" 41 | echo "Status: ${{ steps.buildx.outputs.status }}" 42 | echo "Flags: ${{ steps.buildx.outputs.flags }}" 43 | echo "Platforms: ${{ steps.buildx.outputs.platforms }}" 44 | echo "outputs tags: ${{ steps.vars.outputs.tag }}" 45 | echo "github.sha : ${{ github.sha }}" 46 | echo "github.ref : ${{ github.ref }}" 47 | echo "date : $(date +%s)" 48 | echo "outputs version : ${{ steps.tag.outputs.version }}" 49 | echo "outputs SOURCE_TAG : ${{ steps.tag.outputs.SOURCE_TAG }}" 50 | echo "outputs RELEASE_VERSION : $RELEASE_VERSION" 51 | 52 | - 53 | name: Login to DockerHub 54 | if: github.event_name != 'pull_request' 55 | uses: docker/login-action@v2 56 | with: 57 | username: ${{ secrets.DOCKERHUB_USERNAME }} 58 | password: ${{ secrets.DOCKERHUB_TOKEN }} 59 | 60 | - 61 | name: Build and push 62 | id: docker_build 63 | uses: docker/build-push-action@v3 64 | with: 65 | context: . 66 | platforms: linux/amd64,linux/arm64 67 | push: true 68 | tags: j0n4n/deezspot_bot_docker:latest 69 | - 70 | name: Image digest 71 | run: echo ${{ steps.docker_build.outputs.digest }} 72 | -------------------------------------------------------------------------------- /utils/utils_graphs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from io import BytesIO 4 | 5 | import matplotlib as mpl 6 | mpl.use("agg") 7 | 8 | from datetime import datetime 9 | import matplotlib.pyplot as plt 10 | from calendar import month_abbr 11 | from configs.customs import bot_name 12 | import matplotlib.dates as months_dates 13 | from helpers.db_help import select_users_settings_date, select_dwsongs_top_downloaders 14 | 15 | __locator = months_dates.MonthLocator() 16 | __fmt = months_dates.DateFormatter("%b") 17 | __many = 10 18 | 19 | __manies = [ 20 | a 21 | for a in range(1, 11) 22 | ] 23 | 24 | def __get_data_users(): 25 | num_of_months = len(month_abbr) 26 | datetime_months = [] 27 | nums_users_per_month = [] 28 | now = datetime.now() 29 | c_year = str(now.year) 30 | 31 | for n_month in range(1, num_of_months): 32 | c_month_name = month_abbr[n_month] 33 | 34 | if n_month < 10: 35 | c_month = f"0{n_month}" 36 | else: 37 | c_month = str(n_month) 38 | 39 | data = select_users_settings_date(c_month, c_year) 40 | l_data = len(data) 41 | nums_users_per_month.append(l_data) 42 | datetime_month = datetime.strptime(c_month_name, "%b") 43 | datetime_months.append(datetime_month) 44 | 45 | return datetime_months, nums_users_per_month 46 | 47 | def create_graph_users() -> BytesIO: 48 | datetime_months, nums_users_per_month = __get_data_users() 49 | 50 | plt.plot( 51 | datetime_months, nums_users_per_month, 52 | marker = "o" 53 | ) 54 | 55 | plt.title(f"{bot_name} users", fontweight = "bold") 56 | plt.xlabel("Months") 57 | plt.ylabel("Users") 58 | plt.legend(["Users"]) 59 | 60 | x = plt.gca().xaxis 61 | x.set_major_locator(__locator) 62 | x.set_major_formatter(__fmt) 63 | x.grid() 64 | 65 | y = plt.gca().yaxis 66 | y.grid() 67 | 68 | for c_date, num_users in zip(datetime_months, nums_users_per_month): 69 | plt.text(c_date, num_users, num_users) 70 | 71 | buf = BytesIO() 72 | plt.savefig(buf) 73 | buf.seek(0) 74 | plt.close() 75 | 76 | return buf 77 | 78 | def get_data_downloaders(): 79 | data = select_dwsongs_top_downloaders(__many) 80 | users = [] 81 | nums_downloads = [] 82 | 83 | for user, num_downloads in data: 84 | users.append(user) 85 | nums_downloads.append(num_downloads) 86 | 87 | return users, nums_downloads 88 | 89 | def create_graph_top_downloaders() -> BytesIO: 90 | users, nums_downloads = get_data_downloaders() 91 | 92 | plt.stem(__manies, nums_downloads) 93 | plt.title(f"{bot_name} top downloaders", fontweight = "bold") 94 | plt.xlabel("Users") 95 | plt.ylabel("Downloads") 96 | plt.legend(["Downloads"]) 97 | plt.xticks(__manies) 98 | 99 | x = plt.gca().xaxis 100 | x.grid() 101 | 102 | y = plt.gca().yaxis 103 | y.grid() 104 | 105 | for num, num_downloads in zip(__manies, nums_downloads): 106 | plt.text(num, num_downloads, num_downloads) 107 | 108 | buf = BytesIO() 109 | plt.savefig(buf) 110 | buf.seek(0) 111 | plt.close() 112 | 113 | return buf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DeezSpot_bot 2 | 3 | https://hub.docker.com/r/piklujazz/deezer-bot 4 | 5 | # Disclaimer 6 | 7 | - I am not responsible for the usage of this program by other people. 8 | - I do not recommend you doing this illegally or against Deezer's terms of service. 9 | - This project is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) 10 | 11 | * ### PYTHON VERSION SUPPORTED ### 12 | ![Python >= 3.9](https://img.shields.io/badge/python-v%3E=3.9-blue) 13 | 14 | * ### OS Supported ### 15 | ![Linux Support](https://img.shields.io/badge/Linux-Support-brightgreen.svg) 16 | ![macOS Support](https://img.shields.io/badge/macOS-Support-brightgreen.svg) 17 | ![Windows Support](https://img.shields.io/badge/Windows-Support-brightgreen.svg) 18 | 19 | # SET UP 20 | Docker Variables: 21 | - **MODE_BOT**: (default: 2) 22 | - 1 -> Test Mode. 23 | - 2 -> Cool mode. 24 | - 3 -> Test Mode (No zip). 25 | - 4 -> Cool Mode (No zip). 26 | 27 | - **WARNING_BANNING**: (default: 4) number of flooding messaging when to ban a user. 28 | 29 | - **USER_ERRORS**: (MANDATORY) Chat id where to send users errors. 30 | 31 | - **BUNKER_CHANNEL**: (MANDATORY) Chat id to use as an archive 32 | 33 | - **OWL_CHANNEL**: (MANDATORY) Chat id where to listen for announcements to the users 34 | 35 | - **ROOT_ID**: (MANDATORY) User id to have admin access 36 | 37 | - **METHOD_SAVE**: (default: 3) Method of the naming schema for the song name. 38 | - 0 -> "{album} CD {discnum} TRACK {tracknum}" 39 | - 1 -> "{songname} - {artist}" 40 | - 2 -> "{songname} - {artist} [{isrc}]" 41 | - 3 -> "{discnum}|{tracknum} - {songname} - {artist}" 42 | 43 | - **DOWNLOAD_DIR_MAX_SIZE**: (default: 6) Directory max size in GB. 44 | 45 | - **PROGRESS_STATUS_RATE**: (default: 15) 46 | 47 | - **TIME_SLEEP**: (default: 8) 48 | 49 | - **SECONDS_LIMITS_ALBUM**: (default: 30000) In seconds 50 | 51 | - **SECONDS_LIMITS_TRACK**: (default: 7200) In seconds 52 | 53 | - **UPLOAD_MAX_SIZE_USER**: (default: 2) In GB 54 | 55 | - **MAX_SONGS_PER_PLAYLIST**: (default: 200) Maximum number of song in a playlist to be downloaded 56 | 57 | - **MAX_DOWNLOAD_USER**: (default: 3) Maximum parallel downloads per user 58 | 59 | - **BOT_NAME**: (MANDATORY) Username with the `@` of the bot. 60 | 61 | - **FORUM**: (default: @) 62 | 63 | - **EMAIL_DEE**: (MANDATORY) Email to log in on Deezer 64 | 65 | - **PWD_DEE**: (MANDATORY) Password to log in on Deezer 66 | 67 | - **EMAIL_SPO**: (MANDATORY) Email to log in on Spotify 68 | 69 | - **PWD_SPO**: (MANDATORY) Password to log in on Spotify 70 | 71 | - **BOT_TOKEN**: (MANDATORY) Telegram bot token 72 | 73 | - **API_ID**: (MANDATORY) Telegram api id 74 | 75 | - **API_HASH**: (MANDATORY) Telegram api hash 76 | 77 | - **ACRCLOUD_KEY**: for acrcloud key look at [acrcloud](https://docs.acrcloud.com/tutorials/recognize-music) 78 | 79 | - **ACRCLOUD_SECRET**: for acrcloud secret look at [acrcloud](https://docs.acrcloud.com/tutorials/recognize-music) 80 | 81 | - **ACRCLOUD_HOST**: for host look at [acrcloud](https://docs.acrcloud.com/tutorials/recognize-music) 82 | 83 | 84 | # Where to get some tokens 85 | 86 | - the pyrogram api_id & api_hash can be created [here](https://my.telegram.org/auth?to=apps) 87 | - for create a telegram bot look [here](https://t.me/BotFather) 88 | - for acrcloud key, secret, host look at [acrcloud](https://docs.acrcloud.com/tutorials/recognize-music) 89 | - If you don't know how to get chat id send messages to him [@JsonDumpBot](https://t.me/JsonDumpBot) 90 | -------------------------------------------------------------------------------- /utils/utils_users_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from datetime import datetime 4 | from configs.bot_settings import root_ids, warning_for_banning 5 | 6 | from configs.customs import ( 7 | banning_msg1, banning_msg2, 8 | version, bot_name, creator, 9 | forum, last_update, 10 | last_reset, date_start 11 | ) 12 | 13 | from helpers.db_help import ( 14 | select_users_settings, write_users_settings, 15 | update_users_settings, write_banned, 16 | select_banned, select_all_banned, 17 | select_all_downloads, select_all_users 18 | ) 19 | 20 | def users_set_cache(chat_id, users_data): 21 | user_exist = True 22 | 23 | if not chat_id in users_data: 24 | match = select_users_settings(chat_id) 25 | 26 | if not match: 27 | user_exist = False 28 | write_users_settings(chat_id) 29 | match = select_users_settings(chat_id) 30 | 31 | quality = match[0] 32 | zips = bool(match[1]) 33 | tracks = bool(match[2]) 34 | lang = match[3] 35 | source = match[4] 36 | search_method = match[5] 37 | 38 | users_data[chat_id] = { 39 | "quality": quality, 40 | "zips": zips, 41 | "tracks": tracks, 42 | "lang": lang, 43 | "source": source, 44 | "search_method": search_method, 45 | "last_message": None, 46 | "messages_sent": 0, 47 | "times": 0, 48 | "c_downloads": {} 49 | } 50 | 51 | return user_exist 52 | 53 | def user_setting_save_db(chat_id, user_data): 54 | update_users_settings(user_data, chat_id) 55 | 56 | def check_flood(date, user_data, chat_id): 57 | if chat_id in root_ids: 58 | return 59 | 60 | last_message = user_data['last_message'] 61 | 62 | if not last_message: 63 | user_data['last_message'] = date 64 | return 65 | 66 | user_data['last_message'] = date 67 | time_passed = (date - last_message).seconds 68 | 69 | if time_passed < 4: 70 | user_data['messages_sent'] += 1 71 | else: 72 | user_data['messages_sent'] = 0 73 | 74 | messages_sent = user_data['messages_sent'] 75 | 76 | if messages_sent == 3: 77 | user_data['messages_sent'] = 0 78 | user_data['times'] += 1 79 | return banning_msg1, 0 80 | 81 | times = user_data['times'] 82 | 83 | if times == warning_for_banning: 84 | write_banned(chat_id) 85 | return banning_msg2, 1 86 | 87 | def kill_threads(users_data): 88 | for c_user_data in users_data.values(): 89 | for c_thread in c_user_data['c_downloads'].values(): 90 | c_thread['thread'].kill() 91 | 92 | c_user_data['c_downloads'].clear() 93 | 94 | def is_banned(chat_id): 95 | match = select_banned(chat_id) 96 | 97 | if match: 98 | return True 99 | 100 | return False 101 | 102 | def get_banned_ids(): 103 | match = select_all_banned() 104 | 105 | chat_ids = [ 106 | chat_id[0] 107 | for chat_id in match 108 | ] 109 | 110 | chat_ids = set(chat_ids) 111 | return chat_ids 112 | 113 | def get_tot_downloads(): 114 | match = select_all_downloads() 115 | tot = len(match) 116 | return tot 117 | 118 | def get_tot_users(): 119 | match = select_all_users() 120 | tot = len(match) 121 | return tot 122 | 123 | def get_info(): 124 | tot_users = get_tot_users() 125 | tot_downloads = get_tot_downloads() 126 | time_now = datetime.now() 127 | days_no_accidents = (time_now - date_start).days 128 | 129 | info_msg = ( 130 | f"🔺 Version: {version}\ 131 | \n📅 Last Update: {last_update}\ 132 | \n🔻 Name: {bot_name}\ 133 | \n✒️ Creator: {creator}\ 134 | \n📅 Last reset: {last_reset}\ 135 | \n📣 Forum: {forum}\ 136 | \n👥 Users: {tot_users}\ 137 | \n⬇️ Total downloads: {tot_downloads}\ 138 | \n📅 DAYS WITHOUT ACCIDENTS⚠️: {days_no_accidents}" 139 | ) 140 | 141 | return info_msg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | 147 | # PyCharm 148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 150 | # and can be added to the global gitignore or merged into this file. For a more nuclear 151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 152 | #.idea/ 153 | 154 | *.session 155 | *.ini 156 | *.json 157 | docker-compose-good.yml 158 | DB/deez_bot.db 159 | -------------------------------------------------------------------------------- /configs/customs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | from datetime import datetime 5 | 6 | version = 1.0 7 | bot_name = os.environ.get("BOT_NAME", "@") 8 | creator = "@Anonimia (bot) & J0n4n (docker)" 9 | donation = "https://www.paypal.com/paypalme/an0nimia" 10 | source_code_bot = "https://github.com/J0nan/DeezSpot_bot_docker" 11 | source_code_lib = "https://pypi.org/project/deezloader/" 12 | forum = os.environ.get("FORUM", "@") 13 | last_update = "19/09/2022" 14 | date_start = datetime.now() 15 | last_reset = datetime.strftime(date_start, "%d/%m/%Y %H:%M:%S") 16 | 17 | not_found_query_gif = "https://i1.wp.com/blog-pantheon-prod.global.ssl.fastly.net/blog/wp-content/uploads/2017/03/coding-programming-errors-404-page-not-found.gif?resize=625%2C469&ssl=1" 18 | empty_image_url = "https://e-cdns-images.dzcdn.net/images/cover/1000x1000-000000-80-0-0.jpg" 19 | 20 | banning_msg1 = "WE ARE DETECTING A FLOOD OF MESSAGES PLEASE DON'T SEND TOO MUCH MESSAGES" 21 | banning_msg2 = "CONGRATULATIONS YOU ARE BANNED =)" 22 | 23 | album_too_long = "DON'T YOU GET BORE LISTENING AN ALBUM SO LONG :)))" 24 | track_too_long = "IS THIS TRACK FOR A SATAN CELEBRATION? :)))" 25 | 26 | shazam_function_msg = "You found a fantastic function, if you send a vocal message or an audio, you will see :)" 27 | max_download_user_msg = "You have reached, max download per time avalaible, wait or kill someone :)" 28 | help_msg = f"WELCOME IN {bot_name} here you can find the commands avalaible, JUST TRY IT :)" 29 | help_photo = open("photos/help_msg.jpg", "rb") 30 | 31 | feedback_text = f"If you have any question, just ask to this dude {creator}" 32 | donate_text = f"If you are poor like me, I understand you, IF NOT, I will appreciate a little donation 🥺" 33 | 34 | startup_text = ( 35 | f""" 36 | Hello guys welcome in {bot_name}⚡️, developed by {creator}. 37 | If you want to stay updated join to {forum} 38 | If you like my project support my buying a kebab [DONATE]({donation}) 39 | 40 | *DISCLAIMER*: 41 | 1): DO NOT USE THIS BOT FOR YOUR OWN PURPOSE 42 | 2): I AM NOT RESPONSABLE FOR ANY ILLEGIT USAGE 43 | 3): The source code can be found here: 44 | a): [DeezSpot_bot]({source_code_bot}) 45 | b): [Main lib]({source_code_lib}) 46 | 5): For the artists songs I don't think would get poor if someone doesn't pay for their content. 47 | 6): ENJOY THE MUSIC ART🔥 48 | """ 49 | ) 50 | 51 | reasons_text = ( 52 | "WHY I MADE THIS BOT?\ 53 | \n1): This was a nice challenge for me as a little dev\ 54 | \n2): No all of us have the possibility to pay for music content, so I did this to give to everybody for free the chance to download songs" 55 | ) 56 | 57 | what_can_I_do = ( 58 | "Glad you asked, I can do:\ 59 | \n1): Download songs in three different qualities (/quality)\ 60 | \n2): Shazam engine like to download songs around you\ 61 | \n3): Zip sending\ 62 | \n4): I hope enough performing JAJAJAJAJAJ\ 63 | \n5): I am too lazy to continue, found out by yourself :)" 64 | ) 65 | 66 | bot_settings_config = [ 67 | ("Quality", "quality", "MP3_320"), 68 | ("Send zips", "zips", True), 69 | ("Send tracks", "tracks", True), 70 | ("Language", "lang", "en"), 71 | ("Download Source", "source", "SpoDee"), 72 | ("Search Method", "search_method", "results_audio_article") 73 | ] 74 | 75 | search_methods = [ 76 | ("results_audio", "Results in Audio"), 77 | ("results_article", "Results in Articles"), 78 | ("results_audio_article", "Results Smooth ;)") 79 | ] 80 | 81 | send_image_track_query = ( 82 | "🎧 Track title: %s\ 83 | \n👤 Artist: %s\ 84 | \n💽 Album: %s\ 85 | \n📅 Release date: %s" 86 | ) 87 | 88 | send_image_album_query = ( 89 | "💽 Album: %s\ 90 | \n👤 Artist: %s\ 91 | \n📅 Date: %s\ 92 | \n🎧 Tracks amount: %d" 93 | ) 94 | 95 | send_image_artist_query = ( 96 | "👤 Artist: %s\ 97 | \n💽 Album numbers: %d\ 98 | \n👥 Fans on Deezer: %d" 99 | ) 100 | 101 | send_image_playlist_query = ( 102 | "📅 Creation: %s\ 103 | \n👤 User: %s\ 104 | \n🎧 Tracks amount: %d\ 105 | \n👥 Fans on Deezer: %d" 106 | ) 107 | 108 | shazam_audio_query = ( 109 | "👤 Artist: %s\ 110 | \nGenre: %s\ 111 | \n💽 Album: %s\ 112 | \nLabel: %s\ 113 | \n📅 Release date: %s\ 114 | \n🎧 Track title: %s" 115 | ) 116 | 117 | inline_textes = { 118 | "download_track": { 119 | "text": "⬇️ Download track 🎧" 120 | }, 121 | 122 | "download_album": { 123 | "text": "⬇️ Download album 💽" 124 | }, 125 | 126 | "download_artist": { 127 | "text": "⬇️ Get artist 👤" 128 | }, 129 | 130 | "back": { 131 | "text": "BACK 🔙" 132 | } 133 | } 134 | 135 | commands_queries = { 136 | "s_art": { 137 | "query": "art: %s", 138 | "text": "Search by artist 👤" 139 | }, 140 | 141 | "s_alb": { 142 | "query": "alb: %s", 143 | "text": "Search by album 💽" 144 | }, 145 | 146 | "s_pla": { 147 | "query": "pla: %s", 148 | "text": "Search playlist 📂" 149 | }, 150 | 151 | "s_trk": { 152 | "query": "trk: %s", 153 | "text": "Search track 🎧" 154 | }, 155 | 156 | "s_global": { 157 | "query": "%s", 158 | "text": "Global search 📊" 159 | } 160 | } 161 | 162 | artist_commands_queries = { 163 | "top": { 164 | "query": "%s:top", 165 | "text": "TOP 30 🔝" 166 | }, 167 | 168 | "albums": { 169 | "query": "%s:albums", 170 | "text": "ALBUMS 💽" 171 | }, 172 | 173 | "related": { 174 | "query": "%s:related", 175 | "text": "RELATED 🗣" 176 | }, 177 | 178 | "radio": { 179 | "query": "%s:radio", 180 | "text": "RADIO 📻" 181 | }, 182 | 183 | "playlists": { 184 | "query": "%s:playlists", 185 | "text": "PLAYLISTS 📂" 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /inlines/inline_keyboards.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from deezloader.libutils.utils import get_ids 4 | from helpers.db_help import select_all_banned 5 | from deezloader.deezloader.deezer_settings import qualities as dee_qualities 6 | from deezloader.spotloader.spotify_settings import qualities as spo_qualities 7 | 8 | from telegram import ( 9 | InlineKeyboardMarkup, InlineKeyboardButton 10 | ) 11 | 12 | from configs.customs import ( 13 | commands_queries, artist_commands_queries, 14 | bot_settings_config, inline_textes, search_methods, 15 | donation, source_code_bot, source_code_lib 16 | ) 17 | 18 | __back_keyboard = [ 19 | [ 20 | InlineKeyboardButton( 21 | inline_textes['back']['text'], 22 | callback_data = "/back_home" 23 | ) 24 | ] 25 | ] 26 | 27 | __commands_queries = list( 28 | commands_queries.values() 29 | ) 30 | 31 | __l_commands_queries = len(__commands_queries) 32 | 33 | def create_keyboad_search(to_search): 34 | keyboad_search = [ 35 | [ 36 | InlineKeyboardButton( 37 | command['text'], 38 | switch_inline_query_current_chat = command['query'] % to_search 39 | ) 40 | for command in __commands_queries[ 41 | line:line + 2 42 | ] 43 | ] 44 | for line in range(0, __l_commands_queries, 2) 45 | ] 46 | 47 | search_keyboard = InlineKeyboardMarkup(keyboad_search) 48 | return search_keyboard 49 | 50 | __artist_commands_queries = list( 51 | artist_commands_queries.values() 52 | ) 53 | 54 | __l_artist_commands_queries = len(__artist_commands_queries) 55 | 56 | def create_keyboard_artist(link): 57 | ids = get_ids(link) 58 | query = f"artist:{ids}" 59 | 60 | keyboad_artist = [ 61 | [ 62 | InlineKeyboardButton( 63 | command['text'], 64 | switch_inline_query_current_chat = command['query'] % query 65 | ) 66 | for command in __artist_commands_queries[ 67 | line:line + 2 68 | ] 69 | ] 70 | for line in range(0, __l_artist_commands_queries, 2) 71 | ] 72 | 73 | artist_keyboard = InlineKeyboardMarkup(keyboad_artist) 74 | return artist_keyboard 75 | 76 | __l_bot_settings = len(bot_settings_config) 77 | __dict_seach_methods = dict(search_methods) 78 | 79 | def create_keyboard_settings(datas): 80 | datas = list( 81 | datas.values() 82 | ) 83 | 84 | keyboard_settings = [] 85 | 86 | for line in range(0, __l_bot_settings, 2): 87 | c_array = [] 88 | 89 | for line2 in range(line, line + 2): 90 | if line2 >= __l_bot_settings: 91 | continue 92 | 93 | c_data = bot_settings_config[line2] 94 | msg = c_data[0] 95 | cmd = c_data[1] 96 | data = datas[line2] 97 | 98 | if type(data) is bool: 99 | if data: 100 | msg += ": ✅" 101 | else: 102 | msg += ": 🚫" 103 | else: 104 | if cmd == "search_method": 105 | data = __dict_seach_methods[data] 106 | 107 | msg += f": {data}" 108 | 109 | c_keyboard = InlineKeyboardButton( 110 | msg, 111 | callback_data = f"/edit_setting_{cmd}" 112 | ) 113 | 114 | c_array.append(c_keyboard) 115 | 116 | keyboard_settings.append(c_array) 117 | 118 | settings_keyboard = InlineKeyboardMarkup(keyboard_settings) 119 | return settings_keyboard 120 | 121 | __qualities_dee = list( 122 | dee_qualities.keys() 123 | ) 124 | 125 | __qualities_spo = list( 126 | spo_qualities.keys() 127 | ) 128 | 129 | __l_qualities = len(__qualities_dee) 130 | 131 | def create_keyboard_qualities(): 132 | keyboad_qualities = [ 133 | [ 134 | InlineKeyboardButton( 135 | f"{quality_dee}/{quality_spo}", 136 | callback_data = f"/edit_setting_quality_{quality_dee}" 137 | ) 138 | for quality_dee, quality_spo in zip( 139 | __qualities_dee[ 140 | line:line + 2 141 | ], 142 | __qualities_spo[ 143 | line:line + 2 144 | ] 145 | ) 146 | ] 147 | for line in range(0, __l_qualities, 2) 148 | ] 149 | 150 | keyboad_qualities += __back_keyboard 151 | qualities_keyboard = InlineKeyboardMarkup(keyboad_qualities) 152 | 153 | return qualities_keyboard 154 | 155 | __l_search_methods = len(search_methods) 156 | 157 | def create_keyboard_search_method(): 158 | keyboad_search_methods = [ 159 | [ 160 | InlineKeyboardButton( 161 | search_method[1], 162 | callback_data = f"/edit_setting_search_method_{search_method[0]}" 163 | ) 164 | for search_method in search_methods[ 165 | line:line + 2 166 | ] 167 | ] 168 | for line in range(0, __l_search_methods, 2) 169 | ] 170 | 171 | keyboad_search_methods += __back_keyboard 172 | qualities_keyboard = InlineKeyboardMarkup(keyboad_search_methods) 173 | return qualities_keyboard 174 | 175 | def create_shazamed_keyboard(track_link, album_link, artist_link): 176 | keyboard_shazamed = [ 177 | [ 178 | InlineKeyboardButton( 179 | inline_textes['download_track']['text'], 180 | callback_data = f"/down:{track_link}" 181 | ) 182 | ], 183 | [ 184 | InlineKeyboardButton( 185 | inline_textes['download_album']['text'], 186 | callback_data = f"/down:{album_link}" 187 | ) 188 | ], 189 | [ 190 | InlineKeyboardButton( 191 | inline_textes['download_artist']['text'], 192 | callback_data = f"/down:{artist_link}" 193 | ) 194 | ] 195 | ] 196 | 197 | shazamed_keyboard = InlineKeyboardMarkup(keyboard_shazamed) 198 | return shazamed_keyboard 199 | 200 | def create_banned_keyboard(): 201 | users_ids = select_all_banned() 202 | l_users_ids = len(users_ids) 203 | 204 | keyboard_banned = [ 205 | [ 206 | InlineKeyboardButton( 207 | user_id[0], 208 | callback_data = f"/unban_{user_id[0]}" 209 | ) 210 | for user_id in users_ids[ 211 | line:line + 2 212 | ] 213 | ] 214 | for line in range(0, l_users_ids, 2) 215 | ] 216 | 217 | banned_keyboard = InlineKeyboardMarkup(keyboard_banned) 218 | return banned_keyboard 219 | 220 | def create_c_dws_user_keyboard(dws: dict): 221 | keyboad_dws = [ 222 | InlineKeyboardMarkup( 223 | [ 224 | [ 225 | InlineKeyboardButton( 226 | "Press here to delete this download 🚫", 227 | callback_data = f"/kill_dw_{key}" 228 | ) 229 | ] 230 | ] 231 | ) for key in dws.keys() 232 | ] 233 | 234 | return keyboad_dws 235 | 236 | def create_info_keyboard(): 237 | keyboard_info = [ 238 | [ 239 | InlineKeyboardButton( 240 | "💸 PAYPAL DONATION HERE 🥺", 241 | url = donation 242 | ) 243 | ], 244 | [ 245 | InlineKeyboardButton( 246 | "👨‍💻 BOT Source code HERE", 247 | url = source_code_bot 248 | 249 | ) 250 | ], 251 | [ 252 | InlineKeyboardButton( 253 | "👨‍💻 LIB Source code HERE", 254 | url = source_code_lib 255 | 256 | ) 257 | ] 258 | ] 259 | 260 | info_keyboard = InlineKeyboardMarkup(keyboard_info) 261 | 262 | return info_keyboard -------------------------------------------------------------------------------- /utils/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from urllib.parse import urlparse 4 | from requests import get as req_get 5 | from shutil import disk_usage, rmtree 6 | from helpers.db_help import initialize_db 7 | from libtmux import Server as tmux_server 8 | from .converter_bytes import convert_bytes_to 9 | from deezloader.libutils.utils import var_excape 10 | from deezloader.deezloader.deezer_settings import qualities as dee_qualities 11 | from deezloader.spotloader.spotify_settings import qualities as spo_qualities 12 | 13 | from logging import ( 14 | getLogger, FileHandler, 15 | Formatter, Logger 16 | ) 17 | 18 | from configs.bot_settings import ( 19 | output_songs, supported_link, output_shazam, 20 | logs_path, logger_names, 21 | log_uploads, log_downloads 22 | ) 23 | 24 | from os import ( 25 | walk, listdir, mkdir, 26 | remove, system, 27 | name as os_name 28 | ) 29 | 30 | from os.path import ( 31 | getsize, join, 32 | islink, isdir 33 | ) 34 | 35 | __qualities_dee = list( 36 | dee_qualities.keys() 37 | ) 38 | 39 | __qualities_spo = list( 40 | spo_qualities.keys() 41 | ) 42 | 43 | def get_netloc(link): 44 | netloc = urlparse(link).netloc 45 | 46 | return netloc 47 | 48 | def is_supported_link(link): 49 | is_supported = True 50 | netloc = urlparse(link).netloc 51 | 52 | if not any( 53 | c_link == netloc 54 | for c_link in supported_link 55 | ): 56 | return False 57 | 58 | return is_supported 59 | 60 | def __get_tronc(string): 61 | l_encoded = len( 62 | string.encode() 63 | ) 64 | 65 | if l_encoded > 242: 66 | n_tronc = len(string) - l_encoded - 242 67 | else: 68 | n_tronc = 242 69 | 70 | return n_tronc 71 | 72 | def set_path(song_metadata, song_quality, file_format, method_save): 73 | album = var_excape(song_metadata['album']) 74 | artist = var_excape(song_metadata['artist']) 75 | music = var_excape(song_metadata['music']) 76 | 77 | if method_save == 0: 78 | discnum = song_metadata['discnum'] 79 | tracknum = song_metadata['tracknum'] 80 | song_name = f"{album} CD {discnum} TRACK {tracknum}" 81 | 82 | elif method_save == 1: 83 | song_name = f"{music} - {artist}" 84 | 85 | elif method_save == 2: 86 | isrc = song_metadata['isrc'] 87 | song_name = f"{music} - {artist} [{isrc}]" 88 | 89 | elif method_save == 3: 90 | discnum = song_metadata['discnum'] 91 | tracknum = song_metadata['tracknum'] 92 | song_name = f"{artist} - {music}" 93 | 94 | n_tronc = __get_tronc(song_name) 95 | song_path = f"{song_name[:n_tronc]}{file_format}" 96 | 97 | return song_path 98 | 99 | def get_quality_dee_s_quality(dee_quality): 100 | chosen = dee_qualities[dee_quality] 101 | s_quality = chosen['s_quality'] 102 | 103 | return s_quality 104 | 105 | def get_quality_spo(dee_quality): 106 | index = __qualities_dee.index(dee_quality) 107 | chosen = __qualities_spo[index] 108 | 109 | return chosen 110 | 111 | def get_quality_spo_s_quality(spo_quality): 112 | chosen = spo_qualities[spo_quality] 113 | s_quality = chosen['s_quality'] 114 | 115 | return s_quality 116 | 117 | def get_url_path(link): 118 | parsed = urlparse(link) 119 | path = parsed.path 120 | s_path = path.split("/") 121 | path = f"{s_path[-2]}/{s_path[-1]}" 122 | 123 | return path 124 | 125 | def my_round(num): 126 | rounded = round(num, 2) 127 | 128 | return rounded 129 | 130 | def get_image_bytes(image_url): 131 | content = req_get(image_url).content 132 | 133 | return content 134 | 135 | def get_avalaible_disk_space(): 136 | total, used, free = disk_usage("/") 137 | total = convert_bytes_to(total, "gb") 138 | used = convert_bytes_to(used, "gb") 139 | free = convert_bytes_to(free, "gb") 140 | 141 | return free 142 | 143 | def get_download_dir_size(): 144 | total_size = 0 145 | 146 | for dirpath, dirnames, filenames in walk(output_songs): 147 | for f in filenames: 148 | fp = join(dirpath, f) 149 | 150 | if not islink(fp): 151 | total_size += getsize(fp) 152 | 153 | total_size = convert_bytes_to(total_size, "gb") 154 | 155 | return total_size 156 | 157 | def clear_download_dir(): 158 | dirs = listdir(output_songs) 159 | 160 | for c_dir in dirs: 161 | cc_dir = join(output_songs, c_dir) 162 | 163 | if isdir(cc_dir): 164 | rmtree(cc_dir) 165 | 166 | def clear_recorded_dir(): 167 | files = listdir(output_shazam) 168 | 169 | for c_file in files: 170 | cc_file = join(output_shazam, c_file) 171 | remove(cc_file) 172 | 173 | def create_recorded_dir(): 174 | if not isdir(output_shazam): 175 | mkdir(output_shazam) 176 | 177 | def create_download_dir(): 178 | if not isdir(output_songs): 179 | mkdir(output_songs) 180 | 181 | def create_log_dir(): 182 | if not isdir(logs_path): 183 | mkdir(logs_path) 184 | 185 | def logging_bot() -> list: 186 | formatter = Formatter( 187 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 188 | ) 189 | 190 | loggers = [] 191 | 192 | for logger, level, log_path in logger_names: 193 | fu = FileHandler(log_path) 194 | fu.setFormatter(formatter) 195 | c_logger = getLogger(logger) 196 | c_logger.setLevel(level) 197 | c_logger.addHandler(fu) 198 | loggers.append(c_logger) 199 | 200 | return loggers 201 | 202 | def check_config_bot(): 203 | initialize_db() 204 | create_recorded_dir() 205 | create_download_dir() 206 | create_log_dir() 207 | 208 | def get_size(f, size) -> float: 209 | b_size = getsize(f) 210 | mb_size = convert_bytes_to(b_size, size) 211 | 212 | return mb_size 213 | 214 | def show_menu(): 215 | print("1): TEST MODE") 216 | print("2): COOL MODE") 217 | print("3): TEST MODE (NO ZIP)") 218 | print("4): COOL MODE (NO ZIP)") 219 | 220 | ans = input("How to use it?: ") 221 | 222 | if ans == "1": 223 | choice = 1 224 | elif ans == "2": 225 | choice = 2 226 | elif ans == "3": 227 | choice = 3 228 | elif ans == "4": 229 | choice = 4 230 | else: 231 | exit() 232 | 233 | return choice 234 | 235 | def clear(): 236 | cmd = None 237 | 238 | if os_name == "nt": 239 | cmd = "cls" 240 | else: 241 | cmd = "clear" 242 | 243 | return cmd 244 | 245 | def create_tmux(): 246 | cclear = clear() 247 | system(cclear) 248 | server = tmux_server() 249 | 250 | info = { 251 | "session_name": "deez_bot" 252 | } 253 | 254 | session = server.find_where(info) 255 | 256 | try: 257 | window = session.attached_window 258 | except AttributeError: 259 | print("Must be executed after typed tmux new -s deez_bot :)") 260 | raise KeyboardInterrupt 261 | 262 | pan_top_right = window.split_window(vertical = False) 263 | pan_top_right.send_keys(cclear) 264 | pan_top_right.send_keys(f"tail -f {log_downloads}") 265 | pan_bot_left = pan_top_right.split_window(vertical = True) 266 | pan_bot_left.send_keys(cclear) 267 | pan_bot_left.send_keys(f"tail -n2 -f {log_uploads}") 268 | #pan_bot_right = pan_bot_left.split_window(vertical = False) 269 | #pan_bot_right.send_keys(cclear) 270 | #pan_bot_right.send_keys(f"tail -n2 -f {log_downloads}") 271 | return session 272 | -------------------------------------------------------------------------------- /helpers/db_help.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from configs.bot_settings import db_name 4 | from sqlite3 import connect as db_connect 5 | from configs.customs import bot_settings_config 6 | 7 | users_settings_columns = [ 8 | setting[1] 9 | for setting in bot_settings_config 10 | ] 11 | 12 | query_insert_users_settings_str_fields = "" 13 | query_insert_users_settings_str_input = "" 14 | query_update_users_settings_str_input = "" 15 | 16 | for setting in bot_settings_config: 17 | query_insert_users_settings_str_fields += f"{setting[1]}," 18 | query_insert_users_settings_str_input += "?," 19 | query_update_users_settings_str_input += f"{setting[1]} = ?," 20 | 21 | query_update_users_settings_str_input = query_update_users_settings_str_input[:-1] 22 | query_insert_users_settings_str_fields = query_insert_users_settings_str_fields[:-1] 23 | query_insert_users_settings_str_input = query_insert_users_settings_str_input[:-1] 24 | 25 | def initialize_db(): 26 | query_create_table_dwsongs = ( 27 | "CREATE TABLE IF NOT EXISTS dwsongs(\ 28 | id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \ 29 | link VARCHAR(255) NOT NULL, \ 30 | file_id VARCHAR(255) UNIQUE NOT NULL, \ 31 | quality VARCHAR(5) NOT NULL, \ 32 | date DATE DEFAULT (datetime('now', 'localtime')), \ 33 | chat_id INT NOT NULL, \ 34 | UNIQUE(link, quality))" 35 | ) 36 | 37 | query_create_table_users_settings = ( 38 | "CREATE TABLE IF NOT EXISTS users_settings(\ 39 | id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \ 40 | chat_id INT UNIQUE NOT NULL, \ 41 | quality VARCHAR(5) NOT NULL, \ 42 | zips BOOLEAN NOT NULL, \ 43 | tracks BOOLEAN NOT NULL, \ 44 | lang VARCHAR(5) NOT NULL, \ 45 | date DATE DEFAULT (datetime('now', 'localtime')), \ 46 | source VARCHAR(8) NOT NULL, \ 47 | search_method VARCHAR(15) NOT NULL)" 48 | ) 49 | 50 | query_create_table_banned = ( 51 | "CREATE TABLE IF NOT EXISTS banned(\ 52 | id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \ 53 | date DATE DEFAULT (datetime('now', 'localtime')), \ 54 | chat_id INT UNIQUE NOT NULL)" 55 | ) 56 | 57 | con = db_connect(db_name) 58 | cur = con.cursor() 59 | cur.execute(query_create_table_dwsongs) 60 | cur.execute(query_create_table_users_settings) 61 | cur.execute(query_create_table_banned) 62 | con.commit() 63 | con.close() 64 | 65 | def write_dwsongs(link, file_id, quality, chat_id): 66 | con = db_connect(db_name) 67 | cur = con.cursor() 68 | query_insert_dwsongs = "INSERT INTO dwsongs(link, file_id, quality, chat_id) VALUES (?, ?, ?, ?)" 69 | 70 | cur.execute( 71 | query_insert_dwsongs, 72 | ( 73 | link, file_id, 74 | quality, chat_id 75 | ) 76 | ) 77 | 78 | con.commit() 79 | con.close() 80 | 81 | def delete_dwsongs(file_id): 82 | con = db_connect(db_name) 83 | cur = con.cursor() 84 | query_delete_dwsongs = "DELETE FROM dwsongs WHERE file_id = ?" 85 | 86 | cur.execute( 87 | query_delete_dwsongs, 88 | ( 89 | file_id, 90 | ) 91 | ) 92 | 93 | con.commit() 94 | con.close() 95 | 96 | def select_dwsongs(link, quality): 97 | con = db_connect(db_name) 98 | cur = con.cursor() 99 | query_select_dwsongs = "SELECT file_id FROM dwsongs WHERE link = ? AND quality = ?" 100 | 101 | cur.execute( 102 | query_select_dwsongs, 103 | ( 104 | link, quality 105 | ) 106 | ) 107 | 108 | match = cur.fetchone() 109 | con.close() 110 | 111 | return match 112 | 113 | def write_users_settings(chat_id): 114 | con = db_connect(db_name) 115 | cur = con.cursor() 116 | 117 | query_insert_users_settings = ( 118 | f"INSERT INTO users_settings\ 119 | (chat_id, {query_insert_users_settings_str_fields}) \ 120 | VALUES (?, {query_insert_users_settings_str_input})" 121 | ) 122 | 123 | c_settings = [chat_id] 124 | 125 | c_settings += [ 126 | c_setting[2] 127 | for c_setting in bot_settings_config 128 | ] 129 | 130 | cur.execute(query_insert_users_settings, c_settings) 131 | con.commit() 132 | con.close() 133 | 134 | def write_banned(chat_id): 135 | con = db_connect(db_name) 136 | cur = con.cursor() 137 | query_insert_banned = "INSERT INTO banned(chat_id) VALUES (?)" 138 | 139 | cur.execute( 140 | query_insert_banned, 141 | ( 142 | chat_id, 143 | ) 144 | ) 145 | 146 | con.commit() 147 | con.close() 148 | 149 | def delete_banned(chat_id): 150 | con = db_connect(db_name) 151 | cur = con.cursor() 152 | query_delete_banned = "DELETE FROM banned WHERE chat_id = ?" 153 | 154 | cur.execute( 155 | query_delete_banned, 156 | ( 157 | chat_id, 158 | ) 159 | ) 160 | 161 | con.commit() 162 | con.close() 163 | 164 | def select_banned(chat_id): 165 | con = db_connect(db_name) 166 | cur = con.cursor() 167 | query_select_banned = "SELECT chat_id FROM banned WHERE chat_id = ?" 168 | 169 | cur.execute( 170 | query_select_banned, 171 | ( 172 | chat_id, 173 | ) 174 | ) 175 | 176 | match = cur.fetchone() 177 | con.close() 178 | 179 | return match 180 | 181 | def select_all_banned(): 182 | con = db_connect(db_name) 183 | cur = con.cursor() 184 | query_select_banned = "SELECT chat_id FROM banned" 185 | cur.execute(query_select_banned) 186 | match = cur.fetchall() 187 | con.close() 188 | 189 | return match 190 | 191 | def update_users_settings(user_settings, chat_id): 192 | con = db_connect(db_name) 193 | cur = con.cursor() 194 | 195 | query_update_users_settings = ( 196 | f"UPDATE users_settings SET {query_update_users_settings_str_input} WHERE chat_id = ?" 197 | ) 198 | 199 | c_settings = [] 200 | 201 | for c_setting in user_settings: 202 | if c_setting in users_settings_columns: 203 | c_settings.append(user_settings[c_setting]) 204 | 205 | c_settings.append(chat_id) 206 | cur.execute(query_update_users_settings, c_settings) 207 | con.commit() 208 | con.close() 209 | 210 | def select_users_settings(chat_id): 211 | con = db_connect(db_name) 212 | cur = con.cursor() 213 | 214 | query_select_users_settings = ( 215 | f"SELECT {query_insert_users_settings_str_fields} FROM users_settings WHERE chat_id = ?" 216 | ) 217 | 218 | cur.execute( 219 | query_select_users_settings, 220 | ( 221 | chat_id, 222 | ) 223 | ) 224 | 225 | match = cur.fetchone() 226 | con.close() 227 | 228 | return match 229 | 230 | def select_all_users(): 231 | con = db_connect(db_name) 232 | cur = con.cursor() 233 | query_select_users = "SELECT chat_id FROM users_settings" 234 | cur.execute(query_select_users) 235 | match = cur.fetchall() 236 | con.close() 237 | 238 | return match 239 | 240 | def select_all_downloads(): 241 | con = db_connect(db_name) 242 | cur = con.cursor() 243 | query_select_dwsongs = "SELECT file_id FROM dwsongs" 244 | cur.execute(query_select_dwsongs) 245 | match = cur.fetchall() 246 | con.close() 247 | 248 | return match 249 | 250 | def select_users_settings_date(c_month, c_year): 251 | con = db_connect(db_name) 252 | cur = con.cursor() 253 | 254 | cur.execute( 255 | "SELECT date FROM users_settings WHERE strftime('%m', date) = ? AND strftime('%Y', date) = ?", 256 | ( 257 | c_month, c_year 258 | ) 259 | ) 260 | 261 | match = cur.fetchall() 262 | con.close() 263 | 264 | return match 265 | 266 | def select_dwsongs_top_downloaders(many): 267 | con = db_connect(db_name) 268 | cur = con.cursor() 269 | 270 | cur.execute( 271 | "SELECT chat_id, COUNT(chat_id) as cnt FROM dwsongs GROUP BY chat_id ORDER BY cnt DESC LIMIT ?", 272 | (many, ) 273 | ) 274 | 275 | match = cur.fetchall() 276 | con.close() 277 | 278 | return match -------------------------------------------------------------------------------- /inlines/inline_query_results.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from helpers.db_help import select_dwsongs 4 | from utils.utils import my_round, get_url_path 5 | from configs.customs import not_found_query_gif 6 | 7 | from telegram import ( 8 | InlineQueryResultArticle, InputTextMessageContent, 9 | InlineQueryResultAudio, InlineQueryResultCachedAudio, 10 | InlineQueryResultGif 11 | ) 12 | 13 | def create_result_article_artist(datas): 14 | results = [ 15 | InlineQueryResultArticle( 16 | id = data['id'], 17 | title = data['name'], 18 | input_message_content = InputTextMessageContent( 19 | data['link'] 20 | ), 21 | description = ( 22 | f"Album number: {data['nb_album']}" + 23 | f"\nFan number: {data['nb_fan']}" 24 | ), 25 | thumb_url = data['picture_big'] 26 | ) 27 | for data in datas 28 | ] 29 | 30 | return results 31 | 32 | def create_result_article_track(datas): 33 | results = [ 34 | InlineQueryResultArticle( 35 | id = data['id'], 36 | title = data['title'], 37 | input_message_content = InputTextMessageContent( 38 | data['link'] 39 | ), 40 | description = ( 41 | f"Artist: {data['artist']['name']}" + 42 | f"\nAlbum: {data['album']['title']}" + 43 | f"\nDuration: {my_round(data['duration'] / 60)}" + 44 | f"\nRank: {data['rank']}" 45 | ), 46 | thumb_url = data['album']['cover_big'] 47 | ) 48 | for data in datas 49 | ] 50 | 51 | return results 52 | 53 | def create_result_article_track_audio(datas, quality): 54 | results = [] 55 | 56 | for data in datas: 57 | ids = data['id'] 58 | link = get_url_path(data['link']) 59 | match = select_dwsongs(link, quality) 60 | 61 | if match: 62 | audio_file_id = match[0] 63 | 64 | article = InlineQueryResultCachedAudio( 65 | id = ids, 66 | audio_file_id = audio_file_id, 67 | ) 68 | else: 69 | article = InlineQueryResultAudio( 70 | id = ids, 71 | audio_url = data['preview'], 72 | title = data['title'], 73 | performer = data['artist']['name'], 74 | audio_duration = data['duration'], 75 | input_message_content = InputTextMessageContent( 76 | data['link'] 77 | ) 78 | ) 79 | 80 | results.append(article) 81 | 82 | return results 83 | 84 | def create_result_article_track_and_audio(datas, quality): 85 | results = [] 86 | 87 | for data in datas: 88 | ids = data['id'] 89 | link = get_url_path(data['link']) 90 | match = select_dwsongs(link, quality) 91 | 92 | if match: 93 | audio_file_id = match[0] 94 | 95 | article = InlineQueryResultCachedAudio( 96 | id = ids, 97 | audio_file_id = audio_file_id, 98 | ) 99 | else: 100 | article = InlineQueryResultArticle( 101 | id = data['id'], 102 | title = data['title'], 103 | input_message_content = InputTextMessageContent( 104 | data['link'] 105 | ), 106 | description = ( 107 | f"Artist: {data['artist']['name']}" + 108 | f"\nAlbum: {data['album']['title']}" + 109 | f"\nDuration: {my_round(data['duration'] / 60)}" + 110 | f"\nRank: {data['rank']}" 111 | ), 112 | thumb_url = data['album']['cover_big'] 113 | ) 114 | 115 | results.append(article) 116 | 117 | return results 118 | 119 | def create_result_article_album(datas): 120 | results = [ 121 | InlineQueryResultArticle( 122 | id = data['id'], 123 | title = data['title'], 124 | input_message_content = InputTextMessageContent( 125 | data['link'] 126 | ), 127 | description = ( 128 | f"Tracks number: {data['nb_tracks']}" + 129 | f"\nArtist: {data['artist']['name']}" 130 | ), 131 | thumb_url = data['cover_big'] 132 | ) 133 | for data in datas 134 | ] 135 | 136 | return results 137 | 138 | def create_result_article_artist_album(datas): 139 | results = [ 140 | InlineQueryResultArticle( 141 | id = data['id'], 142 | title = data['title'], 143 | input_message_content = InputTextMessageContent( 144 | data['link'] 145 | ), 146 | description = ( 147 | f"Release date: {data['release_date']}" + 148 | f"\nFans: {data['fans']}" 149 | ), 150 | thumb_url = data['cover_big'] 151 | ) 152 | for data in datas 153 | ] 154 | 155 | return results 156 | 157 | def create_result_article_playlist(datas): 158 | results = [ 159 | InlineQueryResultArticle( 160 | id = data['id'], 161 | title = data['title'], 162 | input_message_content = InputTextMessageContent( 163 | data['link'] 164 | ), 165 | description = ( 166 | f"Tracks number: {data['nb_tracks']}" + 167 | f"\nUser: {data['user']['name']}" + 168 | f"\nCreation: {data['creation_date']}" 169 | ), 170 | thumb_url = data['picture_big'] 171 | ) 172 | for data in datas 173 | ] 174 | 175 | return results 176 | 177 | def create_result_article_artist_playlist(datas): 178 | results = [ 179 | InlineQueryResultArticle( 180 | id = data['id'], 181 | title = data['title'], 182 | input_message_content = InputTextMessageContent( 183 | data['link'] 184 | ), 185 | description = ( 186 | f"User: {data['user']['name']}" + 187 | f"\nCreation: {data['creation_date']}" 188 | ), 189 | thumb_url = data['picture_big'] 190 | ) 191 | for data in datas 192 | ] 193 | 194 | return results 195 | 196 | def create_result_article_artist_radio(datas): 197 | results = [ 198 | InlineQueryResultArticle( 199 | id = data['id'], 200 | title = data['title'], 201 | input_message_content = InputTextMessageContent( 202 | f"https://deezer.com/track/{data['id']}" 203 | ), 204 | description = ( 205 | f"Artist: {data['artist']['name']}" + 206 | f"\nAlbum: {data['album']['title']}" + 207 | f"\nDuration: {my_round(data['duration'] / 60)}" + 208 | f"\nRank: {data['rank']}" 209 | ), 210 | thumb_url = data['album']['cover_big'] 211 | ) 212 | for data in datas 213 | ] 214 | 215 | return results 216 | 217 | def create_result_article_chart_album(datas): 218 | results = [ 219 | InlineQueryResultArticle( 220 | id = data['id'], 221 | title = data['title'], 222 | input_message_content = InputTextMessageContent( 223 | data['link'] 224 | ), 225 | description = ( 226 | f"Position: {data['position']}" + 227 | f"\nArtist: {data['artist']['name']}" 228 | ), 229 | thumb_url = data['cover_big'] 230 | ) 231 | for data in datas 232 | ] 233 | 234 | return results 235 | 236 | def create_result_article_chart_artist(datas): 237 | results = [ 238 | InlineQueryResultArticle( 239 | id = data['id'], 240 | title = data['name'], 241 | input_message_content = InputTextMessageContent( 242 | data['link'] 243 | ), 244 | description = f"Position: {data['position']}", 245 | thumb_url = data['picture_big'] 246 | ) 247 | for data in datas 248 | ] 249 | 250 | return results 251 | 252 | def create_result_article_chart_track(datas): 253 | results = [ 254 | InlineQueryResultArticle( 255 | id = data['id'], 256 | title = data['title'], 257 | input_message_content = InputTextMessageContent( 258 | data['link'] 259 | ), 260 | description = ( 261 | f"Artist: {data['artist']['name']}" + 262 | f"\nAlbum: {data['album']['title']}" + 263 | f"\nDuration: {my_round(data['duration'] / 60)}" + 264 | f"\nRank: {data['rank']}" + 265 | f"\nPosition: {data['position']}" 266 | ), 267 | thumb_url = data['album']['cover_big'] 268 | ) 269 | for data in datas 270 | ] 271 | 272 | return results 273 | 274 | def create_result_not_found(): 275 | results = [ 276 | InlineQueryResultGif( 277 | id = "not_found", 278 | gif_url = not_found_query_gif, 279 | thumb_url = not_found_query_gif, 280 | title = "ERROR 404 :)", 281 | input_message_content = InputTextMessageContent( 282 | "YOU ARE WONDERFUL =)" 283 | ), 284 | ) 285 | ] 286 | 287 | return results -------------------------------------------------------------------------------- /utils/utils_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from deezloader.easy_spoty import Spo 4 | from configs.set_configs import SetConfigs 5 | from deezloader.exceptions import NoDataApi 6 | from deezloader.libutils.utils import get_ids 7 | from utils.utils import get_quality_dee_s_quality 8 | from deezloader.deezloader.dee_api import API as deezer_api 9 | 10 | from inlines.inline_query_results import ( 11 | create_result_article_artist, create_result_article_track, 12 | create_result_article_album, create_result_article_playlist, 13 | create_result_article_artist_album, create_result_article_artist_radio, 14 | create_result_article_artist_playlist, create_result_article_chart_album, 15 | create_result_article_chart_artist, create_result_article_chart_track, 16 | create_result_article_track_audio, create_result_not_found, 17 | create_result_article_track_and_audio 18 | ) 19 | 20 | def shazam_song(song): 21 | data = SetConfigs.acrcloud_api.recognize_audio(song) 22 | status = data['status'] 23 | 24 | if status['msg'] != "Success": 25 | return 26 | 27 | song_tags = data['metadata']['music'][0] 28 | 29 | artists = [ 30 | artist['name'] 31 | for artist in song_tags['artists'] 32 | ] 33 | 34 | artist = " & ".join(artists) 35 | 36 | if "genres" in song_tags: 37 | genres = [ 38 | genre['name'] 39 | for genre in song_tags['genres'] 40 | ] 41 | 42 | genre = " & ".join(genres) 43 | else: 44 | genre = "Unknown" 45 | 46 | album = song_tags['album']['name'] 47 | label = song_tags['label'] 48 | external_ids = song_tags['external_ids'] 49 | 50 | if "upc" in external_ids: 51 | upc = f"upc:{external_ids['upc']}" 52 | 53 | if "isrc" in external_ids: 54 | isrc = f"isrc:{external_ids['isrc']}" 55 | data_track = deezer_api.get_track(isrc) 56 | track_link = data_track['link'] 57 | album_link = data_track['album']['link'] 58 | artist_link = data_track['artist']['link'] 59 | image_url = data_track['album']['cover_xl'] 60 | else: 61 | track_link = None 62 | album_link = None 63 | image_url = None 64 | 65 | release_date = song_tags['release_date'] 66 | title = song_tags['title'] 67 | 68 | return ( 69 | artist, genre, 70 | album, label, 71 | track_link, album_link, 72 | artist_link, image_url, 73 | release_date, title 74 | ) 75 | 76 | #OLD SPOTIFY DOWNLOAD 77 | def track_spo_to_dee_data(link): 78 | link_dee = SetConfigs.deez_api.convert_spoty_to_dee_link_track(link) 79 | dee_data = track_dee_data(link_dee) 80 | 81 | return dee_data 82 | 83 | def track_spo_data(link, conv: bool): 84 | if conv: 85 | return track_spo_to_dee_data(link) 86 | 87 | ids = get_ids(link) 88 | data = Spo.get_track(ids) 89 | image_url = data['album']['images'][0]['url'] 90 | name = data['name'] 91 | artist = data['artists'][0]['name'] 92 | album = data['album']['name'] 93 | date = data['album']['release_date'] 94 | duration = data['duration_ms'] // 1000 95 | 96 | return ( 97 | image_url, name, 98 | artist, album, 99 | date, link, duration 100 | ) 101 | 102 | def track_dee_data(link): 103 | ids = get_ids(link) 104 | data = deezer_api.get_track(ids) 105 | md5_image = data['md5_image'] 106 | image_url = deezer_api.get_img_url(md5_image, size = "1000x1000") 107 | name = data['title'] 108 | artist = data['artist']['name'] 109 | album = data['album']['title'] 110 | date = data['album']['release_date'] 111 | link_dee = data['link'] 112 | duration = data['duration'] 113 | 114 | return ( 115 | image_url, name, 116 | artist, album, 117 | date, link_dee, duration 118 | ) 119 | 120 | def artist_dee_data(link): 121 | ids = get_ids(link) 122 | data = deezer_api.get_artist(ids) 123 | name = data['name'] 124 | image_url = data['picture_xl'] 125 | nb_album = data['nb_album'] 126 | nb_fan = data['nb_fan'] 127 | 128 | return ( 129 | name, image_url, 130 | nb_album, nb_fan 131 | ) 132 | 133 | def playlist_dee_data(link): 134 | ids = get_ids(link) 135 | data = deezer_api.get_playlist(ids) 136 | nb_tracks = data['nb_tracks'] 137 | n_fans = data['fans'] 138 | image_url = data['picture_xl'] 139 | creation_date = data['creation_date'] 140 | creator = data['creator']['name'] 141 | tracks = data['tracks']['data'] 142 | 143 | return ( 144 | nb_tracks, n_fans, 145 | image_url, creation_date, 146 | creator, tracks 147 | ) 148 | 149 | def playlist_spo_data(link): 150 | ids = get_ids(link) 151 | data = Spo.get_playlist(ids) 152 | n_fans = data['followers']['total'] 153 | image_url = data['images'][0]['url'] 154 | creation_date = data['tracks']['items'][0]['added_at'] 155 | creator = data['owner']['display_name'] 156 | tracks = data['tracks']['items'] 157 | nb_tracks = len(tracks) 158 | 159 | return ( 160 | nb_tracks, n_fans, 161 | image_url, creation_date, 162 | creator, tracks 163 | ) 164 | 165 | def album_dee_data(link): 166 | ids = get_ids(link) 167 | data = deezer_api.get_album(ids) 168 | md5_image = data['md5_image'] 169 | image_url = deezer_api.get_img_url(md5_image, size = "1000x1000") 170 | album = data['title'] 171 | artist = data['artist']['name'] 172 | date = data['release_date'] 173 | nb_tracks = data['nb_tracks'] 174 | tracks = data['tracks']['data'] 175 | duration = data['duration'] 176 | link_dee = data['link'] 177 | 178 | return ( 179 | image_url, album, 180 | artist, date, 181 | nb_tracks, tracks, 182 | duration, link_dee 183 | ) 184 | 185 | def convert_spoty_to_dee_link_track(link): 186 | link_dee = SetConfigs.deez_api.convert_spoty_to_dee_link_track(link) 187 | 188 | return link_dee 189 | 190 | def album_spo_data_to_dee(link): 191 | link_dee = SetConfigs.deez_api.convert_spoty_to_dee_link_album(link) 192 | dee_data = album_dee_data(link_dee) 193 | 194 | return dee_data 195 | 196 | def album_spo_data(link, conv: bool): 197 | if conv: 198 | return album_spo_data_to_dee(link) 199 | 200 | ids = get_ids(link) 201 | data = Spo.get_album(ids) 202 | image_url = data['images'][0]['url'] 203 | album = data['name'] 204 | artist = data['artists'][0]['name'] 205 | date = data['release_date'] 206 | nb_tracks = data['total_tracks'] 207 | tracks = data['tracks']['items'] 208 | duration = 0 209 | 210 | for track in tracks: 211 | duration += track['duration_ms'] 212 | 213 | duration //= 1000 214 | 215 | return ( 216 | image_url, album, 217 | artist, date, 218 | nb_tracks, tracks, 219 | duration, link 220 | ) 221 | 222 | def __lazy_create(search_method): 223 | if search_method == "results_audio": 224 | c_create_article = create_result_article_track_audio 225 | mode = "results_audio" 226 | 227 | elif search_method == "results_article": 228 | c_create_article = create_result_article_track 229 | mode = 0 230 | 231 | elif search_method == "results_audio_article": 232 | c_create_article = create_result_article_track_and_audio 233 | mode = "results_audio" 234 | 235 | return c_create_article, mode 236 | 237 | def create_response_article(query: str, user_data): 238 | s_art = "art: " 239 | s_alb = "alb: " 240 | s_pla = "pla: " 241 | s_trk = "trk: " 242 | s_art_id = "artist:" 243 | mode = 0 244 | search_method = user_data['search_method'] 245 | 246 | if search_method.startswith("results_audio"): 247 | user_quality = user_data['quality'] 248 | quality = get_quality_dee_s_quality(user_quality) 249 | 250 | if query.startswith(s_art): 251 | c_query = query.replace(s_art, "") 252 | c_api = deezer_api.search_artist 253 | c_create_article = create_result_article_artist 254 | 255 | elif query.startswith(s_alb): 256 | c_query = query.replace(s_alb, "") 257 | c_api = deezer_api.search_album 258 | c_create_article = create_result_article_album 259 | 260 | elif query.startswith(s_pla): 261 | c_query = query.replace(s_pla, "") 262 | c_api = deezer_api.search_playlist 263 | c_create_article = create_result_article_playlist 264 | 265 | elif query.startswith(s_trk): 266 | c_query = query.replace(s_trk, "") 267 | c_api = deezer_api.search_track 268 | c_create_article, mode = __lazy_create(search_method) 269 | 270 | elif query.startswith(s_art_id): 271 | c_query = query.replace(s_art_id, "") 272 | s_c_query = c_query.split(":") 273 | c_query = s_c_query[0] 274 | path = s_c_query[1] 275 | 276 | if path == "top": 277 | c_api = deezer_api.get_artist_top_tracks 278 | c_create_article, mode = __lazy_create(search_method) 279 | 280 | elif path == "albums": 281 | c_api = deezer_api.get_artist_top_albums 282 | c_create_article = create_result_article_artist_album 283 | 284 | elif path == "related": 285 | c_api = deezer_api.get_artist_related 286 | c_create_article = create_result_article_artist 287 | 288 | elif path == "radio": 289 | c_api = deezer_api.get_artist_radio 290 | c_create_article = create_result_article_artist_radio 291 | 292 | elif path == "playlists": 293 | c_api = deezer_api.get_artist_top_playlists 294 | c_create_article = create_result_article_artist_playlist 295 | 296 | else: 297 | return 298 | 299 | else: 300 | c_query = query 301 | 302 | if c_query == "": 303 | mode = 1 304 | c_api = deezer_api.get_chart 305 | else: 306 | c_api = deezer_api.search 307 | c_create_article, mode = __lazy_create(search_method) 308 | 309 | try: 310 | data = c_api(c_query) 311 | except NoDataApi: 312 | return create_result_not_found() 313 | 314 | if mode == 0: 315 | data = data['data'] 316 | results = c_create_article(data) 317 | 318 | elif mode == 1: 319 | tracks = data['tracks']['data'] 320 | albums = data['albums']['data'] 321 | artists = data['artists']['data'] 322 | playlists = data['playlists']['data'] 323 | 324 | if search_method == "results_audio": 325 | results = create_result_article_track_audio(tracks, quality) 326 | elif search_method == "results_article": 327 | results = create_result_article_chart_track(tracks) 328 | elif search_method == "results_audio_article": 329 | results = create_result_article_track_and_audio(tracks, quality) 330 | 331 | results += create_result_article_chart_album(albums) 332 | results += create_result_article_chart_artist(artists) 333 | results += create_result_article_playlist(playlists) 334 | 335 | elif mode == "results_audio": 336 | data = data['data'] 337 | results = c_create_article(data, quality) 338 | 339 | return results -------------------------------------------------------------------------------- /helpers/download_help.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from time import sleep 4 | from io import BytesIO 5 | from os.path import isfile 6 | from telegram import ChatAction 7 | from sqlite3 import IntegrityError 8 | from telegram.error import BadRequest 9 | from deezloader.models.track import Track 10 | from deezloader.models.album import Album 11 | from configs.set_configs import SetConfigs 12 | from deezloader.exceptions import TrackNotFound 13 | from deezloader.libutils.utils import request, what_kind 14 | from inlines.inline_keyboards import create_keyboard_artist 15 | from deezloader.deezloader.dee_api import API as deezer_API 16 | 17 | from .db_help import ( 18 | write_dwsongs, select_dwsongs, delete_dwsongs 19 | ) 20 | 21 | from deezloader.exceptions import ( 22 | NoDataApi, InvalidLink, AlbumNotFound 23 | ) 24 | 25 | from utils.utils import ( 26 | get_quality_dee_s_quality, get_quality_spo_s_quality, 27 | get_quality_spo, get_url_path, set_path, 28 | get_size, logging_bot, get_netloc 29 | ) 30 | 31 | from configs.customs import ( 32 | send_image_track_query, send_image_artist_query, 33 | send_image_playlist_query, send_image_album_query, 34 | album_too_long, track_too_long, empty_image_url 35 | ) 36 | 37 | from utils.utils_data import ( 38 | track_spo_data, track_dee_data, 39 | artist_dee_data, playlist_dee_data, 40 | playlist_spo_data, album_dee_data, 41 | album_spo_data, convert_spoty_to_dee_link_track 42 | ) 43 | 44 | from configs.bot_settings import ( 45 | bunker_channel, seconds_limits_album, 46 | seconds_limits_track, max_song_per_playlist, 47 | method_save, output_songs, 48 | recursive_quality, recursive_download, 49 | upload_max_size_user, user_errors, 50 | progress_status_rate, is_thread 51 | ) 52 | 53 | deezer_api = deezer_API() 54 | bot = SetConfigs.tg_bot_api.bot 55 | l_telegram, l_uploads, l_downloads, l_links = logging_bot() 56 | 57 | def log_error(log, exc_info = False): 58 | l_downloads.error(log, exc_info = exc_info) 59 | 60 | def write_db(track_md5, file_id, n_quality, chat_id): 61 | try: 62 | write_dwsongs(track_md5, file_id, n_quality, chat_id) 63 | except IntegrityError: 64 | pass 65 | 66 | class DW: 67 | def __init__( 68 | self, 69 | chat_id: int, 70 | user_data: dict, 71 | hash_link: int 72 | ) -> None: 73 | 74 | self.__chat_id = chat_id 75 | self.__source = 1 76 | self.__quality = user_data['quality'] 77 | self.__n_quality = get_quality_dee_s_quality(self.__quality) 78 | self.__send_to_user_tracks = user_data['tracks'] 79 | self.__send_to_user_zips = user_data['zips'] 80 | self.__hash_link = hash_link 81 | self.__c_download = user_data['c_downloads'] 82 | 83 | if user_data['source'] == "SpoDee": 84 | conv = False 85 | else: 86 | conv = True 87 | 88 | self.__conv: bool = conv 89 | 90 | def __set_quality(self, link): 91 | netloc = get_netloc(link) 92 | 93 | if "spotify" in netloc: 94 | if self.__source == 2: 95 | return 96 | 97 | self.__source = 2 98 | self.__quality = get_quality_spo(self.__quality) 99 | self.__n_quality = get_quality_spo_s_quality(self.__quality) 100 | 101 | def __before_dw(self): 102 | SetConfigs.queues_started += 1 103 | 104 | def __after_dw(self): 105 | SetConfigs.queues_finished += 1 106 | 107 | def __finished(self): 108 | try: 109 | del self.__c_download[self.__hash_link] 110 | except KeyError: 111 | pass 112 | 113 | def __upload_audio(self, file_id): 114 | if self.__send_to_user_tracks: 115 | bot.send_chat_action( 116 | chat_id = self.__chat_id, 117 | action = ChatAction.UPLOAD_AUDIO 118 | ) 119 | 120 | sleep(0.1) 121 | l_uploads.info(f"UPLOADING: {file_id}") 122 | 123 | bot.send_audio( 124 | chat_id = self.__chat_id, 125 | audio = file_id 126 | ) 127 | 128 | def __upload_zip(self, file_id): 129 | if self.__send_to_user_zips: 130 | bot.send_chat_action( 131 | chat_id = self.__chat_id, 132 | action = ChatAction.UPLOAD_DOCUMENT 133 | ) 134 | 135 | sleep(0.1) 136 | l_uploads.info(f"UPLOADING: {file_id}") 137 | 138 | bot.send_document( 139 | chat_id = self.__chat_id, 140 | document = file_id 141 | ) 142 | 143 | def __upload_audio_track(self, track: Track): 144 | c_path = track.song_path 145 | track_md5 = track.track_md5 146 | md5_image = track.md5_image 147 | 148 | if self.__source == 1: 149 | image_bytes1 = deezer_api.choose_img(md5_image, "90x90") 150 | elif self.__source == 2: 151 | image_bytes1 = request(track.tags['image3']).content 152 | 153 | io_image = BytesIO(image_bytes1) 154 | io_image.name = md5_image 155 | duration = track.duration 156 | performer = track.artist 157 | title = track.music 158 | f_format = track.file_format 159 | tag = track.tags 160 | track_quality = track.quality 161 | 162 | file_name = set_path(tag, self.__n_quality, f_format, method_save) 163 | 164 | if not isfile(c_path): 165 | bot.send_message( 166 | chat_id = self.__chat_id, 167 | text = f"Cannot download {track.link} :(" 168 | ) 169 | 170 | return 171 | 172 | track_size = get_size(c_path, "gb") 173 | 174 | if track_size > upload_max_size_user: 175 | bot.send_message( 176 | chat_id = self.__chat_id, 177 | text = f"THE SONG {track.song_name} IS TOO BIG TO BE UPLOADED\ 178 | , MAX {upload_max_size_user} GB\ 179 | , CURRENT {track_size} GB :(" 180 | ) 181 | 182 | return 183 | 184 | if track_quality != self.__n_quality: 185 | bot.send_message( 186 | chat_id = self.__chat_id, 187 | text = ( 188 | f"⚠ The {title} - {performer} can't be downloaded in {self.__quality} quality :( ⚠\ 189 | \nIT HAS BEEN DOWNLOADED IN {track_quality}" 190 | ) 191 | ) 192 | 193 | file_id = SetConfigs.tg_user_api.send_audio( 194 | chat_id = bunker_channel, 195 | audio = c_path, 196 | thumb = io_image, 197 | duration = duration, 198 | performer = performer, 199 | title = title, 200 | file_name = file_name 201 | ) 202 | 203 | if file_id.audio: 204 | file_id = file_id.audio.file_id 205 | else: 206 | return 207 | 208 | write_db( 209 | track_md5, file_id, 210 | track_quality, self.__chat_id 211 | ) 212 | 213 | self.__upload_audio(file_id) 214 | 215 | def __download_track(self, url): 216 | try: 217 | if "deezer" in url: 218 | track = SetConfigs.deez_api.download_trackdee( 219 | url, 220 | output_dir = output_songs, 221 | quality_download = self.__quality, 222 | recursive_quality = recursive_quality, 223 | recursive_download = recursive_download, 224 | method_save = method_save 225 | ) 226 | 227 | elif "spotify" in url: 228 | track = SetConfigs.spot_api.download_track( 229 | url, 230 | output_dir = output_songs, 231 | quality_download = self.__quality, 232 | recursive_quality = recursive_quality, 233 | recursive_download = recursive_download, 234 | method_save = method_save, 235 | is_thread = is_thread 236 | ) 237 | except TrackNotFound as error: 238 | log_error(error, exc_info = True) 239 | 240 | bot.send_message( 241 | chat_id = self.__chat_id, 242 | text = f"Cannot download {url} :(" 243 | ) 244 | 245 | return 246 | 247 | progress_message_id = bot.send_message( 248 | chat_id = self.__chat_id, 249 | text = f"Starting uploading {track.song_name} ..." 250 | ).message_id 251 | 252 | self.__upload_audio_track(track) 253 | 254 | bot.delete_message( 255 | chat_id = self.__chat_id, 256 | message_id = progress_message_id 257 | ) 258 | 259 | def __progress_status(self, current, total, times, album_name): 260 | c_time = times[0] 261 | 262 | if current == total: 263 | msg_id = times[1] 264 | 265 | bot.delete_message( 266 | chat_id = self.__chat_id, 267 | message_id = msg_id 268 | ) 269 | 270 | if (c_time % progress_status_rate == 0): 271 | c_progress = f"{current * 100 / total:.1f}%" 272 | c_text = f"Uploading {album_name}: {c_progress}" 273 | l_uploads.info(c_text) 274 | 275 | if c_time == 0: 276 | msg_id = bot.send_message( 277 | chat_id = self.__chat_id, 278 | text = c_text 279 | ).message_id 280 | 281 | times.append(msg_id) 282 | else: 283 | msg_id = times[1] 284 | 285 | try: 286 | bot.edit_message_text( 287 | chat_id = self.__chat_id, 288 | message_id = msg_id, 289 | text = c_text 290 | ) 291 | except BadRequest: 292 | pass 293 | 294 | times[0] += 1 295 | 296 | def __upload_zip_album(self, album: Album): 297 | times = [0] 298 | album_name = album.album_name 299 | md5_image = album.md5_image 300 | 301 | if self.__source == 1: 302 | image_bytes2 = deezer_api.choose_img(md5_image, "320x320") 303 | elif self.__source == 2: 304 | image_bytes2 = request(album.tags['image2']).content 305 | 306 | image_io2 = BytesIO(image_bytes2) 307 | image_io2.name = md5_image 308 | progress_args = (times, album_name) 309 | path_zip = album.zip_path 310 | album_md5 = album.album_md5 311 | zip_size = get_size(path_zip, "gb") 312 | album_quality = album.tracks[0].quality 313 | 314 | if zip_size > upload_max_size_user: 315 | bot.send_message( 316 | chat_id = self.__chat_id, 317 | text = f"THE ZIP IS TOO BIG TO BE UPLOADED\ 318 | , MAX {upload_max_size_user} GB\ 319 | , CURRENT {zip_size} GB :(" 320 | ) 321 | 322 | write_db( 323 | album_md5, "TOO BIG", 324 | album_quality, self.__chat_id 325 | ) 326 | 327 | return 328 | 329 | file_id = SetConfigs.tg_user_api.send_document( 330 | chat_id = bunker_channel, 331 | document = path_zip, 332 | thumb = image_io2, 333 | progress = self.__progress_status, 334 | progress_args = progress_args 335 | ).document.file_id 336 | 337 | write_db( 338 | album_md5, file_id, 339 | album_quality, self.__chat_id 340 | ) 341 | 342 | self.__upload_zip(file_id) 343 | 344 | def __upload_audio_album( 345 | self, 346 | track: Track, 347 | image_bytes1, 348 | num_track, nb_tracks, 349 | progress_message_id 350 | ): 351 | c_path = track.song_path 352 | track_md5 = track.track_md5 353 | image_io1 = BytesIO(image_bytes1) 354 | image_io1.name = track_md5 355 | duration = track.duration 356 | performer = track.artist 357 | title = track.music 358 | f_format = track.file_format 359 | tag = track.tags 360 | file_name = set_path(tag, self.__n_quality, f_format, method_save) 361 | c_progress = f"Uploading ({num_track}/{nb_tracks}): {title}" 362 | c_progress += f" {num_track * 100 / nb_tracks:.1f}%" 363 | l_uploads.info(c_progress) 364 | 365 | bot.edit_message_text( 366 | chat_id = self.__chat_id, 367 | message_id = progress_message_id, 368 | text = c_progress 369 | ) 370 | 371 | if track.success: 372 | if not isfile(c_path): 373 | bot.send_message( 374 | chat_id = self.__chat_id, 375 | text = f"Cannot download {track.link} :(" 376 | ) 377 | 378 | return 379 | 380 | track_size = get_size(c_path, "gb") 381 | 382 | if track_size > upload_max_size_user: 383 | bot.send_message( 384 | chat_id = self.__chat_id, 385 | text = f"THE SONG {track.song_name} IS TOO BIG TO BE UPLOADED\ 386 | , MAX {upload_max_size_user} GB\ 387 | , CURRENT {track_size} GB :(" 388 | ) 389 | 390 | return 391 | 392 | track_quality = track.quality 393 | 394 | if track_quality != self.__n_quality: 395 | bot.send_message( 396 | chat_id = self.__chat_id, 397 | text = ( 398 | f"⚠ The {title} - {performer} can't be downloaded in {self.__quality} quality :( ⚠\ 399 | \nIT HAS BEEN DOWNLOADED IN {track_quality}" 400 | ) 401 | ) 402 | 403 | file_id = SetConfigs.tg_user_api.send_audio( 404 | chat_id = bunker_channel, 405 | audio = c_path, 406 | thumb = image_io1, 407 | duration = duration, 408 | performer = performer, 409 | title = title, 410 | file_name = file_name 411 | ) 412 | 413 | if file_id.audio: 414 | file_id = file_id.audio.file_id 415 | else: 416 | return 417 | 418 | write_db( 419 | track_md5, file_id, 420 | track_quality, self.__chat_id 421 | ) 422 | 423 | self.__upload_audio(file_id) 424 | else: 425 | bot.send_message( 426 | chat_id = self.__chat_id, 427 | text = f"Cannot download {track.song_name} :(" 428 | ) 429 | 430 | def __download_album(self, url): 431 | if "deezer" in url: 432 | album = SetConfigs.deez_api.download_albumdee( 433 | url, 434 | output_dir = output_songs, 435 | quality_download = self.__quality, 436 | recursive_quality = recursive_quality, 437 | recursive_download = recursive_download, 438 | make_zip = SetConfigs.create_zips, 439 | method_save = method_save 440 | ) 441 | 442 | elif "spotify" in url: 443 | album = SetConfigs.spot_api.download_album( 444 | url, 445 | output_dir = output_songs, 446 | quality_download = self.__quality, 447 | recursive_quality = recursive_quality, 448 | recursive_download = recursive_download, 449 | make_zip = SetConfigs.create_zips, 450 | method_save = method_save, 451 | is_thread = is_thread 452 | ) 453 | 454 | md5_image = album.md5_image 455 | nb_tracks = album.nb_tracks 456 | 457 | if self.__source == 1: 458 | image_bytes1 = deezer_api.choose_img(md5_image, "90x90") 459 | elif self.__source == 2: 460 | image_bytes1 = request(album.tags['image3']).content 461 | 462 | num_track = 1 463 | 464 | progress_message_id = bot.send_message( 465 | chat_id = self.__chat_id, 466 | text = "Starting uploading..." 467 | ).message_id 468 | 469 | for track in album.tracks: 470 | self.__upload_audio_album( 471 | track, image_bytes1, num_track, 472 | nb_tracks, progress_message_id 473 | ) 474 | 475 | num_track += 1 476 | 477 | bot.delete_message( 478 | chat_id = self.__chat_id, 479 | message_id = progress_message_id 480 | ) 481 | 482 | if SetConfigs.create_zips: 483 | self.__upload_zip_album(album) 484 | else: 485 | write_db( 486 | album.album_md5, "TOO BIG", 487 | self.__quality, self.__chat_id 488 | ) 489 | 490 | def __send_for_debug(self, link, error): 491 | err_str = f"ERROR WITH THIS LINK {link} {self.__quality}" 492 | 493 | bot.send_message( 494 | chat_id = self.__chat_id, 495 | text = err_str 496 | ) 497 | 498 | sleep(0.1) 499 | 500 | bot.send_message( 501 | chat_id = user_errors, 502 | text = err_str 503 | ) 504 | 505 | log_error(error, exc_info = True) 506 | log_error(err_str) 507 | 508 | def __check_track(self, link): 509 | self.__set_quality(link) 510 | link_path = get_url_path(link) 511 | match = select_dwsongs(link_path, self.__n_quality) 512 | 513 | if match: 514 | file_id = match[0] 515 | 516 | try: 517 | self.__upload_audio(file_id) 518 | except BadRequest: 519 | delete_dwsongs(file_id) 520 | self.__check_track(link) 521 | else: 522 | try: 523 | self.__download_track(link) 524 | except Exception as error: 525 | self.__send_for_debug(link, error) 526 | 527 | def __check_album(self, link, tracks): 528 | self.__set_quality(link) 529 | link_path = get_url_path(link) 530 | match = select_dwsongs(link_path, self.__n_quality) 531 | 532 | if match: 533 | file_id = match[0] 534 | 535 | if file_id != "TOO BIG": 536 | try: 537 | self.__upload_zip(file_id) 538 | except BadRequest: 539 | delete_dwsongs(file_id) 540 | self.__check_album(link, tracks) 541 | 542 | if self.__send_to_user_tracks: 543 | for track in tracks: 544 | if self.__source == 1: 545 | c_link = track['link'] 546 | elif self.__source == 2: 547 | c_link = track['external_urls']['spotify'] 548 | 549 | c_link_path = get_url_path(c_link) 550 | c_match = select_dwsongs(c_link_path, self.__n_quality) 551 | 552 | if not c_match: 553 | bot.send_message( 554 | chat_id = self.__chat_id, 555 | text = f"The song {c_link} isn't avalaible :(" 556 | ) 557 | 558 | continue 559 | 560 | c_file_id = c_match[0] 561 | 562 | try: 563 | self.__upload_audio(c_file_id) 564 | except BadRequest: 565 | delete_dwsongs(c_file_id) 566 | self.__check_track(c_link) 567 | else: 568 | try: 569 | self.__download_album(link) 570 | except Exception as error: 571 | self.__send_for_debug(link, error) 572 | 573 | def __send_photo( 574 | self, chat_id, 575 | image_url, caption, 576 | reply_markup = None 577 | ): 578 | try: 579 | data = bot.send_photo( 580 | chat_id = chat_id, 581 | photo = image_url, 582 | caption = caption, 583 | reply_markup = reply_markup 584 | ) 585 | except BadRequest: 586 | data = bot.send_photo( 587 | chat_id = chat_id, 588 | photo = empty_image_url, 589 | caption = caption, 590 | reply_markup = reply_markup 591 | ) 592 | 593 | return data 594 | 595 | def download(self, link): 596 | try: 597 | l_links.info(link) 598 | stat = 1 599 | self.__before_dw() 600 | link = what_kind(link) 601 | 602 | if "track/" in link: 603 | if "spotify.com" in link: 604 | try: 605 | image_url, name,\ 606 | artist, album,\ 607 | date, link_dee, duration = track_spo_data(link, self.__conv) 608 | except TrackNotFound: 609 | bot.send_message( 610 | chat_id = self.__chat_id, 611 | text = f"Cannot download {link} :(" 612 | ) 613 | 614 | return 615 | 616 | elif "deezer.com" in link: 617 | image_url, name,\ 618 | artist, album,\ 619 | date, link_dee, duration = track_dee_data(link) 620 | 621 | if duration > seconds_limits_track: 622 | bot.send_message( 623 | chat_id = self.__chat_id, 624 | text = track_too_long 625 | ) 626 | 627 | return 628 | 629 | caption = ( 630 | send_image_track_query 631 | % ( 632 | name, 633 | artist, 634 | album, 635 | date 636 | ) 637 | ) 638 | 639 | msg_id = self.__send_photo( 640 | self.__chat_id, image_url, caption 641 | ).message_id 642 | 643 | self.__check_track(link_dee) 644 | 645 | elif "artist/" in link: 646 | stat = 0 647 | 648 | if "deezer.com" in link: 649 | name, image_url,\ 650 | nb_album, nb_fan = artist_dee_data(link) 651 | else: 652 | return 653 | 654 | caption = ( 655 | send_image_artist_query 656 | % ( 657 | name, 658 | nb_album, 659 | nb_fan 660 | ) 661 | ) 662 | 663 | reply_markup = create_keyboard_artist(link) 664 | 665 | msg_id = self.__send_photo( 666 | self.__chat_id, image_url, caption, 667 | reply_markup = reply_markup 668 | ).message_id 669 | 670 | elif "album/" in link: 671 | if "spotify.com" in link: 672 | image_url, album,\ 673 | artist, date,\ 674 | nb_tracks, tracks,\ 675 | duration, link_dee = album_spo_data(link, self.__conv) 676 | 677 | elif "deezer.com" in link: 678 | image_url, album,\ 679 | artist, date,\ 680 | nb_tracks, tracks,\ 681 | duration, link_dee = album_dee_data(link) 682 | 683 | if duration > seconds_limits_album: 684 | bot.send_message( 685 | chat_id = self.__chat_id, 686 | text = album_too_long 687 | ) 688 | 689 | return 690 | 691 | caption = ( 692 | send_image_album_query 693 | % ( 694 | album, 695 | artist, 696 | date, 697 | nb_tracks 698 | ) 699 | ) 700 | 701 | msg_id = self.__send_photo( 702 | self.__chat_id, image_url, caption 703 | ).message_id 704 | 705 | self.__check_album(link_dee, tracks) 706 | 707 | elif "playlist/" in link: 708 | if "spotify.com" in link: 709 | mode = "spotify" 710 | 711 | try: 712 | nb_tracks, n_fans,\ 713 | image_url, creation_data,\ 714 | creator, tracks = playlist_spo_data(link) 715 | except IndexError: 716 | bot.send_message( 717 | chat_id = self.__chat_id, 718 | text = f"This playlist is unreadable :(" 719 | ) 720 | 721 | return 722 | 723 | elif "deezer.com" in link: 724 | mode = "deezer" 725 | 726 | nb_tracks, n_fans,\ 727 | image_url, creation_data,\ 728 | creator, tracks = playlist_dee_data(link) 729 | 730 | caption = ( 731 | send_image_playlist_query 732 | % ( 733 | creation_data, 734 | creator, 735 | nb_tracks, 736 | n_fans 737 | ) 738 | ) 739 | 740 | msg_id = self.__send_photo( 741 | self.__chat_id, image_url, caption 742 | ).message_id 743 | 744 | if nb_tracks > max_song_per_playlist: 745 | bot.send_message( 746 | chat_id = self.__chat_id, 747 | text = f"This playlist contains {nb_tracks} tracks only the first {max_song_per_playlist} will be downloaded" 748 | ) 749 | 750 | for track, index in zip( 751 | tracks, range(max_song_per_playlist) 752 | ): 753 | if mode == "deezer": 754 | c_link = track['link'] 755 | 756 | elif mode == "spotify": 757 | c_track = track['track'] 758 | 759 | if not c_track: 760 | continue 761 | 762 | external_urls = c_track['external_urls'] 763 | 764 | if not external_urls: 765 | bot.send_message( 766 | chat_id = self.__chat_id, 767 | text = f"The track \"{c_track['name']}\" is not avalaible on Spotify :(" 768 | ) 769 | 770 | continue 771 | 772 | c_link = external_urls['spotify'] 773 | 774 | if self.__conv: 775 | try: 776 | c_link = convert_spoty_to_dee_link_track(c_link) 777 | except (NoDataApi, TrackNotFound): 778 | bot.send_message( 779 | chat_id = self.__chat_id, 780 | text = f"Cannot download {c_link} :(" 781 | ) 782 | 783 | continue 784 | 785 | self.__check_track(c_link) 786 | 787 | else: 788 | bot.send_message( 789 | chat_id = self.__chat_id, 790 | text = "Can you just send normal links?, THANKS :)" 791 | ) 792 | 793 | return 794 | 795 | if stat == 1: 796 | bot.send_message( 797 | chat_id = self.__chat_id, 798 | text = "FINISHED =)", 799 | reply_to_message_id = msg_id 800 | ) 801 | except AlbumNotFound as error: 802 | bot.send_message( 803 | chat_id = self.__chat_id, 804 | text = error.msg 805 | ) 806 | except (NoDataApi, InvalidLink) as error: 807 | if type(error) is NoDataApi: 808 | text = f"This {link} doesn't exist :(" 809 | 810 | elif type(error) is InvalidLink: 811 | text = f"INVALID LINK {link} :(" 812 | 813 | bot.send_message( 814 | chat_id = self.__chat_id, 815 | text = text 816 | ) 817 | except Exception as error: 818 | try: 819 | self.__send_for_debug(link, error) 820 | except Exception as error: 821 | log_error(f"{link} {self.__quality} {self.__chat_id}") 822 | log_error(error, exc_info = True) 823 | finally: 824 | self.__after_dw() 825 | self.__finished() -------------------------------------------------------------------------------- /deez_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from utils.utils import check_config_bot 4 | import os 5 | 6 | check_config_bot() 7 | mode_bot = int(os.environ.get("MODE_BOT", 2)) 8 | 9 | from configs.set_configs import SetConfigs 10 | 11 | SetConfigs(mode_bot) 12 | 13 | from sys import argv 14 | from hashlib import md5 15 | 16 | # from signal import SIGTERM 17 | # from os import getpid, kill 18 | from time import sleep, time 19 | from telegram import ParseMode 20 | from helpers.download_help import DW 21 | from pyrogram import idle as tg_user_start 22 | from pyrogram.errors import ChatAdminRequired, UserNotParticipant 23 | from utils.special_thread import magicThread 24 | from utils.converter_bytes import convert_bytes_to 25 | from telegram.error import BadRequest, Unauthorized 26 | from utils.utils_data import create_response_article, shazam_song 27 | 28 | from utils.utils_graphs import ( 29 | create_graph_users, 30 | create_graph_top_downloaders, 31 | get_data_downloaders, 32 | ) 33 | 34 | from telegram import MessageEntity, Update, InputMediaPhoto 35 | 36 | from helpers.db_help import delete_banned, select_all_users, write_banned 37 | 38 | from configs.customs import ( 39 | not_found_query_gif, 40 | shazam_audio_query, 41 | shazam_function_msg, 42 | max_download_user_msg, 43 | help_msg, 44 | help_photo, 45 | feedback_text, 46 | what_can_I_do, 47 | donate_text, 48 | reasons_text, 49 | startup_text, 50 | ) 51 | 52 | from configs.bot_settings import ( 53 | download_dir_max_size, 54 | time_sleep, 55 | output_shazam, 56 | recorded_file_max_size, 57 | root_ids, 58 | bunker_channel, 59 | owl_channel, 60 | max_download_user, 61 | ) 62 | 63 | from utils.utils_users_bot import ( 64 | user_setting_save_db, 65 | users_set_cache, 66 | check_flood, 67 | get_banned_ids, 68 | get_info, 69 | kill_threads, 70 | ) 71 | 72 | from utils.utils import ( 73 | is_supported_link, 74 | get_download_dir_size, 75 | clear_download_dir, 76 | clear_recorded_dir, 77 | my_round, 78 | create_tmux, 79 | ) 80 | 81 | from telegram.ext import ( 82 | CommandHandler, 83 | MessageHandler, 84 | Filters, 85 | InlineQueryHandler, 86 | CallbackQueryHandler, 87 | ) 88 | 89 | from inlines.inline_keyboards import ( 90 | create_keyboad_search, 91 | create_keyboard_settings, 92 | create_keyboard_qualities, 93 | create_shazamed_keyboard, 94 | create_keyboard_search_method, 95 | create_banned_keyboard, 96 | create_c_dws_user_keyboard, 97 | create_info_keyboard, 98 | ) 99 | 100 | bot_chat_id = SetConfigs.tg_bot_api.bot.id 101 | bot = SetConfigs.tg_bot_api.bot 102 | 103 | banned_ids = get_banned_ids() 104 | 105 | users_data = {} 106 | roots_data = {} 107 | 108 | to_ban = Filters.user(banned_ids) 109 | strict_modes = [1, 3] 110 | 111 | 112 | def participant(user_id: int): 113 | if SetConfigs.__fsub_chat_id is None: 114 | return True 115 | try: 116 | bot.get_chat_member(SetConfigs.__fsub_chat_id, user_id) 117 | except: 118 | return False 119 | 120 | 121 | def ban_chat_id(chat_id): 122 | write_banned(chat_id) 123 | to_ban.add_chat_ids(chat_id) 124 | 125 | 126 | def help_check_user(chat_id, date=None): 127 | if (mode_bot in strict_modes) and (not chat_id in root_ids): 128 | bot.send_message(chat_id=chat_id, text="BOT IS UNDER MAINTENANCE") 129 | 130 | to_ban.add_chat_ids(chat_id) 131 | 132 | return 133 | 134 | user_exist = users_set_cache(chat_id, users_data) 135 | 136 | if date: 137 | user_data = users_data[chat_id] 138 | result = check_flood(date, user_data, chat_id) 139 | 140 | if result: 141 | msg, mode = result 142 | 143 | bot.send_message(chat_id=chat_id, text=msg) 144 | 145 | if mode == 1: 146 | to_ban.add_chat_ids(chat_id) 147 | del users_data[chat_id] 148 | 149 | if not user_exist: 150 | bot.send_message( 151 | chat_id=chat_id, text=startup_text, parse_mode=ParseMode.MARKDOWN 152 | ) 153 | 154 | 155 | def help_download(link, chat_id): 156 | if chat_id in to_ban.user_ids: 157 | return 158 | 159 | if not is_supported_link(link): 160 | text = "THIS LINK IS NOT SUPPORTED :(" 161 | 162 | bot.send_message(chat_id=chat_id, text=text) 163 | 164 | return 165 | 166 | c_user_data = users_data[chat_id] 167 | c_downloads = c_user_data["c_downloads"] 168 | 169 | if len(c_downloads) == max_download_user: 170 | bot.send_message(chat_id=chat_id, text=max_download_user_msg) 171 | 172 | return 173 | 174 | to_hash = f"{link}{c_user_data['quality']}{chat_id}{time()}".encode() 175 | hash_link = md5(to_hash).hexdigest() 176 | new_ins = DW(chat_id, c_user_data, hash_link) 177 | 178 | t = magicThread(target=new_ins.download, args=(link,)) 179 | 180 | c_downloads[hash_link] = {"link": link, "thread": t, "dw": new_ins} 181 | 182 | t.start() 183 | 184 | 185 | def handle_inline_queries(update: Update, context): 186 | inline_query = update.inline_query 187 | chat_id = inline_query.from_user.id 188 | 189 | if chat_id in to_ban.user_ids: 190 | return 191 | 192 | help_check_user(chat_id) 193 | query_id = inline_query.id 194 | query = inline_query.query 195 | c_user_data = users_data[chat_id] 196 | results = create_response_article(query, c_user_data) 197 | 198 | try: 199 | bot.answer_inline_query(inline_query_id=query_id, results=results) 200 | except BadRequest: 201 | pass 202 | 203 | 204 | def handle_callback_queries(update: Update, context): 205 | callback_query = update.callback_query 206 | chat_id = callback_query.from_user.id 207 | 208 | if chat_id in to_ban.user_ids: 209 | return 210 | 211 | msg = callback_query.message 212 | date = msg.date 213 | help_check_user(chat_id, date) 214 | msg_id = msg.message_id 215 | query_id = callback_query.id 216 | data = callback_query.data 217 | c_user_data = users_data[chat_id] 218 | text = "Your settings" 219 | answer = "DONE" 220 | mode = 0 221 | 222 | if data == "/edit_setting_quality": 223 | text = "Qualities" 224 | c_keyboard = create_keyboard_qualities() 225 | 226 | elif data == "/edit_setting_search_method": 227 | text = "Search methods" 228 | c_keyboard = create_keyboard_search_method() 229 | 230 | elif data == "/edit_setting_zips": 231 | zips = c_user_data["zips"] 232 | 233 | if zips: 234 | c_user_data["zips"] = False 235 | else: 236 | c_user_data["zips"] = True 237 | 238 | c_keyboard = create_keyboard_settings(c_user_data) 239 | user_setting_save_db(chat_id, c_user_data) 240 | 241 | elif data == "/edit_setting_tracks": 242 | tracks = c_user_data["tracks"] 243 | 244 | if tracks: 245 | c_user_data["tracks"] = False 246 | else: 247 | c_user_data["tracks"] = True 248 | 249 | c_keyboard = create_keyboard_settings(c_user_data) 250 | user_setting_save_db(chat_id, c_user_data) 251 | 252 | elif data == "/edit_setting_source": 253 | source = c_user_data["source"] 254 | 255 | if source == "SpoDee": 256 | c_user_data["source"] = "Dee" 257 | else: 258 | c_user_data["source"] = "SpoDee" 259 | 260 | c_keyboard = create_keyboard_settings(c_user_data) 261 | user_setting_save_db(chat_id, c_user_data) 262 | 263 | elif data.startswith("/unban_"): 264 | c_data = data.replace("/unban_", "") 265 | c_chat_id = int(c_data) 266 | text = "BANNED USERS" 267 | delete_banned(c_chat_id) 268 | to_ban.remove_chat_ids(c_chat_id) 269 | c_keyboard = create_banned_keyboard() 270 | answer = f"UNBANNED {c_chat_id}" 271 | 272 | elif data.startswith("/edit_setting_quality_"): 273 | c_data = data.replace("/edit_setting_quality_", "") 274 | c_user_data["quality"] = c_data 275 | c_keyboard = create_keyboard_settings(c_user_data) 276 | user_setting_save_db(chat_id, c_user_data) 277 | 278 | elif data.startswith("/edit_setting_search_method_"): 279 | c_data = data.replace("/edit_setting_search_method_", "") 280 | c_user_data["search_method"] = c_data 281 | c_keyboard = create_keyboard_settings(c_user_data) 282 | user_setting_save_db(chat_id, c_user_data) 283 | 284 | elif data.startswith("/down:"): 285 | mode = "down:" 286 | answer = "GOOD CHOICE :)" 287 | c_data = data.replace("/down:", "") 288 | 289 | elif data == "/back_home": 290 | c_keyboard = create_keyboard_settings(c_user_data) 291 | 292 | elif data.startswith("/kill_dw_"): 293 | mode = "kill" 294 | answer = "DOWNLOAD DELETED :)" 295 | c_hash = data.replace("/kill_dw_", "") 296 | c_dws = c_user_data["c_downloads"] 297 | 298 | if not c_hash in c_dws: 299 | answer = "THIS IS AN OLD DOWNLOAD :)" 300 | else: 301 | t = c_dws[c_hash]["thread"] 302 | t.kill() 303 | del c_dws[c_hash] 304 | 305 | else: 306 | mode = 1 307 | answer = "Sorry isn't avalaible :(" 308 | 309 | if mode == 0: 310 | bot.edit_message_text( 311 | chat_id=chat_id, message_id=msg_id, text=text, reply_markup=c_keyboard 312 | ) 313 | 314 | bot.answer_callback_query(callback_query_id=query_id, text=answer) 315 | 316 | if mode == "kill": 317 | bot.delete_message(chat_id=chat_id, message_id=msg_id) 318 | 319 | elif mode == "down:": 320 | help_download(c_data, chat_id) 321 | 322 | 323 | def audio_handler(update: Update, context): 324 | msg = update.message 325 | chat_id = msg.from_user.id 326 | msg_id = msg.message_id 327 | date = msg.date 328 | help_check_user(chat_id, date) 329 | audio = msg.audio 330 | 331 | if not audio: 332 | audio = msg.voice 333 | 334 | audio_size = convert_bytes_to(audio.file_size, "mb") 335 | 336 | if audio_size > recorded_file_max_size: 337 | bot.send_message( 338 | chat_id=chat_id, 339 | text=f"PLEASE SEND A FILE AUDIO/RECORD LOWER THAN {recorded_file_max_size} MB =)", 340 | ) 341 | 342 | return 343 | 344 | file_id = audio.file_id 345 | c_file = bot.get_file(file_id) 346 | 347 | try: 348 | SetConfigs.queues_started += 1 349 | 350 | out = c_file.download(custom_path=f"{output_shazam}{file_id}") 351 | 352 | resp = shazam_song(out) 353 | finally: 354 | SetConfigs.queues_finished += 1 355 | 356 | if not resp: 357 | bot.send_message(chat_id=chat_id, text="I CANNOT SHAZAM THE SONG RETRY :(") 358 | 359 | return 360 | 361 | ( 362 | artist, 363 | genre, 364 | album, 365 | label, 366 | track_link, 367 | album_link, 368 | artist_link, 369 | image_url, 370 | release_date, 371 | title, 372 | ) = resp 373 | 374 | if track_link: 375 | reply_markup = create_shazamed_keyboard(track_link, album_link, artist_link) 376 | else: 377 | reply_markup = None 378 | image_url = not_found_query_gif 379 | 380 | bot.send_photo( 381 | chat_id=chat_id, 382 | photo=image_url, 383 | reply_to_message_id=msg_id, 384 | reply_markup=reply_markup, 385 | caption=( 386 | shazam_audio_query % (artist, genre, album, label, release_date, title) 387 | ), 388 | ) 389 | 390 | 391 | def start_command(update: Update, context): 392 | msg = update.message 393 | chat_id = msg.from_user.id 394 | date = msg.date 395 | help_check_user(chat_id, date) 396 | if not participant(chat_id): 397 | bot.send_message( 398 | chat_id=chat_id, 399 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 400 | ) 401 | return 402 | bot.send_message( 403 | chat_id=chat_id, 404 | text="YOU JUST PRESSED START YOU WON A NICE DAY :)))", 405 | reply_markup=create_keyboad_search(""), 406 | ) 407 | 408 | 409 | def settings_command(update: Update, context): 410 | msg = update.message 411 | chat_id = msg.from_user.id 412 | date = msg.date 413 | help_check_user(chat_id, date) 414 | c_user_data = users_data[chat_id] 415 | if not participant(chat_id): 416 | bot.send_message( 417 | chat_id=chat_id, 418 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 419 | ) 420 | return 421 | bot.send_message( 422 | chat_id=chat_id, 423 | text="Your settings", 424 | reply_markup=create_keyboard_settings(c_user_data), 425 | ) 426 | 427 | 428 | def quality_command(update: Update, context): 429 | msg = update.message 430 | chat_id = msg.from_user.id 431 | date = msg.date 432 | help_check_user(chat_id, date) 433 | c_user_data = users_data[chat_id] 434 | if not participant(chat_id): 435 | bot.send_message( 436 | chat_id=chat_id, 437 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 438 | ) 439 | return 440 | 441 | bot.send_message( 442 | chat_id=chat_id, 443 | text=f"Current quality {c_user_data['quality']}", 444 | reply_markup=create_keyboard_qualities(), 445 | ) 446 | 447 | 448 | def managing_banned_command(update: Update, context): 449 | msg = update.message 450 | chat_id = msg.from_user.id 451 | if not participant(chat_id): 452 | bot.send_message( 453 | chat_id=chat_id, 454 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 455 | ) 456 | return 457 | 458 | bot.send_message( 459 | chat_id=chat_id, text="Banned users", reply_markup=create_banned_keyboard() 460 | ) 461 | 462 | 463 | def add_banned_command(update: Update, context): 464 | msg = update.message 465 | chat_id = msg.from_user.id 466 | if not participant(chat_id): 467 | bot.send_message( 468 | chat_id=chat_id, 469 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 470 | ) 471 | return 472 | 473 | if not chat_id in roots_data: 474 | roots_data[chat_id] = {"stage": None} 475 | 476 | bot.send_message(chat_id=chat_id, text="Send me the user to ban") 477 | 478 | roots_data[chat_id]["stage"] = "add_banned" 479 | 480 | 481 | def send_global_msg_command(update: Update, context): 482 | msg = update.channel_post 483 | text = msg.text 484 | audio = msg.audio 485 | document = msg.document 486 | animation = msg.animation 487 | sticker = msg.sticker 488 | video = msg.video 489 | photo = msg.photo 490 | to_send = None 491 | method = None 492 | 493 | if text: 494 | to_send = text 495 | method = bot.send_message 496 | elif audio: 497 | to_send = audio.file_id 498 | method = bot.send_audio 499 | elif document: 500 | to_send = document.file_id 501 | method = bot.send_document 502 | elif animation: 503 | to_send = animation.file_id 504 | method = bot.send_animation 505 | elif sticker: 506 | to_send = sticker.file_id 507 | method = bot.send_sticker 508 | elif video: 509 | to_send = video.file_id 510 | method = bot.send_video 511 | elif photo: 512 | to_send = photo[0].file_id 513 | method = bot.send_photo 514 | 515 | def broadcast(): 516 | all_user = select_all_users() 517 | 518 | for user_id in all_user: 519 | c_user_id = user_id[0] 520 | 521 | try: 522 | method(c_user_id, to_send) 523 | except (BadRequest, Unauthorized): 524 | pass 525 | 526 | magicThread(target=broadcast).start() 527 | 528 | 529 | def shazam_command(update: Update, context): 530 | 531 | msg = update.message 532 | chat_id = msg.from_user.id 533 | date = msg.date 534 | help_check_user(chat_id, date) 535 | if not participant(chat_id): 536 | bot.send_message( 537 | chat_id=chat_id, 538 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 539 | ) 540 | return 541 | 542 | bot.send_message(chat_id=chat_id, text=shazam_function_msg) 543 | 544 | 545 | def kill_dw_command(update: Update, context): 546 | msg = update.message 547 | chat_id = msg.from_user.id 548 | date = msg.date 549 | help_check_user(chat_id, date) 550 | c_user_data = users_data[chat_id] 551 | c_downloads = c_user_data["c_downloads"] 552 | 553 | if not c_downloads: 554 | bot.send_message(chat_id=chat_id, text="There aren't any download in progress") 555 | 556 | return 557 | 558 | keybords_dws = create_c_dws_user_keyboard(c_downloads) 559 | 560 | for c_download, keyboard in zip(c_downloads.values(), keybords_dws): 561 | c_text = f"{c_download['link']} in {c_user_data['quality']}" 562 | 563 | bot.send_message(chat_id=chat_id, text=c_text, reply_markup=keyboard) 564 | 565 | 566 | def info_command(update: Update, context): 567 | msg = update.message 568 | chat_id = msg.from_user.id 569 | date = msg.date 570 | help_check_user(chat_id, date) 571 | users_graph = create_graph_users() 572 | if not participant(chat_id): 573 | bot.send_message( 574 | chat_id=chat_id, 575 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 576 | ) 577 | return 578 | 579 | bot.send_photo( 580 | chat_id=chat_id, 581 | photo=users_graph, 582 | caption=get_info(), 583 | reply_markup=create_info_keyboard(), 584 | ) 585 | 586 | 587 | def reasons_command(update: Update, context): 588 | msg = update.message 589 | chat_id = msg.from_user.id 590 | date = msg.date 591 | help_check_user(chat_id, date) 592 | if not participant(chat_id): 593 | bot.send_message( 594 | chat_id=chat_id, 595 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 596 | ) 597 | return 598 | 599 | bot.send_message(chat_id=chat_id, text=reasons_text) 600 | 601 | 602 | def help_command(update: Update, context): 603 | msg = update.message 604 | chat_id = msg.from_user.id 605 | date = msg.date 606 | help_check_user(chat_id, date) 607 | if not participant(chat_id): 608 | bot.send_message( 609 | chat_id=chat_id, 610 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 611 | ) 612 | return 613 | 614 | bot.send_photo(chat_id=chat_id, photo=help_photo, caption=help_msg) 615 | 616 | bot.send_message(chat_id=chat_id, text=what_can_I_do) 617 | 618 | 619 | def feedback_command(update: Update, context): 620 | msg = update.message 621 | chat_id = msg.from_user.id 622 | date = msg.date 623 | help_check_user(chat_id, date) 624 | if not participant(chat_id): 625 | bot.send_message( 626 | chat_id=chat_id, 627 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 628 | ) 629 | return 630 | 631 | bot.send_message(chat_id=chat_id, text=feedback_text) 632 | 633 | 634 | def donate_command(update: Update, context): 635 | msg = update.message 636 | chat_id = msg.from_user.id 637 | date = msg.date 638 | help_check_user(chat_id, date) 639 | if not participant(chat_id): 640 | bot.send_message( 641 | chat_id=chat_id, 642 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 643 | ) 644 | return 645 | 646 | bot.send_message( 647 | chat_id=chat_id, text=donate_text, reply_markup=create_info_keyboard() 648 | ) 649 | 650 | 651 | def graphs_command(update: Update, context): 652 | msg = update.message 653 | chat_id = msg.from_user.id 654 | date = msg.date 655 | help_check_user(chat_id, date) 656 | downloads_graph = create_graph_top_downloaders() 657 | users_graph = create_graph_users() 658 | users, nums_downloads = get_data_downloaders() 659 | if not participant(chat_id): 660 | bot.send_message( 661 | chat_id=chat_id, 662 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 663 | ) 664 | return 665 | 666 | caption_text_download_graph = "" 667 | times = 1 668 | 669 | for user, num_downloads in zip(users, nums_downloads): 670 | caption_text_download_graph += ( 671 | f"{times} Place: User `{user}` with {num_downloads} downloads\n" 672 | ) 673 | times += 1 674 | 675 | medias = [ 676 | InputMediaPhoto( 677 | media=downloads_graph, 678 | caption=caption_text_download_graph, 679 | parse_mode=ParseMode.MARKDOWN_V2, 680 | ), 681 | InputMediaPhoto(media=users_graph), 682 | ] 683 | 684 | bot.send_media_group(chat_id=chat_id, media=medias) 685 | 686 | 687 | def msgs_handler(update: Update, context): 688 | msg = update.message 689 | chat_id = msg.from_user.id 690 | text = msg.text 691 | if not participant(chat_id): 692 | bot.send_message( 693 | chat_id=chat_id, 694 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 695 | ) 696 | return 697 | 698 | if chat_id in roots_data: 699 | if roots_data[chat_id]["stage"] == "add_banned": 700 | ban_chat_id(text) 701 | roots_data[chat_id]["stage"] = None 702 | 703 | bot.send_message(chat_id=chat_id, text=f"User {text} has been blocked") 704 | 705 | return 706 | 707 | date = msg.date 708 | help_check_user(chat_id, date) 709 | 710 | bot.send_message( 711 | chat_id=chat_id, text=text, reply_markup=create_keyboad_search(text) 712 | ) 713 | 714 | 715 | def controls_links(update: Update, context): 716 | msg = update.message 717 | chat_id = msg.from_user.id 718 | date = msg.date 719 | if not participant(chat_id): 720 | bot.send_message( 721 | chat_id=chat_id, 722 | text=f"Please join our channel to use this bot.\n{SetConfigs.__fsub_chat_link}", 723 | ) 724 | return 725 | help_check_user(chat_id, date) 726 | entity_link = msg.entities[0] 727 | link = msg.parse_entity(entity_link) 728 | help_download(link, chat_id) 729 | 730 | 731 | dispatcher = SetConfigs.tg_bot_api.dispatcher 732 | 733 | start_handler = CommandHandler("start", start_command, filters=~to_ban, run_async=True) 734 | 735 | dispatcher.add_handler(start_handler) 736 | 737 | settings_handler = CommandHandler( 738 | "settings", settings_command, filters=~to_ban, run_async=True 739 | ) 740 | 741 | dispatcher.add_handler(settings_handler) 742 | 743 | quality_handler = CommandHandler( 744 | "quality", quality_command, filters=~to_ban, run_async=True 745 | ) 746 | 747 | dispatcher.add_handler(quality_handler) 748 | 749 | to_root = Filters.user(root_ids) 750 | 751 | managing_banned_handler = CommandHandler( 752 | "managing_banned", managing_banned_command, filters=to_root, run_async=True 753 | ) 754 | 755 | dispatcher.add_handler(managing_banned_handler) 756 | 757 | add_banned_handler = CommandHandler( 758 | "add_banned", add_banned_command, filters=to_root, run_async=True 759 | ) 760 | 761 | dispatcher.add_handler(add_banned_handler) 762 | 763 | shazam_handler = CommandHandler( 764 | "shazam", shazam_command, filters=~to_ban, run_async=True 765 | ) 766 | 767 | dispatcher.add_handler(shazam_handler) 768 | 769 | kill_dw_handler = CommandHandler( 770 | "kill_dw", kill_dw_command, filters=~to_ban, run_async=True 771 | ) 772 | 773 | dispatcher.add_handler(kill_dw_handler) 774 | 775 | info_handler = CommandHandler("info", info_command, filters=~to_ban, run_async=True) 776 | 777 | dispatcher.add_handler(info_handler) 778 | 779 | reasons_handler = CommandHandler( 780 | "reasons", reasons_command, filters=~to_ban, run_async=True 781 | ) 782 | 783 | dispatcher.add_handler(reasons_handler) 784 | 785 | help_handler = CommandHandler("help", help_command, filters=~to_ban, run_async=True) 786 | 787 | dispatcher.add_handler(help_handler) 788 | 789 | feedback_handler = CommandHandler( 790 | "feedback", feedback_command, filters=~to_ban, run_async=True 791 | ) 792 | 793 | dispatcher.add_handler(feedback_handler) 794 | 795 | donate_handler = CommandHandler( 796 | "donate", donate_command, filters=~to_ban, run_async=True 797 | ) 798 | 799 | dispatcher.add_handler(donate_handler) 800 | 801 | graphs_handler = CommandHandler( 802 | "graphs", graphs_command, filters=~to_ban, run_async=True 803 | ) 804 | 805 | dispatcher.add_handler(graphs_handler) 806 | 807 | filter_owl_channel = Filters.chat(owl_channel) 808 | 809 | send_global_msg_handler = MessageHandler( 810 | filter_owl_channel, send_global_msg_command, run_async=True 811 | ) 812 | 813 | dispatcher.add_handler(send_global_msg_handler) 814 | 815 | filter_url = Filters.entity(MessageEntity.URL) 816 | 817 | control_links = MessageHandler((filter_url & ~to_ban), controls_links, run_async=True) 818 | 819 | dispatcher.add_handler(control_links) 820 | 821 | filter_text = Filters.text 822 | 823 | msgs = MessageHandler((filter_text & ~to_ban), msgs_handler, run_async=True) 824 | 825 | dispatcher.add_handler(msgs) 826 | 827 | filter_shazam = Filters.voice | Filters.audio 828 | filter_bunker_channel = Filters.chat(bunker_channel) 829 | filter_no_bot = Filters.via_bot(bot_chat_id) 830 | 831 | audio_msgs = MessageHandler( 832 | (filter_shazam & ~filter_no_bot & ~to_ban & ~filter_bunker_channel), 833 | audio_handler, 834 | run_async=True, 835 | ) 836 | 837 | dispatcher.add_handler(audio_msgs) 838 | 839 | inline_queries = InlineQueryHandler(handle_inline_queries, run_async=True) 840 | 841 | dispatcher.add_handler(inline_queries) 842 | 843 | callback_queries = CallbackQueryHandler(handle_callback_queries, run_async=True) 844 | 845 | dispatcher.add_handler(callback_queries) 846 | 847 | SetConfigs.tg_bot_api.start_polling() 848 | 849 | 850 | def checking(): 851 | while True: 852 | sleep(time_sleep) 853 | 854 | dir_size = my_round(get_download_dir_size()) 855 | 856 | print( 857 | f"STATUS DOWNLOADS {SetConfigs.queues_started}/{SetConfigs.queues_finished} {dir_size}/{download_dir_max_size}" 858 | ) 859 | 860 | if (dir_size >= download_dir_max_size) or ( 861 | SetConfigs.queues_started == SetConfigs.queues_finished 862 | ): 863 | SetConfigs.tg_bot_api.stop() 864 | kill_threads(users_data) 865 | sleep(3) 866 | SetConfigs.queues_started = 0 867 | SetConfigs.queues_finished = 0 868 | clear_download_dir() 869 | clear_recorded_dir() 870 | SetConfigs.tg_bot_api.start_polling() 871 | 872 | 873 | if len(argv) == 1: 874 | tmux_session = None 875 | else: 876 | tmux_session = create_tmux() 877 | 878 | check_thread = magicThread(target=checking) 879 | check_thread.start() 880 | 881 | tg_user_start() 882 | 883 | print("\nEXITTING WAIT A FEW SECONDS :)") 884 | clear_download_dir() 885 | clear_recorded_dir() 886 | 887 | SetConfigs.tg_bot_api.stop() 888 | check_thread.kill() 889 | kill_threads(users_data) 890 | 891 | if tmux_session: 892 | tmux_session.kill_session() 893 | --------------------------------------------------------------------------------