async def delete_thumbnail(_, message): custom_thumb_path = os.path.join(Config.WORK_DIR, str(message.from_user.id) + ".jpg") if os.path.isfile(custom_thumb_path): os.remove(custom_thumb_path) LOGGER.info("Custom thumbnail removed.") await message.reply_text(text=String.DELETED_CUSTOM_THUMB_NAIL, ) else: await message.reply_text(text=String.FAILED_DELETE_CUSTOM_THUMB_NAIL, )
async def save_photo(_, message): custom_thumb_path = os.path.join(Config.WORK_DIR, str(message.from_user.id) + ".jpg") await message.download(file_name=custom_thumb_path) if os.path.isfile(custom_thumb_path): LOGGER.info("Custom thumbnail saved.") resize_thumbnail(custom_thumb_path) await message.reply_text(text=String.SAVED_CUSTOM_THUMBNAIL, ) else: await message.reply_text(text=String.FAILED_SAVE_CUSTOM_THUMBNAIL, )
def screencapture(input_file, output_dir, seek_time): # https://stackoverflow.com/a/13891070/4723940 output_file = output_dir + "/" + str(time.time()) + ".jpg" try: (ffmpeg.input(input_file, ss=seek_time).output( output_file, vframes=1).overwrite_output().run(capture_stdout=True, capture_stderr=True)) except ffmpeg.Error as e: LOGGER.info(e.stderr.decode()) finally: return output_file or None
async def direct_downloader(url, file_name, message, start): async with aiohttp.ClientSession() as session: display_message = "" async with session.get(url, timeout=Config.PROCESS_MAX_TIMEOUT) as response: total_length = int(response.headers["Content-Length"]) content_type = response.headers["Content-Type"] if "text" in content_type and total_length < 500: return await response.release() await message.edit_text( text= f"Initiating Download \nURL: {url} \nFile Size: {humanbytes(total_length)}", ) with open(file_name, "wb") as f_handle: downloaded = 0 while True: chunk = await response.content.read(Config.CHUNK_SIZE) if not chunk: break f_handle.write(chunk) downloaded += Config.CHUNK_SIZE now = time.time() diff = now - start if round(diff % 10.00) == 0 or downloaded == total_length: elapsed_time = round(diff) if elapsed_time == 0: return speed = downloaded / elapsed_time time_to_completion = round( (total_length - downloaded) / speed) try: current_message = f"URL: {url}\n" current_message += ( f"Downloaded {humanbytes(downloaded)} of " f"{humanbytes(total_length)} at {humanbytes(speed)}\n" f"ETA: {time_formatter(time_to_completion)}\n") if current_message != display_message: await message.edit_text(text=current_message) display_message = current_message except FloodWait as e: await asyncio.sleep(e.x) except Exception as e: LOGGER.info(str(e)) return await response.release()
async def direct_downloader(url, file_name, message, start): async with session.get(url, timeout=Config.PROCESS_MAX_TIMEOUT) as response: display_message = "" total_length = int(response.headers["Content-Length"]) content_type = response.headers["Content-Type"] if "text" in content_type and total_length < 500: return await response.release() initialise_text = ("Initiating Download" f"\nURL: {url}" f"\nContent Type: {content_type}" f"\nFile Size: {humanbytes(total_length)}") await message.edit_text(text=initialise_text) async with aiofiles.open(file_name, "wb") as f_handle: downloaded = 0 async for chunk in response.content.iter_any(): await f_handle.write(chunk) downloaded += len(chunk) now = time.time() diff = now - start if round(diff % 10.00) == 0 or downloaded == total_length: elapsed_time = round(diff) if elapsed_time == 0: return speed = downloaded / elapsed_time time_to_completion = round( (total_length - downloaded) / speed) try: current_message = f"URL: {url}\n" current_message += ( f"Downloaded {humanbytes(downloaded)} of " f"{humanbytes(total_length)} at {humanbytes(speed)}\n" f"ETA: {time_formatter(time_to_completion)}\n") if current_message != display_message: await message.edit_text(text=current_message) display_message = current_message except MessageNotModified: pass except FloodWait as e: await asyncio.sleep(e.x) except Exception as e: LOGGER.info(str(e)) return await response.release()
async def direct_dl_callback(_, update): cb_data = update.data LOGGER.info(cb_data) # youtube_dl extractors send_as, _, __, ___ = cb_data.split("=") ( url, custom_file_name, _, _, ) = get_link(update.message.reply_to_message) if not custom_file_name: custom_file_name = os.path.basename(url) start_download = datetime.now() await update.message.edit_text(text=String.DOWNLOAD_START) tmp_directory_for_each_user = os.path.join( Config.WORK_DIR, str(update.from_user.id) ) if not os.path.isdir(tmp_directory_for_each_user): os.makedirs(tmp_directory_for_each_user) download_directory = os.path.join( mkdtemp(dir=tmp_directory_for_each_user), custom_file_name ) c_time = time.time() try: await direct_downloader( url, download_directory, update.message, c_time, ) except asyncio.TimeoutError: await update.message.edit_text(text=String.SLOW_URL_DECED) return False if os.path.exists(download_directory): end_download = datetime.now() downloaded_in = (end_download - start_download).seconds await update.message.edit_text( text=f"Download took {downloaded_in} seconds.\n" + String.UPLOAD_START ) try: upl = await upload_worker( update, custom_file_name, None, download_directory, downloaded_in ) LOGGER.info(upl) except: return False shutil.rmtree(download_directory, ignore_errors=True) LOGGER.info("Cleared temporary folder") # await update.message.delete() else: await update.message.edit_text( text=String.NO_VOID_FORMAT_FOUND.format("Incorrect Link"), )
async def sticker_downloader(_, message): """Copying @DownloadStickersBot""" LOGGER.info(message.from_user) sticker = message.sticker pack_name = sticker.set_name pack_link = f"http://t.me/addstickers/{pack_name}" if pack_name else "" sticker_ext = PurePath(message.sticker.file_name).suffix zipfile_name = f"{str(message.from_user.id)}_{pack_name}{sticker_ext}.zip" Path(Config.WORK_DIR).mkdir( exist_ok=True ) # Cause TemporaryDirectory failed to create parent directory with TemporaryDirectory(dir=Config.WORK_DIR) as tempdir: status = await message.reply_text( text=String.DOWNLOAD_START, reply_to_message_id=message.message_id ) try: download_to = await message.download( file_name=f"{tempdir}/", progress_args=String.DOWNLOAD_START ) except ValueError as e: await status.edit_text(text=str(e)) return False await status.edit_text( text=String.STICKER_INFO.format( sticker.set_name, sticker.emoji, sticker.file_id ) ) final_location = PurePath(download_to) LOGGER.info(final_location) # /app/DOWNLOADS/<tempdir>/sticker.webp zipfile_path = ( str(final_location.parent) + f"/{zipfile_name}" ) # /app/DOWNLOADS/<tempdir>/<zipfile_name> with ZipFile(zipfile_path, "w") as stickerZip: stickerZip.write(final_location, final_location.name) if sticker_ext == ".webp": png_location = Path(final_location.with_name(final_location.stem + ".png")) LOGGER.info(png_location) # /app/DOWNLOADS/<tempdir>/sticker.png # https://stackoverflow.com/a/21669827/4723940 Image.open(download_to).convert("RGB").save(png_location, "PNG") await status.reply_photo( photo=png_location, reply_to_message_id=status.message_id ) await status.reply_document( document=zipfile_path, caption=pack_link, reply_to_message_id=status.message_id, )
async def direct_dl_callback(bot, update): cb_data = update.data LOGGER.info(cb_data) # youtube_dl extractors send_as, _, __, ___ = cb_data.split("=") thumb_image_path = Config.WORK_DIR + "/" + str( update.from_user.id) + ".jpg" ( url, custom_file_name, _, _, ) = get_link(update.message.reply_to_message) if not custom_file_name: custom_file_name = os.path.basename(url) description = String.CUSTOM_CAPTION_UL_FILE start_download = datetime.now() await bot.edit_message_text( text=String.DOWNLOAD_START, chat_id=update.message.chat.id, message_id=update.message.message_id, ) tmp_directory_for_each_user = os.path.join(Config.WORK_DIR, str(update.from_user.id)) if not os.path.isdir(tmp_directory_for_each_user): os.makedirs(tmp_directory_for_each_user) download_directory = os.path.join(tmp_directory_for_each_user, custom_file_name) c_time = time.time() try: await direct_downloader( url, download_directory, update.message, c_time, ) except: return False if os.path.exists(download_directory): end_download = datetime.now() time_taken_for_download = (end_download - start_download).seconds await bot.edit_message_text( text=f"Download took {time_taken_for_download} seconds.\n" + String.UPLOAD_START, chat_id=update.message.chat.id, message_id=update.message.message_id, ) try: upl = await upload_worker(update, custom_file_name, send_as, False, download_directory) LOGGER.info(upl) except: return False try: os.remove(download_directory) os.remove(thumb_image_path) except: pass await update.message.delete() else: await bot.edit_message_text( text=String.NO_VOID_FORMAT_FOUND.format("Incorrect Link"), chat_id=update.message.chat.id, message_id=update.message.message_id, disable_web_page_preview=True, )
async def stop(self, *args): await super().stop() shutil.rmtree(Config.WORK_DIR, ignore_errors=True) LOGGER.info("AnyDLBot stopped. Bye.")
async def start(self): await super().start() bot = await self.get_me() LOGGER.info(f"AnyDLBot started on @{bot.username}")
async def echo(_, message): LOGGER.info(message.from_user) url, _, youtube_dl_username, youtube_dl_password = get_link(message) info_dict = {} if youtube_dl_username and youtube_dl_password: info_dict.update( { "username": youtube_dl_username, "password": youtube_dl_password, } ) if "hotstar" in url: info_dict.update( { "geo_bypass_country": "IN", } ) try: info = await yt_extract_info( video_url=url, download=False, ytdl_opts=info_dict, ie_key=None, ) except youtube_dl.utils.DownloadError as ytdl_error: await message.reply_text(text=str(ytdl_error), quote=True) return False if info: ikeyboard = InlineKeyboard() thumb_image = info.get("thumbnail", None) thumbnail = thumb_image or Config.DEFAULT_THUMBNAIL extractor_key = info.get("extractor_key", "Generic") duration = info.get("duration", None) if "formats" in info: for formats in info.get("formats"): format_id = formats.get("format_id") format_string = formats.get("format_note", None) if format_string is None: format_string = formats.get("format") # @SpEcHiDe/PublicLeech//helper_funcs/youtube_dl_extractor.py#L100 if "DASH" in format_string.upper(): continue format_ext = formats.get("ext") av_codec = "empty" if formats.get("acodec") == "none" or formats.get("vcodec") == "none": av_codec = "none" approx_file_size = ( humanbytes(formats.get("filesize")) if formats.get("filesize") else "" ) display_str = ( f"{format_string} [{format_ext.upper()}] {approx_file_size}" ) cb_string_video = f"video|{extractor_key}|{format_id}|{av_codec}" # GDrive gets special pass, acodec is not listed here, ie acodec=None if ( extractor_key == "GoogleDrive" and format_id == "source" or extractor_key != "GoogleDrive" and format_string and "audio only" not in format_string ): ikeyboard.row( InlineKeyboardButton(display_str, callback_data=cb_string_video) ) elif extractor_key != "GoogleDrive": # special weird case :\ ikeyboard.row( InlineKeyboardButton( f"Video {approx_file_size}", cb_string_video ), ) if duration: ikeyboard.row( InlineKeyboardButton( "MP3 (64 kbps)", callback_data=f"audio|{extractor_key}|64|mp3" ), InlineKeyboardButton( "MP3 (128 kbps)", callback_data=f"audio|{extractor_key}|128|mp3" ), ) ikeyboard.row( InlineKeyboardButton( "MP3 (320 kbps)", callback_data=f"audio|{extractor_key}|320|mp3" ) ) elif "entries" in info: for entries in info.get("entries"): for formats in entries.get("formats"): format_id = formats.get("format_id") format_ext = formats.get("ext") cb_string_file = f"file|{extractor_key}|{format_id}|{format_ext}" ikeyboard.row( InlineKeyboardButton( f"YTDL Generic File [{format_ext.upper()}]", callback_data=cb_string_file ), ) else: format_id = info.get("format_id") format_ext = info.get("ext") cb_string_file = f"file={extractor_key}={format_id}={format_ext}" ikeyboard.row( InlineKeyboardButton( f"File [{format_ext.upper()}]", callback_data=cb_string_file ), ) save_thumbnail = os.path.join( Config.WORK_DIR, str(message.from_user.id) + ".jpg" ) if not os.path.isdir(Config.WORK_DIR): os.makedirs(Config.WORK_DIR) if os.path.exists(save_thumbnail): thumb_image_path = save_thumbnail else: thumb_image_path = await get_thumbnail(thumbnail, save_thumbnail) await message.reply_photo( photo=thumb_image_path, quote=True, caption=String.FORMAT_SELECTION.format(thumbnail) + "\n" + String.SET_CUSTOM_USERNAME_PASSWORD, reply_markup=ikeyboard, parse_mode="html", ) else: # fallback for nonnumeric port a.k.a seedbox.io ikeyboard = InlineKeyboard() cb_string_file = "file=LFO=NONE=NONE" ikeyboard.row( InlineKeyboardButton("File", callback_data=cb_string_file), ) await message.reply_photo( photo=Config.DEFAULT_THUMBNAIL, quote=True, caption=String.FORMAT_SELECTION.format(""), reply_markup=ikeyboard, parse_mode="html", reply_to_message_id=message.message_id, )
async def upload_worker(update, filename, send_as, generatess, download_directory): tmp_directory_for_each_user = os.path.join( Config.WORK_DIR, str(update.from_user.id) ) thumb_image_path = os.path.join(Config.WORK_DIR, str(update.from_user.id) + ".jpg") download_directory_dirname = os.path.dirname(download_directory) download_directory_contents = os.listdir(download_directory_dirname) for download_directory_c in download_directory_contents: current_file_name = os.path.join( download_directory_dirname, download_directory_c ) file_size = os.stat(current_file_name).st_size if file_size > Config.TG_MAX_FILE_SIZE: await update.message.edit_caption( caption=String.RCHD_TG_API_LIMIT.format(humanbytes(file_size)) ) return # get the correct width, height, and duration # for videos greater than 10MB # ref: message from @BotSupport width = 0 height = 0 duration = 0 if send_as != "file": metadata = extractMetadata(createParser(current_file_name)) if metadata is not None and metadata.has("duration"): duration = metadata.get("duration").seconds # get the correct width, height, and duration # for videos greater than 10MB if os.path.exists(thumb_image_path): # https://stackoverflow.com/a/21669827/4723940 Image.open(thumb_image_path).convert("RGB").save(thumb_image_path) metadata = extractMetadata(createParser(thumb_image_path)) if metadata.has("width"): width = metadata.get("width") if metadata.has("height"): height = metadata.get("height") else: thumb_image_path = None start_upload = datetime.now() c_time = time.time() if send_as == "audio": await update.message.reply_audio( audio=current_file_name, caption=filename, parse_mode="HTML", duration=duration, # performer=response_json["uploader"], # title=response_json["title"], # reply_markup=reply_markup, thumb=thumb_image_path, progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) elif send_as == "file": await update.message.reply_document( document=current_file_name, thumb=thumb_image_path, caption=filename, parse_mode="HTML", # reply_markup=reply_markup, progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) elif send_as == "video": await update.message.reply_video( video=current_file_name, caption=filename, parse_mode="HTML", duration=duration, width=width, height=height, supports_streaming=True, # reply_markup=reply_markup, thumb=thumb_image_path, progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) else: LOGGER.info("Did this happen? :\\") end_upload = datetime.now() time_taken_for_upload = (end_upload - start_upload).seconds min_duration = 300 media_album_p = [] if generatess and duration > min_duration: images = generate_screenshots( current_file_name, tmp_directory_for_each_user, duration, 5 ) LOGGER.info(images) i = 0 caption = f"© @AnyDLBot - Uploaded in {time_taken_for_upload} seconds" for image in images: if os.path.exists(image): if i == 0: media_album_p.append( InputMediaPhoto( media=image, caption=caption, parse_mode="html" ) ) else: media_album_p.append(InputMediaPhoto(media=image)) i += 1 await update.message.reply_media_group( media=media_album_p, disable_notification=True ) # return True
async def youtube_dl_call_back(_, update): cb_data = update.data LOGGER.info(cb_data) # youtube_dl extractors send_as, extractor_key, format_id, av_codec = cb_data.split("|") thumb_image_path = os.path.join(Config.WORK_DIR, str(update.from_user.id) + ".jpg") ( youtube_dl_url, custom_file_name, youtube_dl_username, youtube_dl_password, ) = get_link(update.message.reply_to_message) if not custom_file_name: custom_file_name = "%(title)s.%(ext)s" await update.message.edit_caption(caption=String.DOWNLOAD_START) # description = Translation.CUSTOM_CAPTION_UL_FILE tmp_directory_for_each_user = os.path.join(Config.WORK_DIR, str(update.from_user.id)) if not os.path.isdir(tmp_directory_for_each_user): os.makedirs(tmp_directory_for_each_user) download_directory = os.path.join(tmp_directory_for_each_user, custom_file_name) ytdl_opts = { "outtmpl": download_directory, "ignoreerrors": True, "nooverwrites": True, "continuedl": True, "noplaylist": True, "restrictfilenames": True, "max_filesize": Config.TG_MAX_FILE_SIZE, } if youtube_dl_username and youtube_dl_password: ytdl_opts.update({ "username": youtube_dl_username, "password": youtube_dl_password, }) if extractor_key == "HotStar": ytdl_opts.update({ "geo_bypass_country": "IN", }) if send_as == "audio": ytdl_opts.update({ "format": "bestaudio/best", "postprocessors": [ { "key": "FFmpegExtractAudio", "preferredcodec": av_codec, "preferredquality": format_id, }, { "key": "FFmpegMetadata" }, ], }) elif send_as == "video": final_format = format_id if extractor_key == "Youtube" and av_codec == "none": final_format = f"{format_id}+bestaudio" ytdl_opts.update({ "format": final_format, "postprocessors": [{ "key": "FFmpegMetadata" }], }) elif send_as == "file": ytdl_opts.update({ "format": format_id, }) start_download = datetime.now() try: info = await yt_extract_info( video_url=youtube_dl_url, download=True, ytdl_opts=ytdl_opts, ie_key=extractor_key, ) except youtube_dl.utils.DownloadError as ytdl_error: await update.message.edit_caption(caption=str(ytdl_error)) return False if info: end_download = datetime.now() time_taken_for_download = (end_download - start_download).seconds await update.message.edit_caption( caption=f"Download took {time_taken_for_download} seconds.\n" + String.UPLOAD_START) upl = await upload_worker(update, info.get("title", ""), send_as, True, download_directory) LOGGER.info(upl) shutil.rmtree(tmp_directory_for_each_user, ignore_errors=True) LOGGER.info("Cleared temporary folder") os.remove(thumb_image_path) await update.message.delete()
async def upload_worker(update, filename, thumbnail, download_directory, downloaded_in): download_directory_dirname = os.path.dirname(download_directory) download_directory_contents = os.listdir(download_directory_dirname) LOGGER.info(download_directory_contents) for download_directory_c in download_directory_contents: current_file_name = os.path.join(download_directory_dirname, download_directory_c) file_size = os.stat(current_file_name).st_size if file_size > Config.TG_MAX_FILE_SIZE: await update.message.edit_text( text=String.RCHD_TG_API_LIMIT.format(humanbytes(file_size))) return custom_thumb_path = os.path.join(Config.WORK_DIR, str(update.from_user.id) + ".jpg") temp_thumb_dir = os.path.join(download_directory_dirname, "thumbnail.jpg") if os.path.isfile(custom_thumb_path): LOGGER.info("Custom thumbnail found. Using this now") thumb = custom_thumb_path else: thumb = (await get_thumbnail(thumbnail, temp_thumb_dir) if thumbnail else None) mime_type = magic.from_file(filename=current_file_name, mime=True) start_upload = datetime.now() c_time = time.time() width = height = duration = 0 if mime_type.startswith("audio"): duration = media_duration(current_file_name) await update.message.reply_audio( audio=current_file_name, caption=filename, parse_mode="HTML", duration=duration, thumb=thumb, progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) elif mime_type.startswith("video"): duration = media_duration(current_file_name) if thumb is None: thumb = screencapture(current_file_name, download_directory_dirname, duration // 2) LOGGER.info("Generating thumbnail of the video.") if os.path.isfile(thumb): width, height = width_and_height(thumb) await update.message.reply_video( video=current_file_name, caption=filename, parse_mode="HTML", duration=duration, width=width, height=height, supports_streaming=True, thumb=thumb, progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) else: await update.message.reply_document( document=current_file_name, thumb=thumb, caption=filename, parse_mode="HTML", progress=progress_for_pyrogram, progress_args=(String.UPLOAD_START, update.message, c_time), ) end_upload = datetime.now() uploaded_in = (end_upload - start_upload).seconds with TemporaryDirectory(prefix="screenshots", dir=download_directory_dirname) as tempdir: if mime_type.startswith( "video") and duration > Config.MIN_DURATION: media_album_p = generate_screenshots(current_file_name, tempdir, duration, 5) # LOGGER.info(media_album_p) try: await update.message.reply_media_group( media=media_album_p, disable_notification=True) except FloodWait as e: await asyncio.sleep(e.x) # first_name = f"{update.from_user.first_name}" user_link = f"tg://user?id={update.from_user.id}" await update.message.edit_text(text=String.FINAL_STATUS.format( user_link, first_name, downloaded_in, uploaded_in)) return True