├── .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 |
9 |
10 |

11 |

12 |
13 | A Telegram bot to download Subtitle for movies and tv shows.
14 |
15 |
16 |
17 |
18 | ### Host on Heroku
19 |
20 | 
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 | [](https://github.com/TerminalWarlord/GoGoAnime-API) 
35 |
36 | [](https://t.me/JayBeeBots)
37 | 
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
--------------------------------------------------------------------------------