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()

[((31, 7, 31, 80), 'pyrogram.Client', 'Client', (), '', False, 'from pyrogram import Client, filters\n'), ((37, 9, 37, 25), 'shlex.split', 'shlex.split', ({(37, 21, 37, 24): 'cmd'}, {}), '(cmd)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((58, 12, 58, 30), 'requests.Session', 'requests.Session', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((15, 8, 15, 80), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((16, 8, 16, 77), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((18, 5, 18, 61), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((23, 8, 23, 66), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((24, 8, 24, 61), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((26, 5, 26, 57), 'pyrogram.types.InlineKeyboardButton', 'InlineKeyboardButton', (), '', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((38, 18, 40, 3), 'asyncio.create_subprocess_exec', 'asyncio.create_subprocess_exec', (), '', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((50, 17, 50, 41), 'pyrogram.filters.command', 'filters.command', ({(50, 33, 50, 40): '"""start"""'}, {}), "('start')", False, 'from pyrogram import Client, filters\n'), ((55, 17, 55, 50), 'pyrogram.filters.regex', 'filters.regex', (), '', False, 'from pyrogram import Client, filters\n'), ((69, 4, 69, 21), 'os.makedirs', 'os.makedirs', ({(69, 16, 69, 20): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((74, 14, 74, 32), 'requests.Session', 'requests.Session', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((81, 8, 81, 69), 'requests.get', 'requests.get', ({(81, 21, 81, 68): "'https://api.reiyuura.me/api/dl/tiktok?url=' + tt"}, {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)", False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((83, 9, 83, 27), 'json.loads', 'json.loads', ({(83, 20, 83, 26): 'result'}, {}), '(result)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((86, 8, 86, 52), 'requests.get', 'requests.get', (), '', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((89, 4, 89, 23), 'shutil.rmtree', 'shutil.rmtree', ({(89, 18, 89, 22): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((92, 4, 92, 21), 'os.makedirs', 'os.makedirs', ({(92, 16, 92, 20): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((97, 14, 97, 32), 'requests.Session', 'requests.Session', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((104, 8, 104, 69), 'requests.get', 'requests.get', ({(104, 21, 104, 68): "'https://api.reiyuura.me/api/dl/tiktok?url=' + tt"}, {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)", False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((106, 9, 106, 27), 'json.loads', 'json.loads', ({(106, 20, 106, 26): 'result'}, {}), '(result)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((109, 8, 109, 52), 'requests.get', 'requests.get', (), '', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((112, 4, 112, 23), 'shutil.rmtree', 'shutil.rmtree', ({(112, 18, 112, 22): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((52, 115, 52, 150), 'pyrogram.types.InlineKeyboardMarkup', 'InlineKeyboardMarkup', ({(52, 136, 52, 149): 'START_BUTTONS'}, {}), '(START_BUTTONS)', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((62, 68, 62, 100), 'pyrogram.types.InlineKeyboardMarkup', 'InlineKeyboardMarkup', ({(62, 89, 62, 99): 'DL_BUTTONS'}, {}), '(DL_BUTTONS)', False, 'from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery\n'), ((68, 28, 68, 40), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((115, 4, 115, 21), 'os.makedirs', 'os.makedirs', ({(115, 16, 115, 20): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((120, 14, 120, 32), 'requests.Session', 'requests.Session', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((127, 8, 127, 69), 'requests.get', 'requests.get', ({(127, 21, 127, 68): "'https://api.reiyuura.me/api/dl/tiktok?url=' + tt"}, {}), "('https://api.reiyuura.me/api/dl/tiktok?url=' + tt)", False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((129, 9, 129, 27), 'json.loads', 'json.loads', ({(129, 20, 129, 26): 'result'}, {}), '(result)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((132, 8, 132, 52), 'requests.get', 'requests.get', (), '', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((137, 4, 137, 23), 'shutil.rmtree', 'shutil.rmtree', ({(137, 18, 137, 22): 'dirs'}, {}), '(dirs)', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((91, 28, 91, 40), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n'), ((114, 28, 114, 40), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import json, requests, os, shlex, asyncio, uuid, shutil\n')]