async def copy_via_rclone(src: str, remote_name: str, remote_dir: str, conf_file: str): if os.path.isdir(src): remote_dir = f"{remote_dir}/{src}" command_to_exec = [ "rclone", "move", src, f"{remote_name}:{remote_dir}", f"--config={conf_file}", "--fast-list", "--transfers", "18", "--checkers", "10", "--drive-chunk-size", "64M", ] LOGGER(__name__).info(command_to_exec) t_response, e_response = await run_command(command_to_exec) # Wait for the subprocess to finish LOGGER(__name__).info(e_response) LOGGER(__name__).info(t_response) # https://github.com/rg3/youtube-dl/issues/2630#issuecomment-38635239 remote_file_link = await r_clone_extract_link_s( re.escape(src), remote_name, remote_dir, conf_file ) LOGGER(__name__).info(remote_file_link) return remote_file_link
async def incoming_youtube_dl_f(client, message): """/ytdl command""" i_m_sefg = await message.reply_text("processing", quote=True) # LOGGER.info(message) if not message.reply_to_message: await i_m_sefg.edit_text( "No ytdl links to download\n" f"Reply <code>/{Command.YTDL}</code> to a ytdl link") return # extract link from message dl_url, cf_name, yt_dl_user_name, yt_dl_pass_word = await extract_link( message.reply_to_message, "YTDL") LOGGER(__name__).info(f"extracted /ytdl links {dl_url}") # LOGGER.info(cf_name) if dl_url is not None: current_user_id = message.from_user.id # create an unique directory user_working_dir = os.path.join( Config.DOWNLOAD_LOCATION, str(current_user_id), str(message.reply_to_message.message_id), ) # create download directory, if not exist if not os.path.isdir(user_working_dir): os.makedirs(user_working_dir) LOGGER(__name__).info("fetching youtube_dl formats") # list the formats, and display in button markup formats thumb_image, text_message, reply_markup = await extract_youtube_dl_formats( dl_url, # cf_name, yt_dl_user_name, yt_dl_pass_word, user_working_dir, ) if thumb_image is not None: thumb_image = await fetch_thumbnail(thumb_image, user_working_dir) await message.reply_photo( photo=thumb_image, quote=True, caption=text_message, reply_to_message_id=message.reply_to_message.message_id, reply_markup=reply_markup, ) os.remove(thumb_image) await i_m_sefg.delete() else: await i_m_sefg.edit_text(text=text_message, reply_markup=reply_markup)
async def r_clone_extract_link_s( src_file_name: str, remote_name: str, remote_dir: str, conf_file: str ): # TODO: Need to fix file linking for individual files command_to_exec = [ "rclone", "link", f"{remote_name}:{remote_dir}", f"--config={conf_file}", ] LOGGER(__name__).info(command_to_exec) t_response, e_response = await run_command(command_to_exec) # Wait for the subprocess to finish LOGGER(__name__).info(e_response) LOGGER(__name__).info(t_response) return t_response
async def cancel_message_f(_, message): if len(message.command) > 1: # /cancel command i_m_s_e_g = await message.reply_text(String.PROCESSING, quote=True) g_id = message.command[1].strip() LOGGER(__name__).info(g_id) try: downloads = aria2.get_download(g_id) LOGGER(__name__).info(downloads) LOGGER(__name__).info(downloads.remove(force=True, files=True)) await i_m_s_e_g.edit_text(String.TOR_CANCELLED) except Exception as e: LOGGER(__name__).info(str(e)) await i_m_s_e_g.edit_text(String.TOR_CANCEL_FAILED) else: await message.delete()
async def leech_commandi_f(client, message): m_ = await message.reply_text("checking", quote=True) m_sgra = " ".join(message.command[1:]) if not message.reply_to_message: await m_.edit_text("No URIs to download\n" f"Reply <code>/{Command.LEECH}</code> to an URI") return # get link from the incoming message dl_url, cf_name, _, _ = await extract_link(message.reply_to_message, "LEECH") LOGGER(__name__).info(f"extracted /leech links {dl_url}") # LOGGER.info(cf_name) if dl_url is not None: current_user_id = message.reply_to_message.from_user.id # create an unique directory new_download_location = os.path.join( Config.DOWNLOAD_LOCATION, str(current_user_id), str(message.reply_to_message.message_id), ) # create download directory, if not exist if not os.path.isdir(new_download_location): os.makedirs(new_download_location) if "_" in m_sgra: LOGGER(__name__).info("rclone upload mode") # try to download the "link" sagtus, err_message = await fake_etairporpa_call( aria2, dl_url, new_download_location, m_, int(m_sgra.split("_")[2]) # maybe IndexError / ValueError might occur, # we don't know, yet!! ) else: is_zip = False if "a" in m_sgra: is_zip = True LOGGER(__name__).info("tg upload mode") # try to download the "link" sagtus, err_message = await call_apropriate_function( aria2, dl_url, new_download_location, m_, is_zip) if not sagtus: # if FAILED, display the error message await m_.edit_text(err_message)
async def fake_etairporpa_call( aria_instance, incoming_link, c_file_name, sent_message_to_update_tg_p, r_clone_header_xedni, ): # TODO: duplicate code -_- if incoming_link.lower().startswith("magnet:"): sagtus, err_message = add_magnet(aria_instance, incoming_link, c_file_name) elif os.path.isfile(incoming_link) and incoming_link.lower().endswith( ".torrent"): sagtus, err_message = add_torrent(aria_instance, incoming_link) else: sagtus, err_message = add_url(aria_instance, incoming_link, c_file_name) if not sagtus: return sagtus, err_message LOGGER(__name__).info(err_message) # https://stackoverflow.com/a/58213653/4723940 await check_progress_for_dl(aria_instance, err_message, sent_message_to_update_tg_p, None) has_metadata = aria_instance.client.tell_status(err_message, ["followedBy"]) if has_metadata: err_message = has_metadata["followedBy"][0] await check_progress_for_dl(aria_instance, err_message, sent_message_to_update_tg_p, None) await asyncio.sleep(1) file = aria_instance.get_download(err_message) to_upload_file = file.name # -_- r_clone_conf_file = await get_r_clone_config( Config.RCLONE_CONF_URI, sent_message_to_update_tg_p._client) if r_clone_conf_file is not None: # how? even :\ config = configparser.ConfigParser() config.read(r_clone_conf_file) remote_names = config.sections() try: required_remote = remote_names[r_clone_header_xedni] except IndexError: return False, "maybe a bug, but index seems not valid" remote_file_link = await copy_via_rclone( to_upload_file, required_remote, Config.RCLONE_DEST, # rclone destination folder r_clone_conf_file, ) await sent_message_to_update_tg_p.reply_text( "files might be uploaded in the desired remote " "please check Logs for any errors" f"\n\n{remote_file_link}") return True, None
async def leech_btn_k(message: Message, cb_data: str): # get link from the incoming message dl_url, cf_name, _, _ = await extract_link(message.reply_to_message, "LEECH") LOGGER(__name__).info(f"extracted /leech links {dl_url}") # LOGGER.info(cf_name) current_user_id = message.reply_to_message.from_user.id # create an unique directory new_download_location = os.path.join( Config.DOWNLOAD_LOCATION, str(current_user_id), str(message.reply_to_message.message_id), ) # create download directory, if not exist if not os.path.isdir(new_download_location): os.makedirs(new_download_location) if dl_url is not None: if "_" in cb_data: LOGGER(__name__).info("rclone upload mode") # try to download the "link" sagtus, err_message = await fake_etairporpa_call( aria2, dl_url, new_download_location, message, int(cb_data.split("_")[2]) # maybe IndexError / ValueError might occur, # we don't know, yet!! ) else: is_zip = False if "a" in cb_data: is_zip = True LOGGER(__name__).info("tg upload mode") # try to download the "link" sagtus, err_message = await call_apropriate_function( aria2, dl_url, new_download_location, message, is_zip ) if not sagtus: # if FAILED, display the error message await message.edit_text(err_message)
async def create_archive(input_path): base_dir_name = PurePath(input_path).name[-249:] # nothing just 256 - 7 (.tar.gz), btw caption limit is 1024 compressed_file_name = f"{base_dir_name}.tar.gz" # fix for https://t.me/c/1434259219/13344 cmd_create_archive = [ "tar", "-zcvf", compressed_file_name, f"{input_path}", ] LOGGER(__name__).info(cmd_create_archive) _, error = await run_command(cmd_create_archive) if error: LOGGER(__name__).info(error) # Wait for the subprocess to finish _path = Path(input_path) if _path.is_dir(): shutil.rmtree(_path) elif _path.is_file(): _path.unlink() return compressed_file_name if Path( compressed_file_name).exists() else None
async def get_r_clone_config(message_link: str, py_client: Client) -> Optional[str]: config_path = os.path.join(os.getcwd(), ".config", "rclone", "rclone.conf") if os.path.exists(config_path): return config_path splited_uri = message_link.split("/") chat_id, message_id = None, None if len(splited_uri) == 6 and splited_uri[3] == "c": chat_id, message_id = int(splited_uri[4]), int(splited_uri[5]) try: conf_mesg = await py_client.get_messages( chat_id=chat_id, message_ids=message_id ) except ChannelInvalid: LOGGER(__name__).info("invalid RClone config URL. this is NOT an ERROR") return None return await py_client.download_media(message=conf_mesg, file_name=config_path)
async def upload_document_f(_, message): imsegd = await message.reply_text(String.PROCESSING) if " " not in message.text: await imsegd.edit_text( f"<code>/{Command.UPLOAD}</code> <i>File/Directory path to upload</i>" ) return else: _, local_file_name = message.text.split(" ", 1) if not os.path.exists(local_file_name): await imsegd.edit_text( f"Unable to find the path; <i>{local_file_name}</i>") return else: recvd_response = await upload_to_tg(imsegd, local_file_name, message.from_user.id, {}) LOGGER(__name__).info(recvd_response) await imsegd.edit_text( f"<a href='tg://user?id={message.from_user.id}'>Upload completed</a>" )
async def button(bot, update: CallbackQuery): LOGGER(__name__).info(update) if not update.message.reply_to_message: await update.answer(text=String.TGD_YTLD_STOOPID_DRUSER, show_alert=True) return if update.from_user.id != update.message.reply_to_message.from_user.id: return await update.answer() cb_data = update.data if cb_data.startswith("leech"): await leech_btn_k(update.message, cb_data) elif cb_data.startswith("ytdl"): await ytdl_btn_k(update.message) elif "|" in cb_data: await youtube_dl_call_back(bot, update)
async def stop(self, *args): await super().stop() shutil.rmtree(DOWNLOAD_LOCATION, ignore_errors=True) LOGGER(__name__).info("PublicLeechGroup stopped. Bye.")
async def upload_single_file(message, local_file_path, caption_str, from_user, edit_media): await asyncio.sleep(Config.EDIT_SLEEP_TIME_OUT) start_time = time.time() # thumbnail_location = os.path.join(Config.DOWNLOAD_LOCATION, "thumbnails", str(from_user) + ".jpg") LOGGER(__name__).info(thumbnail_location) # message_for_progress_display = message file_name = os.path.basename(local_file_path) if not edit_media: message_for_progress_display = await message.reply_text( f"starting upload of {file_name}") thumb_image_path = None file_type = magic.from_file(local_file_path, mime=True) if file_type.startswith("video/"): metadata = extractMetadata(createParser(local_file_path)) duration = 0 if metadata.has("duration"): duration = metadata.get("duration").seconds # width = 0 height = 0 if os.path.exists(thumbnail_location): thumb_image_path = await copy_file( thumbnail_location, os.path.dirname(os.path.abspath(local_file_path))) else: thumb_image_path = await take_screen_shot( local_file_path, os.path.dirname(os.path.abspath(local_file_path)), (duration / 2), ) # get the correct width, height, and duration for videos greater than 10MB if os.path.exists(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") # resize image # ref: https://t.me/PyrogramChat/44663 # https://stackoverflow.com/a/21669827/4723940 Image.open(thumb_image_path).convert("RGB").save( thumb_image_path) img = Image.open(thumb_image_path) # https://stackoverflow.com/a/37631799/4723940 img.resize((320, height)) img.save(thumb_image_path, "JPEG") # https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#create-thumbnails # thumb = None if thumb_image_path is not None and os.path.isfile(thumb_image_path): thumb = thumb_image_path # send video if edit_media and message.photo: sent_message = await message.edit_media(media=InputMediaVideo( media=local_file_path, thumb=thumb, caption=caption_str, parse_mode="html", width=width, height=height, duration=duration, supports_streaming=True, ) # quote=True, ) else: sent_message = await message.reply_video( video=local_file_path, # quote=True, caption=caption_str, parse_mode="html", duration=duration, width=width, height=height, thumb=thumb, supports_streaming=True, disable_notification=True, # reply_to_message_id=message.reply_to_message.message_id, progress=progress_for_pyrogram, progress_args=( file_name, message_for_progress_display, start_time, ), ) elif file_type.startswith("audio/"): metadata = extractMetadata(createParser(local_file_path)) duration = 0 title = "" artist = "" if metadata.has("duration"): duration = metadata.get("duration").seconds if metadata.has("title"): title = metadata.get("title") if metadata.has("artist"): artist = metadata.get("artist") if os.path.isfile(thumbnail_location): thumb_image_path = await copy_file( thumbnail_location, os.path.dirname(os.path.abspath(local_file_path))) thumb = None if thumb_image_path is not None and os.path.isfile(thumb_image_path): thumb = thumb_image_path # send audio if edit_media and message.photo: sent_message = await message.edit_media(media=InputMediaAudio( media=local_file_path, thumb=thumb, caption=caption_str, parse_mode="html", duration=duration, performer=artist, title=title, ) # quote=True, ) else: sent_message = await message.reply_audio( audio=local_file_path, # quote=True, caption=caption_str, parse_mode="html", duration=duration, performer=artist, title=title, thumb=thumb, disable_notification=True, # reply_to_message_id=message.reply_to_message.message_id, progress=progress_for_pyrogram, progress_args=( file_name, message_for_progress_display, start_time, ), ) else: if os.path.isfile(thumbnail_location): thumb_image_path = await copy_file( thumbnail_location, os.path.dirname(os.path.abspath(local_file_path))) # if a file, don't upload "thumb" # this "diff" is a major derp -_- ššš thumb = None if thumb_image_path is not None and os.path.isfile(thumb_image_path): thumb = thumb_image_path # # send document if edit_media and message.photo: sent_message = await message.edit_media(media=InputMediaDocument( media=local_file_path, thumb=thumb, caption=caption_str, parse_mode="html", ) # quote=True, ) else: sent_message = await message.reply_document( document=local_file_path, # quote=True, thumb=thumb, caption=caption_str, parse_mode="html", disable_notification=True, # reply_to_message_id=message.reply_to_message.message_id, progress=progress_for_pyrogram, progress_args=( file_name, message_for_progress_display, start_time, ), ) if thumb is not None: os.remove(thumb) if message.message_id != message_for_progress_display.message_id: await message_for_progress_display.delete() os.remove(local_file_path) return sent_message
async def split_large_files(input_file): file = Path(input_file) base_path = PurePath(file.resolve()) # create a new download directory temp_dir = PurePath(tempfile.mkdtemp(dir=base_path.parent)) file_type = magic.from_file(input_file, mime=True) if Config.SPLIT_ALGORITHM.lower() != "rar" and file_type.startswith( "video/"): # handle video / audio files here metadata = extractMetadata(createParser(input_file)) duration = metadata.get("duration").seconds if metadata.has( "duration") else 0 LOGGER(__name__).info(duration) # proprietary logic to get the seconds to trim (at) file_size = file.stat().st_size LOGGER(__name__).info(file_size) minimum_duration = (duration / file_size) * Config.MAX_SPLIT_SIZE # casting to int cuz float Time Stamp can cause errors minimum_duration = int(minimum_duration) LOGGER(__name__).info(minimum_duration) # END: proprietary start_time = 0 end_time = minimum_duration i = 0 flag = False while end_time <= duration: LOGGER(__name__).info(i) # file name generate parted_file_name = ( f"{str(base_path.stem)}_PART_{str(i).zfill(2)}{str(base_path.suffix)}" ) # [.stem] is for final path component without suffix # "Example.mp4" --> "Example_PART_00.mp4" output_path = temp_dir / parted_file_name cmd_split_video = [ "ffmpeg", "-i", input_file, "-ss", str(start_time), "-to", str(end_time), "-async", "1", "-strict", "-2", "-c", "copy", output_path, ] LOGGER(__name__).info(cmd_split_video) await run_command(cmd_split_video) LOGGER(__name__).info( f"Start time {start_time}, End time {end_time}, Itr {i}") # adding offset of 3 seconds to ensure smooth playback start_time = end_time - 3 end_time += minimum_duration i += 1 if (end_time > duration) and not flag: end_time = duration flag = True elif flag: break elif Config.SPLIT_ALGORITHM.lower() == "split": # handle normal files here output_path = temp_dir / f"{base_path.name}." cmd_create_split = [ "split", "--numeric-suffixes=1", "--suffix-length=3", f"--bytes={Config.MAX_SPLIT_SIZE}", input_file, output_path, ] LOGGER(__name__).info(cmd_create_split) await run_command(cmd_create_split) elif Config.SPLIT_ALGORITHM.lower() == "rar": output_path = temp_dir / base_path.stem cmd_create_rar = [ "rar", "a", f"-v{Config.MAX_SPLIT_SIZE}b", "-m0", output_path, input_file, ] LOGGER(__name__).info(cmd_create_rar) await run_command(cmd_create_rar) file.unlink() # Remove input_file return temp_dir
async def call_apropriate_function(aria_instance, incoming_link, c_file_name, sent_message_to_update_tg_p, is_zip): if incoming_link.lower().startswith("magnet:"): sagtus, err_message = add_magnet(aria_instance, incoming_link, c_file_name) elif os.path.isfile(incoming_link) and incoming_link.lower().endswith( ".torrent"): sagtus, err_message = add_torrent(aria_instance, incoming_link) else: sagtus, err_message = add_url(aria_instance, incoming_link, c_file_name) if not sagtus: return sagtus, err_message LOGGER(__name__).info(err_message) # https://stackoverflow.com/a/58213653/4723940 await check_progress_for_dl(aria_instance, err_message, sent_message_to_update_tg_p, None) has_metadata = aria_instance.client.tell_status(err_message, ["followedBy"]) if has_metadata: err_message = has_metadata["followedBy"][0] await check_progress_for_dl(aria_instance, err_message, sent_message_to_update_tg_p, None) await asyncio.sleep(1) file = aria_instance.get_download(err_message) to_upload_file = file.name """os.path.join( c_file_name, file.name )""" # if is_zip: # first check if current free space allows this # ref: https://github.com/out386/aria-telegram-mirror-bot/blob/master/src/download_tools/aria-tools.ts#L194 # archive the contents check_if_file = await create_archive(to_upload_file) if check_if_file is not None: to_upload_file = check_if_file # response = {} LOGGER(__name__).info(response) user_id = sent_message_to_update_tg_p.reply_to_message.from_user.id final_response = await upload_to_tg(sent_message_to_update_tg_p, to_upload_file, user_id, response) LOGGER(__name__).info(final_response) message_to_send = "" for key_f_res_se in final_response: local_file_name = key_f_res_se message_id = final_response[key_f_res_se] channel_id = str(sent_message_to_update_tg_p.chat.id)[4:] private_link = f"https://t.me/c/{channel_id}/{message_id}" message_to_send += "Ć°Åøāā° <a href='" message_to_send += private_link message_to_send += "'>" message_to_send += local_file_name message_to_send += "</a>" message_to_send += "\n" if message_to_send != "": mention_req_user = ( f"<a href='tg://user?id={user_id}'>Your Requested Files</a>\n\n") message_to_send = mention_req_user + message_to_send message_to_send = message_to_send + "\n\n" + "#uploads" else: message_to_send = "<i>FAILED</i> to upload files. Ć°ÅøĖÅ¾Ć°ÅøĖž" await sent_message_to_update_tg_p.reply_to_message.reply_text( text=message_to_send, quote=True, disable_web_page_preview=True) return True, None
async def upload_to_tg( message, local_file_name, from_user, dict_contatining_uploaded_files, edit_media=False, custom_caption=None, ): LOGGER(__name__).info(local_file_name) base_file_name = os.path.basename(local_file_name) caption_str = custom_caption if not caption_str or not edit_media: LOGGER(__name__).info("fall-back to default file_name") caption_str = "<code>" caption_str += base_file_name caption_str += "</code>" # caption_str += "\n\n" # caption_str += "<a href='tg://user?id=" # caption_str += str(from_user) # caption_str += "'>" # caption_str += "Here is the file to the link you sent" # caption_str += "</a>" if os.path.isdir(local_file_name): directory_contents = os.listdir(local_file_name) directory_contents.sort() # number_of_files = len(directory_contents) LOGGER(__name__).info(directory_contents) new_m_esg = message if not message.photo: new_m_esg = await message.reply_text( "Found {} files".format(len(directory_contents)), quote=True # reply_to_message_id=message.message_id ) for single_file in directory_contents: # recursion: will this FAIL somewhere? file_path = os.path.join(local_file_name, single_file) if not os.path.exists(file_path): continue await upload_to_tg( new_m_esg, file_path, from_user, dict_contatining_uploaded_files, edit_media, caption_str, ) elif os.path.getsize(local_file_name) > Config.MAX_FILE_SIZE: LOGGER(__name__).info("TODO") d_f_s = humanbytes(os.path.getsize(local_file_name)) i_m_s_g = await message.reply_text( "Telegram does not support uploading this file.\n" f"Detected File Size: {d_f_s} š”\n" "\nš¤ trying to split the files ššš") splitted_dir = await split_large_files(local_file_name) totlaa_sleif = os.listdir(splitted_dir) totlaa_sleif.sort() number_of_files = len(totlaa_sleif) LOGGER(__name__).info(totlaa_sleif) ba_se_file_name = os.path.basename(local_file_name) await i_m_s_g.edit_text( f"Detected File Size: {d_f_s} š”\n" f"<code>{ba_se_file_name}</code> splitted into {number_of_files} files.\n" "trying to upload to Telegram, now ...") for le_file in totlaa_sleif: # recursion: will this FAIL somewhere? file_path = os.path.join(splitted_dir, le_file) if not os.path.isfile(file_path): continue await upload_to_tg( message, file_path, from_user, dict_contatining_uploaded_files, ) else: sent_message = None if os.path.isfile(local_file_name): sent_message = await upload_single_file(message, local_file_name, caption_str, from_user, edit_media) if sent_message is not None: dict_contatining_uploaded_files[os.path.basename( local_file_name)] = sent_message.message_id # await message.delete() return dict_contatining_uploaded_files
async def check_progress_for_dl(aria2, gid, event, previous_message): try: file = aria2.get_download(gid) complete = file.is_complete if not complete: if not file.error_message: # sometimes, this weird https://t.me/c/1220993104/392975 # error creeps up # TODO: temporary workaround downloading_dir_name = "N/A" try: # another derp -_- # https://t.me/c/1220993104/423318 downloading_dir_name = str(file.name) except: pass # msg = f"\nFilename: <i>{downloading_dir_name}</i>" msg += (f"\nProgress: {file.progress_string()} of " f"<b>{file.total_length_string()}</b> at " f"{file.download_speed_string()}, " f"ETA: {file.eta_string()}") msg += f"\n<b>Info:</b> P: {file.connections}" if file.seeder is False: """https://t.me/c/1220993104/670177""" msg += f" || S: {file.num_seeders}" # msg += f"\nStatus: {file.status}" msg += f"\n<code>/cancel {gid}</code>" # LOGGER.info(msg) if msg != previous_message: await event.edit(msg) previous_message = msg else: msg = file.error_message await event.edit(f"<code>{msg}</code>") return False await asyncio.sleep(Config.EDIT_SLEEP_TIME_OUT) return await check_progress_for_dl(aria2, gid, event, previous_message) else: await event.edit( f"File Downloaded Successfully: <code>{file.name}</code>") return True except MessageNotModified: pass except FloodWait as e: await asyncio.sleep(e.x) except RecursionError: file.remove(force=True) await event.edit("Download Auto Canceled :\n\n" "Your Torrent/Link {} is Dead.".format(file.name)) return False except Exception as e: LOGGER(__name__).info(str(e)) if " not found" in str(e) or "'file'" in str(e): await event.edit("Download Canceled :\n<code>{}</code>".format( file.name)) else: LOGGER(__name__).info(str(e)) await event.edit( "<u>error</u> :\n<code>{}</code> \n\n#error".format(str(e))) return False
async def extract_link(message, type_o_request): custom_file_name = None url = None youtube_dl_username = None youtube_dl_password = None if message is None: url = None custom_file_name = None elif message.text is not None: if message.text.lower().startswith("magnet:"): url = message.text.strip() elif "|" in message.text: url_parts = message.text.split("|") if len(url_parts) == 2: url = url_parts[0] custom_file_name = url_parts[1] elif len(url_parts) == 4: url = url_parts[0] custom_file_name = url_parts[1] youtube_dl_username = url_parts[2] youtube_dl_password = url_parts[3] elif message.entities is not None: url = extract_url_from_entity(message.entities, message.text) else: url = message.text.strip() elif message.document is not None: if message.document.file_name.lower().endswith(".torrent"): url = await message.download() custom_file_name = message.caption elif message.caption is not None: if "|" in message.caption: url_parts = message.caption.split("|") if len(url_parts) == 2: url = url_parts[0] custom_file_name = url_parts[1] elif len(url_parts) == 4: url = url_parts[0] custom_file_name = url_parts[1] youtube_dl_username = url_parts[2] youtube_dl_password = url_parts[3] elif message.caption_entities is not None: url = extract_url_from_entity(message.caption_entities, message.caption) else: url = message.caption.strip() elif message.entities is not None: url = message.text # trim blank spaces from the URL # might have some issues with #45 if url is not None: url = url.strip() if custom_file_name is not None: custom_file_name = custom_file_name.strip() # https://stackoverflow.com/a/761825/4723940 if youtube_dl_username is not None: youtube_dl_username = youtube_dl_username.strip() if youtube_dl_password is not None: youtube_dl_password = youtube_dl_password.strip() # additional conditional check, # here to FILTER out BAD URLs LOGGER(__name__).info(Config.TG_OFFENSIVE_API) if Config.TG_OFFENSIVE_API is not None: try: async with aiohttp.ClientSession() as session: api_url = Config.TG_OFFENSIVE_API.format(i=url, m=custom_file_name, t=type_o_request) LOGGER(__name__).info(api_url) async with session.get(api_url) as resp: suats = int(resp.status) err = await resp.text() if suats != 200: url = None custom_file_name = err except: # this might occur in case of a BAD API URL, # who knows? :\ pass return url, custom_file_name, youtube_dl_username, youtube_dl_password
async def youtube_dl_call_back(bot, update): # LOGGER.info(update) cb_data = update.data # youtube_dl extractors tg_send_type, extractor_key, youtube_dl_format, av_codec = cb_data.split( "|") # current_user_id = update.message.reply_to_message.from_user.id current_message = update.message.reply_to_message current_message_id = current_message.message_id current_touched_user_id = update.from_user.id user_working_dir = os.path.join( Config.DOWNLOAD_LOCATION, str(current_user_id), str(update.message.reply_to_message.message_id), ) # create download directory, if not exist if not os.path.isdir(user_working_dir): await bot.delete_messages( chat_id=update.message.chat.id, message_ids=[ update.message.message_id, update.message.reply_to_message.message_id, ], revoke=True, ) return youtube_dl_url, cf_name, yt_dl_user_name, yt_dl_pass_word = await extract_link( current_message, "YTDL") LOGGER(__name__).info(youtube_dl_url) # custom_file_name = "%(title)s.%(ext)s" # Assign custom filename if specified if cf_name: custom_file_name = f"{cf_name}.%(ext)s" # https://superuser.com/a/994060 # LOGGER.info(custom_file_name) # await update.message.edit_caption(caption="trying to download") tmp_directory_for_each_user = user_working_dir download_directory = 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, # "max_filesize": Config.MAX_FILE_SIZE, } if yt_dl_user_name and yt_dl_pass_word: ytdl_opts.update({ "username": yt_dl_user_name, "password": yt_dl_pass_word, }) if extractor_key == "HotStar": ytdl_opts.update({ "geo_bypass_country": "IN", }) if tg_send_type == "audio": ytdl_opts.update({ "format": "bestaudio/best", "postprocessors": [ { "key": "FFmpegExtractAudio", "preferredcodec": av_codec, "preferredquality": youtube_dl_format, }, { "key": "FFmpegMetadata" }, ], }) elif tg_send_type == "video": # recreating commit 20b0ef4 in a confusing way final_format = youtube_dl_format # GDrive check, it doesn't accept "bestaudio" value # so its no need to append or do a condition check if extractor_key == "Youtube" and av_codec == "none": final_format = f"{youtube_dl_format}+bestaudio" ytdl_opts.update({ "format": final_format, "postprocessors": [{ "key": "FFmpegMetadata" }], }) elif tg_send_type == "generic": ytdl_opts.update({ "format": youtube_dl_format, }) start = datetime.now() try: info = await yt_extract_info( video_url=youtube_dl_url, download=True, ytdl_opts=ytdl_opts, ie_key=extractor_key, ) except yt_dlp.utils.DownloadError as ytdl_error: await update.message.edit_caption(caption=str(ytdl_error)) return False, None if info: end_one = datetime.now() time_taken_for_download = (end_one - start).seconds dir_contents = len(os.listdir(tmp_directory_for_each_user)) # dir_contents.sort() await update.message.edit_caption( caption= f"Download completed in {time_formatter(time_taken_for_download)}" f"\nfound {dir_contents} file(s)") user_id = update.from_user.id # final_response = await upload_to_tg( update.message, tmp_directory_for_each_user, user_id, {}, True, cf_name or info.get("title", ""), ) LOGGER(__name__).info(final_response) # try: shutil.rmtree(tmp_directory_for_each_user) except OSError: pass
# This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. import aria2p import asyncio import configparser import os from pyrogram.errors import (MessageNotModified, FloodWait) from publicleechgroup import (LOGGER) LOGGER = LOGGER(__name__) from publicleechgroup.helper_funcs.upload_to_tg import upload_to_tg from publicleechgroup.helper_funcs.create_compressed_archive import create_archive from publicleechgroup import (ARIA_TWO_STARTED_PORT, MAX_TIME_TO_WAIT_FOR_TORRENTS_TO_START, AUTH_CHANNEL, DOWNLOAD_LOCATION, EDIT_SLEEP_TIME_OUT, R_CLONE_CONF_URI, R_CLONE_DEST) from publicleechgroup.helper_funcs.r_clone import (get_r_clone_config, copy_via_rclone) async def aria_start(): aria2_daemon_start_cmd = [] # start the daemon, aria2c command
async def start(self): await super().start() usr_bot_me = await self.get_me() # create download directory, if not exist if not os.path.isdir(DOWNLOAD_LOCATION): os.makedirs(DOWNLOAD_LOCATION) LOGGER(__name__).info("@PublicLeechGroup, trying to add handlers") # PURGE command self.add_handler( MessageHandler(incoming_purge_message_f, filters=filters.command([Commandi.PURGE]) & filters.chat(chats=AUTH_CHANNEL))) # STATUS command self.add_handler( MessageHandler(status_message_f, filters=filters.command([Commandi.STATUS]) & filters.chat(chats=AUTH_CHANNEL))) # CANCEL command self.add_handler( MessageHandler(cancel_message_f, filters=filters.command([Commandi.CANCEL]) & filters.chat(chats=AUTH_CHANNEL))) if not SHOULD_USE_BUTTONS: LOGGER(__name__).info("using COMMANDi mode") # LEECH command self.add_handler( MessageHandler(leech_commandi_f, filters=filters.command([Commandi.LEECH]) & filters.chat(chats=AUTH_CHANNEL))) # YTDL command self.add_handler( MessageHandler(incoming_youtube_dl_f, filters=filters.command([Commandi.YTDL]) & filters.chat(chats=AUTH_CHANNEL))) else: LOGGER(__name__).info("using BUTTONS mode") # all messages filter # in the AUTH_CHANNELs self.add_handler( MessageHandler(incoming_message_f, filters=message_fliter & filters.chat(chats=AUTH_CHANNEL))) # button is LEGACY command to handle # the OLD YTDL buttons, # and also the new SUB buttons self.add_handler(CallbackQueryHandler(button)) if DIS_ABLE_ST_GFC_COMMAND_I: self.add_handler( MessageHandler(exec_message_f, filters=filters.command([Commandi.EXEC]) & filters.user(users=SUDO_USERS))) self.add_handler( MessageHandler(eval_message_f, filters=filters.command([Commandi.EVAL]) & filters.user(users=SUDO_USERS))) # MEMEs COMMANDs self.add_handler( MessageHandler(upload_document_f, filters=filters.command([Commandi.UPLOAD]) & filters.user(users=SUDO_USERS))) # HELP command self.add_handler( MessageHandler(help_message_f, filters=filters.command([Commandi.HELP]) & filters.chat(chats=AUTH_CHANNEL))) # not AUTH CHANNEL users self.add_handler( MessageHandler(new_join_f, filters=~filters.chat(chats=AUTH_CHANNEL))) # welcome MESSAGE self.add_handler( MessageHandler(help_message_f, filters=filters.chat(chats=AUTH_CHANNEL) & filters.new_chat_members)) # savethumbnail COMMAND self.add_handler( MessageHandler(save_thumb_nail, filters=filters.command([Commandi.SAVETHUMBNAIL]) & filters.chat(chats=AUTH_CHANNEL))) # clearthumbnail COMMAND self.add_handler( MessageHandler(clear_thumb_nail, filters=filters.command([Commandi.CLEARTHUMBNAIL]) & filters.chat(chats=AUTH_CHANNEL))) # an probably easy way to get RClone CONF URI self.add_handler( MessageHandler( save_rclone_conf_f, filters=filters.command([Commandi.GET_RCLONE_CONF_URI]) & filters.user(users=SUDO_USERS))) # Telegram command to upload LOG files self.add_handler( MessageHandler(upload_log_file, filters=filters.command([Commandi.UPLOAD_LOG_FILE]) & filters.user(users=SUDO_USERS))) LOGGER(__name__).info( f"@{usr_bot_me.username} based on Pyrogram v{__version__} ")