import json, requests, os, shlex, asyncio, uuid, shutil
from typing import Tuple
from pyrogram import Client, filters
from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery

# Configs
API_HASH = os.environ['API_HASH']
APP_ID = int(os.environ['APP_ID'])
BOT_TOKEN = os.environ['BOT_TOKEN']
downloads = './downloads/{}/'

#Button
START_BUTTONS=[
    [
        InlineKeyboardButton('Source', url='https://github.com/X-Gorn/TikTokDL'),
        InlineKeyboardButton('Project Channel', url='https://t.me/xTeamBots'),
    ],
    [InlineKeyboardButton('Author', url='https://t.me/xgorn')],
]

DL_BUTTONS=[
    [
        InlineKeyboardButton('No Watermark', callback_data='nowm'),
        InlineKeyboardButton('Watermark', callback_data='wm'),
    ],
    [InlineKeyboardButton('Audio', callback_data='audio')],
]


# Running bot
xbot = Client('TikTokDL', api_id=APP_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)


# Helpers
# Thanks to FridayUB
async def run_cmd(cmd: str) -> Tuple[str, str, int, int]:
  args = shlex.split(cmd)
  process = await asyncio.create_subprocess_exec(
      *args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
  )
  stdout, stderr = await process.communicate()
  return (
      stdout.decode("utf-8", "replace").strip(),
      stderr.decode("utf-8", "replace").strip(),
      process.returncode,
      process.pid,
  )

# Start
@xbot.on_message(filters.command('start') & filters.private)
async def _start(bot, update):
  await update.reply_text(f"I'm TikTokDL!\nYou can download tiktok video/audio using this bot", True, reply_markup=InlineKeyboardMarkup(START_BUTTONS))

# Downloader for tiktok
@xbot.on_message(filters.regex(pattern='.*http.*') & filters.private)
async def _tiktok(bot, update):
  url = update.text
  session = requests.Session()
  resp = session.head(url, allow_redirects=True)
  if not 'tiktok.com' in resp.url:
    return
  await update.reply('Select the options below', True, reply_markup=InlineKeyboardMarkup(DL_BUTTONS))

# Callbacks
@xbot.on_callback_query()
async def _callbacks(bot, cb: CallbackQuery):
  if cb.data == 'nowm':
    dirs = downloads.format(uuid.uuid4().hex)
    os.makedirs(dirs)
    cbb = cb
    update = cbb.message.reply_to_message
    await cb.message.delete()
    url = update.text
    session = requests.Session()
    resp = session.head(url, allow_redirects=True)
    if '?' in resp.url:
      tt = resp.url.split('?', 1)[0]
    else:
      tt = resp.url
    ttid = dirs+tt.split('/')[-1]
    r = requests.get('https://api.reiyuura.me/api/dl/tiktok?url='+tt)
    result = r.text
    rs = json.loads(result)
    link = rs['result']['nowm']
    resp = session.head(link, allow_redirects=True)
    r = requests.get(resp.url, allow_redirects=True)
    open(f'{ttid}.mp4', 'wb').write(r.content)
    await bot.send_video(update.chat.id, f'{ttid}.mp4',)
    shutil.rmtree(dirs)
  elif cb.data == 'wm':
    dirs = downloads.format(uuid.uuid4().hex)
    os.makedirs(dirs)
    cbb = cb
    update = cbb.message.reply_to_message
    await cb.message.delete()
    url = update.text
    session = requests.Session()
    resp = session.head(url, allow_redirects=True)
    if '?' in resp.url:
      tt = resp.url.split('?', 1)[0]
    else:
      tt = resp.url
    ttid = dirs+tt.split('/')[-1]
    r = requests.get('https://api.reiyuura.me/api/dl/tiktok?url='+tt)
    result = r.text
    rs = json.loads(result)
    link = rs['result']['wm']
    resp = session.head(link, allow_redirects=True)
    r = requests.get(resp.url, allow_redirects=True)
    open(f'{ttid}.mp4', 'wb').write(r.content)
    await bot.send_video(update.chat.id, f'{ttid}.mp4',)
    shutil.rmtree(dirs)
  elif cb.data == 'audio':
    dirs = downloads.format(uuid.uuid4().hex)
    os.makedirs(dirs)
    cbb = cb
    update = cbb.message.reply_to_message
    await cb.message.delete()
    url = update.text
    session = requests.Session()
    resp = session.head(url, allow_redirects=True)
    if '?' in resp.url:
      tt = resp.url.split('?', 1)[0]
    else:
      tt = resp.url
    ttid = dirs+tt.split('/')[-1]
    r = requests.get('https://api.reiyuura.me/api/dl/tiktok?url='+tt)
    result = r.text
    rs = json.loads(result)
    link = rs['result']['wm']
    resp = session.head(link, allow_redirects=True)
    r = requests.get(resp.url, allow_redirects=True)
    open(f'{ttid}.mp4', 'wb').write(r.content)
    cmd = f'ffmpeg -i "{ttid}.mp4" -vn -ar 44100 -ac 2 -ab 192 -f mp3 "{ttid}.mp3"'
    await run_cmd(cmd)
    await bot.send_audio(update.chat.id, f'{ttid}.mp3',)
    shutil.rmtree(dirs)

xbot.run()

