├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── main.py ├── requirements.txt └── runtime.txt /.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 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 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 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Joy Biswas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python3 main.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Subtitle Downloader Bot 4 |
5 | Python 6 | PyCharm 7 | Git 8 |
9 |
10 | Heroku 11 | Heroku 12 | 13 | A Telegram bot to download Subtitle for movies and tv shows. 14 |
15 | 16 | 17 | 18 | ### Host on Heroku 19 | 20 |

Deploy to Heroku

21 | 22 | ## Configuring Environments 23 | - `API_HASH` : Your Telegram APP HASH, get this from https://my.telegram.org 24 | - `API_KEY` : Your Telegram APP API KEY, get this from https://my.telegram.org 25 | - `BOT_TOKEN` : Your bot token, generate it from https://t.me/BotFather 26 | - `CUTTLY_API` : Create an account on https://cutt.ly/register and generate an API KEY. 27 | - `WORKERS` : Number of threads to use, this depends on usage. 4 is the recommended (and default) amount, but your experience may vary. 28 | 29 | ## Credits 30 | - TerminalWarlord 31 | 32 | ### Show some :heart: and :star: the repo to support the project 33 | 34 | [![GitHub stars](https://img.shields.io/github/stars/TerminalWarlord/subtitle-downloader-bot.svg?style=social&label=Star)](https://github.com/TerminalWarlord/GoGoAnime-API) ![GitHub followers](https://img.shields.io/github/followers/TerminalWarlord.svg?style=social&label=Follow) 35 | 36 | [![Telegram Channel](https://img.shields.io/badge/Telegram-Channel-orange)](https://t.me/JayBeeBots) 37 | ![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://github.com/TerminalWarlord/Subtitle-Downloader-Bot) 38 | 39 | --- 40 | ### Star the Repo if you find it useful :heart: 41 | ### © [JayBee](https://t.me/JayBeeBots) 42 | #### All Rights Reserved 43 | --- 44 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JayBee Subtitle Bot", 3 | "description": "Telegram bot to download subtitle for movies and tv shows", 4 | "logo" : "https://telegra.ph/file/05bae0725724007c72fa1.jpg", 5 | "success_url" : "https://t.me/JayBeeBots", 6 | "keywords": [ 7 | "telegram", 8 | "bot", 9 | "subtitle", 10 | "jaybee" 11 | ], 12 | "repository": "https://github.com/TerminalWarlord/Subtitle-Downloader-Bot", 13 | "website": "https://github.com/TerminalWarlord/Subtitle-Downloader-Bot", 14 | "env": { 15 | "BOT_TOKEN": { 16 | "description": "Your bot Bot Token, get this value from @BotFather.", 17 | "value": "" 18 | }, 19 | "API_KEY": { 20 | "description": "Your APP API KEY, get this from https://my.telegram.org", 21 | "value": "" 22 | }, 23 | "API_HASH": { 24 | "description": "Your APP HASH, get this from https://my.telegram.org", 25 | "value": "" 26 | }, 27 | "CUTTLY_API": { 28 | "description": "Create an account on https://cutt.ly/register and generate an API KEY", 29 | "value": "" 30 | }, 31 | "WORKERS": { 32 | "description": "Number of threads to use, this depends on usage. 4 is the recommended (and default) amount, but your experience may vary.", 33 | "value": "4" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 TerminalWarlord under the terms of the MIT 2 | # license found at https://github.com/TerminalWarlord/Subtitle-Downloader-Bot/blob/master/LICENSE 3 | # Encoding = 'utf-8' 4 | # Fork and Deploy, do not modify this repo and claim it yours 5 | # For collaboration mail me at dev.jaybee@gmail.com 6 | 7 | 8 | from pyrogram import Client, filters 9 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 10 | import shutil 11 | import requests 12 | import os 13 | import glob 14 | from bs4 import BeautifulSoup as bs 15 | import time 16 | from datetime import timedelta 17 | from dotenv import load_dotenv 18 | import zipfile 19 | 20 | load_dotenv() 21 | bot_token = os.environ.get('BOT_TOKEN') 22 | api = int(os.environ.get('API_KEY')) 23 | hash = os.environ.get('API_HASH') 24 | workers = int(os.environ.get('WORKERS')) 25 | app = Client("JayBeeSubtitleDL", bot_token=bot_token, api_id=api, api_hash=hash, workers=workers) 26 | cuttly = os.environ.get('CUTTLY_API') 27 | 28 | timestarted = timedelta(seconds=int(time.time())) 29 | 30 | 31 | @app.on_message(filters.command('start')) 32 | def start(client,message): 33 | kb = [[InlineKeyboardButton('Channel 🛡', url="https://t.me/JayBeeBots"),InlineKeyboardButton('Support Group 🔰', url="https://t.me/JayBeeBotsSupport")]] 34 | reply_markup = InlineKeyboardMarkup(kb) 35 | app.send_message(chat_id=message.from_user.id, text=f"Hello there, I am a __**Subtitle Downloader Bot**__.\nGive me a Movie/Series name and I will fetch it from __**Subscene**__.\n\n" 36 | "__**Developer :**__ __@JayBeeDev__\n" 37 | "__**Language :**__ __Python__\n" 38 | "__**Framework :**__ __🔥 Pyrogram__", 39 | parse_mode='md', 40 | reply_markup=reply_markup) 41 | 42 | @app.on_message(filters.command('help')) 43 | def help(client,message): 44 | url = [[InlineKeyboardButton(f"PayPal Me ❤️", url=f"https://paypal.me/JayBeeDev")], 45 | [InlineKeyboardButton(f"Buy Me A Coffee ☕️", url=f"https://buymeacoffee.com/JayBee.Dev")]] 46 | reply_markup = InlineKeyboardMarkup(url) 47 | message.reply_text(reply_to_message_id= message.message_id,text=f"Send me any Movie/Series name and I will -\n" 48 | f"__ * Search for it on `Subscene.com`\n" 49 | f" * Let you choose your preferable language.\n" 50 | f" * Download the subtitle, unzip and upload in `.srt/.ass` format__", parse_mode='md', reply_markup=reply_markup) 51 | 52 | 53 | @app.on_message(filters.command('uptime')) 54 | def uptime(client, message): 55 | timecheck = timedelta(seconds=int(time.time())) 56 | uptime = timecheck - timestarted 57 | app.send_message(chat_id=message.from_user.id, text=f"__**Uptime :**__ __{uptime}__", 58 | parse_mode='md') 59 | 60 | 61 | @app.on_message(filters.text) 62 | def search(client, message): 63 | query = message.text.replace(" ", "+") 64 | data = { 65 | 'query' : query, 66 | 'l' : '' 67 | } 68 | 69 | res = requests.post('https://subscene.com/subtitles/searchbytitle', data=data) 70 | soup = bs(res.text, 'html.parser') 71 | results = soup.find('div', {'class': 'search-result'}).find_all('div', {'class': 'title'}) 72 | kb = [] 73 | i = 0 74 | l = 0 75 | for sub in results: 76 | if l < 10: 77 | sublink = sub.find('a').attrs['href'].split('/')[-1] 78 | subtitlename = sub.find('a').text 79 | if len(sublink)<64: 80 | kb.append([InlineKeyboardButton(f"{subtitlename}", callback_data=f'LANG*{sublink}')]) 81 | i += 1 82 | else: 83 | pass 84 | 85 | else: 86 | pass 87 | l += 1 88 | if len(results) > i: 89 | kb.append([InlineKeyboardButton(f"Next ⏭", callback_data=f'SRCNX*{i}*{query}')]) 90 | reply_markup = InlineKeyboardMarkup(kb) 91 | app.send_message(chat_id=message.chat.id, 92 | text=f"__Showing Result for **{query}**\n" 93 | f"Choose your desired Movie/Series:__", 94 | parse_mode='md', 95 | reply_markup=reply_markup) 96 | 97 | 98 | @app.on_callback_query(filters.regex('SRCNX')) 99 | def searchnext(client, callback_query): 100 | query = callback_query.data.split('*')[-1] 101 | data = { 102 | 'query' : query, 103 | 'l' : '' 104 | } 105 | res = requests.post('https://subscene.com/subtitles/searchbytitle', data=data) 106 | soup = bs(res.text, 'html.parser') 107 | results = soup.find('div', {'class': 'search-result'}).find_all('div', {'class': 'title'}) 108 | kb = [] 109 | i = int(callback_query.data.split('*')[-2]) + 1 110 | j = i - 1 111 | k = i + 10 112 | l = 0 113 | for sub in results: 114 | if l > j and l < k: 115 | sublink = sub.find('a').attrs['href'].split('/')[-1] 116 | subtitlename = sub.find('a').text 117 | if len(sublink)<64: 118 | kb.append([InlineKeyboardButton(f"{subtitlename}", callback_data=f'LANG*{sublink}')]) 119 | i += 1 120 | else: 121 | pass 122 | else: 123 | pass 124 | l += 1 125 | 126 | if len(results) > i: 127 | kb.append([InlineKeyboardButton(f"Next ⏭", callback_data=f'SRCNX*{i}*{query}')]) 128 | kb.append([InlineKeyboardButton(f"Previous ⏮️", callback_data=f'SRCPR*{i}*{query}')]) 129 | 130 | reply_markup = InlineKeyboardMarkup(kb) 131 | callback_query.edit_message_reply_markup(reply_markup=reply_markup) 132 | 133 | 134 | 135 | @app.on_callback_query(filters.regex('SRCPR')) 136 | def searchprev(client, callback_query): 137 | query = callback_query.data.split('*')[-1] 138 | data = { 139 | 'query' : query, 140 | 'l' : '' 141 | } 142 | res = requests.post('https://subscene.com/subtitles/searchbytitle', data=data) 143 | soup = bs(res.text, 'html.parser') 144 | results = soup.find('div', {'class': 'search-result'}).find_all('div', {'class': 'title'}) 145 | kb = [] 146 | i = int(callback_query.data.split('*')[-2]) 147 | j = i - 21 148 | k = i - 10 149 | l = 0 150 | for sub in results: 151 | if l > j and l < k: 152 | sublink = sub.find('a').attrs['href'].split('/')[-1] 153 | subtitlename = sub.find('a').text 154 | if len(sublink)<64: 155 | kb.append([InlineKeyboardButton(f"{subtitlename}", callback_data=f'LANG*{sublink}')]) 156 | i -= 1 157 | else: 158 | pass 159 | else: 160 | pass 161 | l += 1 162 | if j > 10: 163 | kb.append([InlineKeyboardButton(f"Previous ⏮️", callback_data=f'SRCPR*{i}*{language}*{suburl}')]) 164 | if len(results) > i: 165 | kb.append([InlineKeyboardButton(f"Next ⏭", callback_data=f'SRCNX*{i}*{query}')]) 166 | reply_markup = InlineKeyboardMarkup(kb) 167 | callback_query.edit_message_reply_markup(reply_markup=reply_markup) 168 | 169 | 170 | 171 | @app.on_callback_query(filters.regex('LANG')) 172 | def chooselang(client, callback_query): 173 | sublink = callback_query.data.split('*')[-1] 174 | kb = [[InlineKeyboardButton("English 🇬🇧", callback_data=f'PREL*english*{sublink}')], 175 | [InlineKeyboardButton("Bengali 🇧🇩", callback_data=f'PREL*bengali*{sublink}')], 176 | [InlineKeyboardButton("Hindi 🇮🇳", callback_data=f'PRE*hindi*{sublink}')], 177 | [InlineKeyboardButton("Indonesian 🇮🇩", callback_data=f'PREL*indonesian*{sublink}')]] 178 | reply_markup = InlineKeyboardMarkup(kb) 179 | app.edit_message_text(chat_id=callback_query.message.chat.id, 180 | message_id=callback_query.message.message_id, 181 | text=f"__Select a Subtitle Language__", 182 | parse_mode='md', 183 | reply_markup=reply_markup) 184 | 185 | 186 | @app.on_callback_query(filters.regex('PREL')) 187 | def langset(client, callback_query): 188 | language = callback_query.data.split('*')[-2] 189 | callback_query.answer(f"Preffered Language : {language.capitalize()}", show_alert=False) 190 | suburl = callback_query.data.split('*')[-1] 191 | url = f'https://subscene.com/subtitles/{suburl}/{language}' 192 | r = requests.get(url) 193 | soup = bs(r.text, 'html.parser') 194 | allsubs = soup.find('tbody').find_all('tr') 195 | kb = [] 196 | i = 0 197 | for subs in allsubs: 198 | try: 199 | if i < 10: 200 | subid = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-1] 201 | sublink = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-3] 202 | subname = subs.find('td', {'class': 'a1'}).find_all('span')[1].text.strip() 203 | if len(sublink) < 64: 204 | kb.append([InlineKeyboardButton(f"{subname}", callback_data=f'DTL*{language}*{sublink}*{subid}')]) 205 | i += 1 206 | 207 | else: 208 | pass 209 | else: 210 | break 211 | except: 212 | pass 213 | if i > 10: 214 | kb.append([InlineKeyboardButton(f"Next ⏭️", callback_data=f'NXT*{i}*{language}*{suburl}')]) 215 | try: 216 | reply_markup = InlineKeyboardMarkup(kb) 217 | app.edit_message_text(chat_id=callback_query.message.chat.id, 218 | message_id=callback_query.message.message_id, 219 | text=f"__Select a Subtitle__", 220 | parse_mode='md', 221 | reply_markup=reply_markup) 222 | except: 223 | app.edit_message_text(chat_id=callback_query.message.chat.id, 224 | message_id=callback_query.message.message_id, 225 | text=f"__Sorry no subtitle available for that specific language!\n" 226 | f"Try another one!__", 227 | parse_mode='md') 228 | 229 | 230 | @app.on_callback_query(filters.regex('DTL')) 231 | def subdetails(client, callback_query): 232 | language = callback_query.data.split('*')[-3] 233 | suburl = callback_query.data.split('*')[-2] 234 | subid = callback_query.data.split('*')[-1] 235 | kb = [] 236 | # getsub 237 | url = f'https://subscene.com/subtitles/{suburl}/{language}/{subid}' 238 | callback_query.answer(f"Getting sub from : {url}", show_alert=False) 239 | r = requests.get(url) 240 | soup = bs(r.text, 'html.parser') 241 | poster = soup.find('div', {'class': 'poster'}).find('img').attrs['src'].replace('154-', '') 242 | info = soup.find('div', {'id': 'details'}).find('ul').find_all('li') 243 | dload = "https://subscene.com" + soup.find('a', {'id': 'downloadButton'}).attrs['href'] 244 | subdetails = [] 245 | for a in info: 246 | try: 247 | w = a.text.replace('-', '') 248 | a = "".join(line.strip() for line in w.split("\n")) 249 | subdetails.append(a) 250 | except: 251 | pass 252 | subtext = "\n".join(subdetails) 253 | 254 | #cuttly 255 | data = requests.get(f"https://cutt.ly/api/api.php?key={cuttly}&short={dload}").json()["url"] 256 | shortened_url = data["shortLink"] 257 | 258 | kb = [[InlineKeyboardButton(f"Download", callback_data=f'DOWNLOAD*{shortened_url}')]] 259 | reply_markup = InlineKeyboardMarkup(kb) 260 | app.send_photo(caption=f'__{subtext}__', 261 | photo=poster, 262 | chat_id=callback_query.message.chat.id, 263 | parse_mode='md', 264 | reply_markup=reply_markup) 265 | 266 | 267 | 268 | 269 | @app.on_callback_query(filters.regex('DOWNLOAD')) 270 | def download(client, callback_query): 271 | callback_query.answer(f"Downloading!!!", show_alert=False) 272 | link = callback_query.data.split('*')[-1] 273 | # unzip 274 | url = requests.get(link).url 275 | r = requests.head(url) 276 | a = r.headers 277 | filename = a['Content-Disposition'].split('=')[-1] 278 | directory = a['Content-Disposition'].split('=')[-1].replace('.zip', '') 279 | with open(filename, 'wb') as f: 280 | im = requests.get(link) 281 | f.write(im.content) 282 | with zipfile.ZipFile(filename,"r") as zip_ref: 283 | zip_ref.extractall(directory) 284 | try: 285 | a = glob.glob(f'./{directory}/*srt', recursive=True) 286 | for file in a: 287 | app.send_document(document=file, 288 | chat_id=callback_query.message.chat.id, 289 | parse_mode='md') 290 | app.delete_messages(chat_id=callback_query.message.chat.id, 291 | message_ids=callback_query.message.message_id) 292 | except: 293 | a = glob.glob(f'./{directory}/*', recursive=True) 294 | for file in a: 295 | app.send_document(document=file, 296 | chat_id=callback_query.message.chat.id, 297 | parse_mode='md') 298 | app.delete_messages(chat_id=callback_query.message.chat.id, 299 | message_ids=callback_query.message.message_id) 300 | try: 301 | os.remove(filename) 302 | shutil.rmtree(directory) 303 | except: 304 | pass 305 | 306 | 307 | 308 | @app.on_callback_query(filters.regex('NXT')) 309 | def nextres(client, callback_query): 310 | language = callback_query.data.split('*')[-2] 311 | suburl = callback_query.data.split('*')[-1] 312 | url = f'https://subscene.com/subtitles/{suburl}/{language}' 313 | print(url) 314 | r = requests.get(url) 315 | soup = bs(r.text, 'html.parser') 316 | allsubs = soup.find('tbody').find_all('tr') 317 | kb = [] 318 | i = int(callback_query.data.split('*')[-3]) + 1 319 | j = i - 1 320 | k = i + 10 321 | l = 0 322 | for subs in allsubs: 323 | try: 324 | if l > j and l < k: 325 | subid = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-1] 326 | sublink = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-3] 327 | subname = subs.find('td', {'class': 'a1'}).find_all('span')[1].text.strip() 328 | if len(sublink) < 64: 329 | kb.append([InlineKeyboardButton(f"{subname}", callback_data=f'DTL*{language}*{sublink}*{subid}')]) 330 | i += 1 331 | 332 | else: 333 | pass 334 | else: 335 | pass 336 | l += 1 337 | 338 | except: 339 | pass 340 | if len(allsubs) > i: 341 | kb.append([InlineKeyboardButton(f"Next ⏭️", callback_data=f'NXT*{i}*{language}*{suburl}')]) 342 | kb.append([InlineKeyboardButton(f"Previous ⏮️", callback_data=f'PRV*{i}*{language}*{suburl}')]) 343 | reply_markup = InlineKeyboardMarkup(kb) 344 | a = app.edit_message_text(chat_id=callback_query.message.chat.id, 345 | message_id=callback_query.message.message_id, 346 | text=f"__Select a Subtitle__", 347 | parse_mode='md', 348 | reply_markup=reply_markup) 349 | 350 | @app.on_callback_query(filters.regex('PRV')) 351 | def prevres(client, callback_query): 352 | language = callback_query.data.split('*')[-2] 353 | suburl = callback_query.data.split('*')[-1] 354 | url = f'https://subscene.com/subtitles/{suburl}/{language}' 355 | r = requests.get(url) 356 | soup = bs(r.text, 'html.parser') 357 | allsubs = soup.find('tbody').find_all('tr') 358 | kb = [] 359 | i = int(callback_query.data.split('*')[-3]) 360 | j = i - 21 361 | k = i - 10 362 | l = 0 363 | for subs in allsubs: 364 | try: 365 | if l > j and l < k: 366 | subid = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-1] 367 | sublink = subs.find('td', {'class': 'a1'}).find('a').attrs['href'].split('/')[-3] 368 | subname = subs.find('td', {'class': 'a1'}).find_all('span')[1].text.strip() 369 | if len(sublink) < 64: 370 | kb.append([InlineKeyboardButton(f"{subname}", callback_data=f'DTL*{language}*{sublink}*{subid}')]) 371 | i -= 1 372 | 373 | else: 374 | pass 375 | else: 376 | pass 377 | l += 1 378 | 379 | except: 380 | pass 381 | if j > 10: 382 | kb.append([InlineKeyboardButton(f"Previous ⏮️", callback_data=f'PRV*{i}*{language}*{suburl}')]) 383 | if len(allsubs) > i: 384 | kb.append([InlineKeyboardButton(f"Next ⏭️", callback_data=f'NXT*{i}*{language}*{suburl}')]) 385 | 386 | reply_markup = InlineKeyboardMarkup(kb) 387 | app.edit_message_text(chat_id=callback_query.message.chat.id, 388 | message_id=callback_query.message.message_id, 389 | text=f"__Select a Subtitle__", 390 | parse_mode='md', 391 | reply_markup=reply_markup) 392 | 393 | app.run() 394 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.25.1 2 | pyrogram 3 | tgcrypto 4 | pymongo[srv] 5 | python-dotenv 6 | bs4 -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.8.5 --------------------------------------------------------------------------------