[((887, 960), 'pyrogram.Client', 'Client', (['"""TikTokDL"""'], {'api_id': 'APP_ID', 'api_hash': 'API_HASH', 'bot_token': 'BOT_TOKEN'}), "('TikTokDL', api_id=APP_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)\n", (893, 960), False, 'from pyrogram import Client, filters\n'), ((1067, 1083), 'shlex.split', 'shlex.split', (['cmd'], {}), '(cmd)\n', (1078, 1083), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((1852, 1870), 'requests.Session', 'requests.Session', ([], {}), '()\n', (1868, 1870), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((402, 474), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""Source"""'], {'url': '"""https://github.com/X-Gorn/TikTokDL"""'}), "('Source', url='https://github.com/X-Gorn/TikTokDL')\n", (422, 474), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((485, 554), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""Project Channel"""'], {'url': '"""https://t.me/xTeamBots"""'}), "('Project Channel', url='https://t.me/xTeamBots')\n", (505, 554), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((570, 626), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""Author"""'], {'url': '"""https://t.me/xgorn"""'}), "('Author', url='https://t.me/xgorn')\n", (590, 626), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((664, 722), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""No Watermark"""'], {'callback_data': '"""nowm"""'}), "('No Watermark', callback_data='nowm')\n", (684, 722), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((733, 786), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""Watermark"""'], {'callback_data': '"""wm"""'}), "('Watermark', callback_data='wm')\n", (753, 786), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((802, 854), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (['"""Audio"""'], {'callback_data': '"""audio"""'}), "('Audio', callback_data='audio')\n", (822, 854), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((1103, 1208), 'asyncio.create_subprocess_exec', 'asyncio.create_subprocess_exec', (['*args'], {'stdout': 'asyncio.subprocess.PIPE', 'stderr': 'asyncio.subprocess.PIPE'}), '(*args, stdout=asyncio.subprocess.PIPE,\n    stderr=asyncio.subprocess.PIPE)\n', (1133, 1208), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((1458, 1482), 'pyrogram.filters.command', 'filters.command', (['"""start"""'], {}), "('start')\n", (1473, 1482), False, 'from pyrogram import Client, filters\n'), ((1732, 1765), 'pyrogram.filters.regex', 'filters.regex', ([], {'pattern': '""".*http.*"""'}), "(pattern='.*http.*')\n", (1745, 1765), False, 'from pyrogram import Client, filters\n'), ((2238, 2255), 'os.makedirs', 'os.makedirs', (['dirs'], {}), '(dirs)\n', (2249, 2255), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((2382, 2400), 'requests.Session', 'requests.Session', ([], {}), '()\n', (2398, 2400), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((2592, 2655), 'requests.get', 'requests.get', (["('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)"], {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)\n", (2604, 2655), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((2685, 2703), 'json.loads', 'json.loads', (['result'], {}), '(result)\n', (2695, 2703), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((2799, 2843), 'requests.get', 'requests.get', (['resp.url'], {'allow_redirects': '(True)'}), '(resp.url, allow_redirects=True)\n', (2811, 2843), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((2955, 2974), 'shutil.rmtree', 'shutil.rmtree', (['dirs'], {}), '(dirs)\n', (2968, 2974), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3052, 3069), 'os.makedirs', 'os.makedirs', (['dirs'], {}), '(dirs)\n', (3063, 3069), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3196, 3214), 'requests.Session', 'requests.Session', ([], {}), '()\n', (3212, 3214), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3406, 3469), 'requests.get', 'requests.get', (["('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)"], {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)\n", (3418, 3469), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3499, 3517), 'json.loads', 'json.loads', (['result'], {}), '(result)\n', (3509, 3517), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3611, 3655), 'requests.get', 'requests.get', (['resp.url'], {'allow_redirects': '(True)'}), '(resp.url, allow_redirects=True)\n', (3623, 3655), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3767, 3786), 'shutil.rmtree', 'shutil.rmtree', (['dirs'], {}), '(dirs)\n', (3780, 3786), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((1650, 1685), 'pyrogram.types.InlineKeyboardMarkup', 'InlineKeyboardMarkup', (['START_BUTTONS'], {}), '(START_BUTTONS)\n', (1670, 1685), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((2038, 2070), 'pyrogram.types.InlineKeyboardMarkup', 'InlineKeyboardMarkup', (['DL_BUTTONS'], {}), '(DL_BUTTONS)\n', (2058, 2070), False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((2215, 2227), 'uuid.uuid4', 'uuid.uuid4', ([], {}), '()\n', (2225, 2227), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3867, 3884), 'os.makedirs', 'os.makedirs', (['dirs'], {}), '(dirs)\n', (3878, 3884), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((4011, 4029), 'requests.Session', 'requests.Session', ([], {}), '()\n', (4027, 4029), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((4221, 4284), 'requests.get', 'requests.get', (["('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)"], {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)\n", (4233, 4284), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((4314, 4332), 'json.loads', 'json.loads', (['result'], {}), '(result)\n', (4324, 4332), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((4426, 4470), 'requests.get', 'requests.get', (['resp.url'], {'allow_redirects': '(True)'}), '(resp.url, allow_redirects=True)\n', (4438, 4470), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((4691, 4710), 'shutil.rmtree', 'shutil.rmtree', (['dirs'], {}), '(dirs)\n', (4704, 4710), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3029, 3041), 'uuid.uuid4', 'uuid.uuid4', ([], {}), '()\n', (3039, 3041), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((3844, 3856), 'uuid.uuid4', 'uuid.uuid4', ([], {}), '()\n', (3854, 3856), False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n')]