diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 54f78a601cf..a4e4b3bcaa9 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: ['https://ko-fi.com/anasty17'] +custom: [ 'https://ko-fi.com/anasty17' ] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0d64d898cda..1ef85dcf1ff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,6 +12,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Used this Command with this link or file. 2. Before/after/while Upload .. 3. Check logs diff --git a/README.md b/README.md index 3d911631006..8cdd06581a1 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,27 @@ -This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/python-aria-mirror-bot), has undergone substantial modifications and is designed for efficiently mirroring or leeching files from the Internet to various destinations, including Google Drive, Telegram, or any rclone-supported cloud. It is built using asynchronous programming in Python. +This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/python-aria-mirror-bot), has undergone +substantial modifications and is designed for efficiently mirroring or leeching files from the Internet to various +destinations, including Google Drive, Telegram, or any rclone-supported cloud. It is built using asynchronous +programming in Python. # Features ## qBittorrent + - Select files from a Torrent before and during downloading (Requires Base URL) (task option) - Seed torrents to a specific ratio and time (task option) - Edit Global Options while the bot is running from bot settings (global option) ## Aria2c + - Select files from a Torrent before and during downloading (Requires Base URL) (task option) - Seed torrents to a specific ratio and time (task option) - Netrc support (global option) -- Direct link authentication for a specific link while using the bot (it will work even if only the username or password is provided) (task option) +- Direct link authentication for a specific link while using the bot (it will work even if only the username or password + is provided) (task option) - Edit Global Options while the bot is running from bot settings (global option) ## TG Upload/Download + - Split size (global, user, and task option) - Thumbnail (user and task option) - Leech filename prefix (user option) @@ -26,25 +33,31 @@ This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/p - Choose transfer by bot or user session in case you have a premium plan (global and user option) ## Google Drive + - Download/Upload/Clone/Delete/Count from/to Google Drive - Count Google Drive files/folders - Search in multiple Drive folder/TeamDrive - Use Token.pickle if the file is not found with a Service Account, for all Gdrive functions - Random Service Account for each task -- Recursive Search (only with `root` or TeamDrive ID, folder ids will be listed with a non-recursive method). Based on [Sreeraj](https://github.com/SVR666) searchX-bot. (task option) +- Recursive Search (only with `root` or TeamDrive ID, folder ids will be listed with a non-recursive method). Based + on [Sreeraj](https://github.com/SVR666) searchX-bot. (task option) - Stop Duplicates (global and user option) - Custom upload destination (global, user, and task option) -- Index link support only for [Bhadoo](https://gitlab.com/GoogleDriveIndex/Google-Drive-Index/-/blob/master/src/worker.js) +- Index link support only + for [Bhadoo](https://gitlab.com/GoogleDriveIndex/Google-Drive-Index/-/blob/master/src/worker.js) ## Status + - Download/Upload/Extract/Archive/Seed/Clone Status - Status Pages for an unlimited number of tasks, view a specific number of tasks in a message (global option) - Interval message update (global option) - Next/Previous buttons to get different pages (global and user option) -- Status buttons to get specific tasks for the chosen status regarding transfer type if the number of tasks is more than 30 (global and user option) +- Status buttons to get specific tasks for the chosen status regarding transfer type if the number of tasks is more than + 30 (global and user option) - Steps buttons for how much next/previous buttons should step backward/forward (global and user option) ## Yt-dlp + - Yt-dlp quality buttons (task option) - Ability to use a specific yt-dlp option (global, user, and task option) - Netrc support (global option) @@ -53,29 +66,38 @@ This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/p - All supported audio formats ## JDownloader + - Synchronize Settings (global option) - Wating to select (enable/disable files or change variants) before download start -- All settings can be edited from the remote access to your JDownloader with Web Interface, Android App, iPhone App or Browser Extensions. +- All settings can be edited from the remote access to your JDownloader with Web Interface, Android App, iPhone App or + Browser Extensions. ## Mongo Database + - Store bot settings - Store user settings including thumbnails and all private files - Store RSS data - Store incompleted task messages - Store JDownloader settings -- Store config.env file on first build and incase any change occured to it, then next build it will define variables from config.env instead of database +- Store config.env file on first build and incase any change occured to it, then next build it will define variables + from config.env instead of database ## Torrents Search + - Search on torrents with Torrent Search API - Search on torrents with variable plugins using qBittorrent search engine ## Archives + - Extract splits with or without password - Zip file/folder with or without password - Using 7-zip tool to extract with or without password all supported types: -> ZIP, RAR, TAR, 7z, ISO, WIM, CAB, GZIP, BZIP2, APM, ARJ, CHM, CPIO, CramFS, DEB, DMG, FAT, HFS, LZH, LZMA, LZMA2,MBR, MSI, MSLZ, NSIS, NTFS, RPM, SquashFS, UDF, VHD, XAR, Z, TAR.XZ + +> ZIP, RAR, TAR, 7z, ISO, WIM, CAB, GZIP, BZIP2, APM, ARJ, CHM, CPIO, CramFS, DEB, DMG, FAT, HFS, LZH, LZMA, LZMA2,MBR, +> MSI, MSLZ, NSIS, NTFS, RPM, SquashFS, UDF, VHD, XAR, Z, TAR.XZ ## RSS + - Based on this repository [rss-chan](https://github.com/hyPnOtICDo0g/rss-chan) - Rss feed (user option) - Title Filters (feed option) @@ -84,6 +106,7 @@ This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/p - All functions have been improved using buttons from one command. ## Rclone + - Rclone transfer (download/upload/clone-server-side) without or with random service accounts (global and user option) - Ability to choose config, remote and path from list with buttons (global, user and task option) - Ability to set rclone flags for each task or globally from config (global, user and task option) @@ -92,13 +115,15 @@ This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/p - Upload destination (global, user and task option) ## Overall + - Docker image support for linux `amd64, arm64/v8, arm/v7` - Edit variables and overwrite the private files while bot running (bot, user settings) - Update bot at startup and with restart command using `UPSTREAM_REPO` - Telegraph. Based on [Sreeraj](https://github.com/SVR666) loaderX-bot - Mirror/Leech/Watch/Clone/Count/Del by reply - Mirror/Leech/Clone multi links/files with one command -- Custom name for all links except torrents. For files you should add extension except yt-dlp links (global and user option) +- Custom name for all links except torrents. For files you should add extension except yt-dlp links (global and user + option) - Extensions Filter for the files to be uploaded/cloned (global and user option) - View Link button. Extra button to open index link in broswer instead of direct download for file - Queueing System for all tasks (global option) @@ -111,15 +136,22 @@ This Telegram Bot, based on [python-aria-mirror-bot](https://github.com/lzzy12/p - Shell and Executor - Add sudo users - Supported Direct links Generators: -> mediafire (file/folders), hxfile.co, streamtape.com, streamsb.net, streamhub.ink, streamvid.net, doodstream.com, feurl.com, upload.ee, pixeldrain.com, racaty.net, 1fichier.com, 1drv.ms (Only works for file not folder or business account), filelions.com, streamwish.com, send.cm (file/folders), solidfiles.com, linkbox.to (file/folders), shrdsk.me (sharedisk.io), akmfiles.com, wetransfer.com, pcloud.link, gofile.io (file/folders), easyupload.io, mdisk.me (with ytdl), tmpsend.com, terabox.com (file/folders) (you need to add cookies txt with name) [terabox.txt](https://github.com/ytdl-org/youtube-dl#how-do-i-pass-cookies-to-youtube-dl). +> mediafire (file/folders), hxfile.co, streamtape.com, streamsb.net, streamhub.ink, streamvid.net, doodstream.com, +> feurl.com, upload.ee, pixeldrain.com, racaty.net, 1fichier.com, 1drv.ms (Only works for file not folder or business +> account), filelions.com, streamwish.com, send.cm (file/folders), solidfiles.com, linkbox.to (file/folders), +> shrdsk.me ( +> sharedisk.io), akmfiles.com, wetransfer.com, pcloud.link, gofile.io (file/folders), easyupload.io, mdisk.me (with +> ytdl), +> tmpsend.com, terabox.com (file/folders) (you need to add cookies txt with +> name) [terabox.txt](https://github.com/ytdl-org/youtube-dl#how-do-i-pass-cookies-to-youtube-dl). # How to deploy? ## Prerequisites - Tutorial Video from A to Z: - - Thanks to [Wiszky](https://github.com/vishnoe115) + - Thanks to [Wiszky](https://github.com/vishnoe115)

@@ -165,73 +197,110 @@ cp config_sample.env config.env _____REMOVE_THIS_LINE_____=True ``` -Fill up rest of the fields. Meaning of each field is discussed below. **NOTE**: All values must be filled between quotes, even if it's `Int`, `Bool` or `List`. +Fill up rest of the fields. Meaning of each field is discussed below. **NOTE**: All values must be filled between +quotes, even if it's `Int`, `Bool` or `List`. **1. Required Fields** - `BOT_TOKEN`: The Telegram Bot Token that you got from [@BotFather](https://t.me/BotFather). `Str` - `OWNER_ID`: The Telegram User ID (not username) of the Owner of the bot. `Int` -- `TELEGRAM_API`: This is to authenticate your Telegram account for downloading Telegram files. You can get this from . `Int` -- `TELEGRAM_HASH`: This is to authenticate your Telegram account for downloading Telegram files. You can get this from . `Str` +- `TELEGRAM_API`: This is to authenticate your Telegram account for downloading Telegram files. You can get this + from . `Int` +- `TELEGRAM_HASH`: This is to authenticate your Telegram account for downloading Telegram files. You can get this + from . `Str` **2. Optional Fields** -- `USER_SESSION_STRING`: To download/upload from your telegram account if user is `PREMIUM` and to send rss. To generate session string use this command `python3 generate_string_session.py` after mounting repo folder for sure. `Str`. **NOTE**: You can't use bot with private message. Use it with superGroup. -- `DATABASE_URL`: Your Mongo Database URL (Connection string). Follow this [Generate Database](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#generate-database) to generate database. Data will be saved in Database: auth and sudo users, users settings including thumbnails for each user, rss data and incomplete tasks. **NOTE**: You can always edit all settings that saved in database from the official site -> (Browse collections). `Str` +- `USER_SESSION_STRING`: To download/upload from your telegram account if user is `PREMIUM` and to send rss. To generate + session string use this command `python3 generate_string_session.py` after mounting repo folder for sure. `Str`. * + *NOTE**: You can't use bot with private message. Use it with superGroup. +- `DATABASE_URL`: Your Mongo Database URL (Connection string). Follow + this [Generate Database](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#generate-database) to + generate database. Data will be saved in Database: auth and sudo users, users settings including thumbnails for each + user, rss data and incomplete tasks. **NOTE**: You can always edit all settings that saved in database from the + official site -> (Browse collections). `Str` - `DOWNLOAD_DIR`: The path to the local folder where the downloads should be downloaded to. `Str` - `CMD_SUFFIX`: commands index number. This number will added at the end all commands. `Str`|`Int` - `AUTHORIZED_CHATS`: Fill user_id and chat_id of groups/users you want to authorize. Separate them by space. `Int` - `SUDO_USERS`: Fill user_id of users whom you want to give sudo permission. Separate them by space. `Int` -- `DEFAULT_UPLOAD`: Whether `rc` to upload to `RCLONE_PATH` or `gd` to upload to `GDRIVE_ID`. Default is `gd`. Read More [HERE](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#upload).`Str` -- `STATUS_UPDATE_INTERVAL`: Time in seconds after which the progress/status message will be updated. Recommended `10` seconds at least. `Int` -- `STATUS_LIMIT`: Limit the no. of tasks shown in status message with buttons. Default is `10`. **NOTE**: Recommended limit is `4` tasks. `Int` +- `DEFAULT_UPLOAD`: Whether `rc` to upload to `RCLONE_PATH` or `gd` to upload to `GDRIVE_ID`. Default is `gd`. Read + More [HERE](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#upload).`Str` +- `STATUS_UPDATE_INTERVAL`: Time in seconds after which the progress/status message will be updated. Recommended `10` + seconds at least. `Int` +- `STATUS_LIMIT`: Limit the no. of tasks shown in status message with buttons. Default is `10`. **NOTE**: Recommended + limit is `4` tasks. `Int` - `EXTENSION_FILTER`: File extensions that won't upload/clone. Separate them by space. `Str` -- `INCOMPLETE_TASK_NOTIFIER`: Get incomplete task messages after restart. Require database and superGroup. Default is `False`. `Bool` -- `FILELION_API`: Filelion api key to mirror Filelion links. Get it from [Filelion](https://vidhide.com/?op=my_account). `str` -- `STREAMWISH_API`: Streamwish api key to mirror Streamwish links. Get it from [Streamwish](https://streamwish.com/?op=my_account). `str` -- `YT_DLP_OPTIONS`: Default yt-dlp options. Check all possible options [HERE](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L184) or use this [script](https://t.me/mltb_official_channel/177) to convert cli arguments to api options. Format: key:value|key:value|key:value. Add `^` before integer or float, some numbers must be numeric and some string. `str` - - Example: "format:bv*+mergeall[vcodec=none]|nocheckcertificate:True" -- `USE_SERVICE_ACCOUNTS`: Whether to use Service Accounts or not, with google-api-python-client. For this to work see [Using Service Accounts](https://github.com/anasty17/mirror-leech-telegram-bot#generate-service-accounts-what-is-service-account) section below. Default is `False`. `Bool` +- `INCOMPLETE_TASK_NOTIFIER`: Get incomplete task messages after restart. Require database and superGroup. Default + is `False`. `Bool` +- `FILELION_API`: Filelion api key to mirror Filelion links. Get it + from [Filelion](https://vidhide.com/?op=my_account). `str` +- `STREAMWISH_API`: Streamwish api key to mirror Streamwish links. Get it + from [Streamwish](https://streamwish.com/?op=my_account). `str` +- `YT_DLP_OPTIONS`: Default yt-dlp options. Check all possible + options [HERE](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L184) or use + this [script](https://t.me/mltb_official_channel/177) to convert cli arguments to api options. Format: key:value|key: + value|key:value. Add `^` before integer or float, some numbers must be numeric and some string. `str` + - Example: "format:bv*+mergeall[vcodec=none]|nocheckcertificate:True" +- `USE_SERVICE_ACCOUNTS`: Whether to use Service Accounts or not, with google-api-python-client. For this to work + see [Using Service Accounts](https://github.com/anasty17/mirror-leech-telegram-bot#generate-service-accounts-what-is-service-account) + section below. Default is `False`. `Bool` ### GDrive Tools -- `GDRIVE_ID`: This is the Folder/TeamDrive ID of the Google Drive OR `root` to which you want to upload all the mirrors using google-api-python-client. `Str` +- `GDRIVE_ID`: This is the Folder/TeamDrive ID of the Google Drive OR `root` to which you want to upload all the mirrors + using google-api-python-client. `Str` - `IS_TEAM_DRIVE`: Set `True` if uploading to TeamDrive using google-api-python-client. Default is `False`. `Bool` - `INDEX_URL`: Refer to . `Str` -- `STOP_DUPLICATE`: Bot will check file/folder name in Drive incase uploading to `GDRIVE_ID`. If it's present in Drive then downloading or cloning will be stopped. (**NOTE**: Item will be checked using name and not hash, so this feature is not perfect yet). Default is `False`. `Bool` +- `STOP_DUPLICATE`: Bot will check file/folder name in Drive incase uploading to `GDRIVE_ID`. If it's present in Drive + then downloading or cloning will be stopped. (**NOTE**: Item will be checked using name and not hash, so this feature + is not perfect yet). Default is `False`. `Bool` ### Rclone - `RCLONE_PATH`: Default rclone path to which you want to upload all the files/folders using rclone. `Str` - `RCLONE_FLAGS`: key:value|key|key|key:value . Check here all [RcloneFlags](https://rclone.org/flags/). `Str` -- `RCLONE_SERVE_URL`: Valid URL where the bot is deployed to use rclone serve. Format of URL should be `http://myip`, where `myip` is the IP/Domain(public) of your bot or if you have chosen port other than `80` so write it in this format `http://myip:port` (`http` and not `https`). `Str` +- `RCLONE_SERVE_URL`: Valid URL where the bot is deployed to use rclone serve. Format of URL should be `http://myip`, + where `myip` is the IP/Domain(public) of your bot or if you have chosen port other than `80` so write it in this + format `http://myip:port` (`http` and not `https`). `Str` - `RCLONE_SERVE_PORT`: Which is the **RCLONE_SERVE_URL** Port. Default is `8080`. `Int` - `RCLONE_SERVE_USER`: Username for rclone serve authentication. `Str` - `RCLONE_SERVE_PASS`: Password for rclone serve authentication. `Str` ### Update -- `UPSTREAM_REPO`: Your github repository link, if your repo is private add `https://username:{githubtoken}@github.com/{username}/{reponame}` format. Get token from [Github settings](https://github.com/settings/tokens). So you can update your bot from filled repository on each restart. `Str`. - - **NOTE**: Any change in docker or requirements you need to deploy/build again with updated repo to take effect. DON'T delete .gitignore file. For more information read [THIS](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#upstream-repo-recommended). +- `UPSTREAM_REPO`: Your github repository link, if your repo is private + add `https://username:{githubtoken}@github.com/{username}/{reponame}` format. Get token + from [Github settings](https://github.com/settings/tokens). So you can update your bot from filled repository on each + restart. `Str`. + - **NOTE**: Any change in docker or requirements you need to deploy/build again with updated repo to take effect. + DON'T delete .gitignore file. For more information + read [THIS](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#upstream-repo-recommended). - `UPSTREAM_BRANCH`: Upstream branch for update. Default is `master`. `Str` ### Leech - `LEECH_SPLIT_SIZE`: Size of split in bytes. Default is `2GB`. Default is `4GB` if your account is premium. `Int` - `AS_DOCUMENT`: Default type of Telegram file upload. Default is `False` mean as media. `Bool` -- `EQUAL_SPLITS`: Split files larger than **LEECH_SPLIT_SIZE** into equal parts size (Not working with zip cmd). Default is `False`. `Bool` +- `EQUAL_SPLITS`: Split files larger than **LEECH_SPLIT_SIZE** into equal parts size (Not working with zip cmd). Default + is `False`. `Bool` - `MEDIA_GROUP`: View Uploaded splitted file parts in media group. Default is `False`. `Bool`. - `USER_TRANSMISSION`: Upload/Download by user session. Default is `False`. `Bool` - `LEECH_FILENAME_PREFIX`: Add custom word to leeched file name. `Str` -- `LEECH_DUMP_CHAT`: Chat ID or USERNAME to where files would be uploaded. `Int`|`Str`. **NOTE**: Only available for superGroup/channel. Add `-100` before channel/superGroup id. In short don't add bot or account id! +- `LEECH_DUMP_CHAT`: Chat ID or USERNAME to where files would be uploaded. `Int`|`Str`. **NOTE**: Only available for + superGroup/channel. Add `-100` before channel/superGroup id. In short don't add bot or account id! ### qBittorrent/Aria2c - `TORRENT_TIMEOUT`: Timeout of dead torrents downloading with qBittorrent and Aria2c in seconds. `Int` -- `BASE_URL`: Valid BASE URL where the bot is deployed to use torrent web files selection. Format of URL should be `http://myip`, where `myip` is the IP/Domain(public) of your bot or if you have chosen port other than `80` so write it in this format `http://myip:port` (`http` and not `https`). `Str` +- `BASE_URL`: Valid BASE URL where the bot is deployed to use torrent web files selection. Format of URL should + be `http://myip`, where `myip` is the IP/Domain(public) of your bot or if you have chosen port other than `80` so + write it in this format `http://myip:port` (`http` and not `https`). `Str` - `BASE_URL_PORT`: Which is the **BASE_URL** Port. Default is `80`. `Int` -- `WEB_PINCODE`: Whether to ask for pincode before selecting files from torrent in web or not. Default is `False`. `Bool`. - - **Qbittorrent NOTE**: If your facing ram issues then set limit for `MaxConnections`, decrease `AsyncIOThreadsCount`, set limit of `DiskWriteCacheSize` to `32` and decrease `MemoryWorkingSetLimit` from qbittorrent.conf or bsetting command. +- `WEB_PINCODE`: Whether to ask for pincode before selecting files from torrent in web or not. Default + is `False`. `Bool`. + - **Qbittorrent NOTE**: If your facing ram issues then set limit for `MaxConnections`, + decrease `AsyncIOThreadsCount`, set limit of `DiskWriteCacheSize` to `32` and decrease `MemoryWorkingSetLimit` + from qbittorrent.conf or bsetting command. ### JDownloader @@ -240,23 +309,37 @@ Fill up rest of the fields. Meaning of each field is discussed below. **NOTE**: ### RSS -- `RSS_DELAY`: Time in seconds for rss refresh interval. Recommended `600` second at least. Default is `600` in sec. `Int` -- `RSS_CHAT`: Chat ID/USERNAME where rss links will be sent. If you want message to be sent to the channel then add channel id. Add `-100` before channel id. `Int`|`Str` - - **RSS NOTES**: `RSS_CHAT` is required, otherwise monitor will not work. You must use `USER_STRING_SESSION` --OR-- *CHANNEL*. If using channel then bot should be added in both channel and group(linked to channel) and `RSS_CHAT` is the channel id, so messages sent by the bot to channel will be forwarded to group. Otherwise with `USER_STRING_SESSION` add group id for `RSS_CHAT`. If `DATABASE_URL` not added you will miss the feeds while bot offline. +- `RSS_DELAY`: Time in seconds for rss refresh interval. Recommended `600` second at least. Default is `600` in + sec. `Int` +- `RSS_CHAT`: Chat ID/USERNAME where rss links will be sent. If you want message to be sent to the channel then add + channel id. Add `-100` before channel id. `Int`|`Str` + - **RSS NOTES**: `RSS_CHAT` is required, otherwise monitor will not work. You must use `USER_STRING_SESSION` --OR-- + *CHANNEL*. If using channel then bot should be added in both channel and group(linked to channel) and `RSS_CHAT` + is the channel id, so messages sent by the bot to channel will be forwarded to group. Otherwise + with `USER_STRING_SESSION` add group id for `RSS_CHAT`. If `DATABASE_URL` not added you will miss the feeds while + bot offline. ### Queue System -- `QUEUE_ALL`: Number of parallel tasks of downloads and uploads. For example if 20 task added and `QUEUE_ALL` is `8`, then the summation of uploading and downloading tasks are 8 and the rest in queue. `Int`. **NOTE**: if you want to fill `QUEUE_DOWNLOAD` or `QUEUE_UPLOAD`, then `QUEUE_ALL` value must be greater than or equal to the greatest one and less than or equal to summation of `QUEUE_UPLOAD` and `QUEUE_DOWNLOAD`. +- `QUEUE_ALL`: Number of parallel tasks of downloads and uploads. For example if 20 task added and `QUEUE_ALL` is `8`, + then the summation of uploading and downloading tasks are 8 and the rest in queue. `Int`. **NOTE**: if you want to + fill `QUEUE_DOWNLOAD` or `QUEUE_UPLOAD`, then `QUEUE_ALL` value must be greater than or equal to the greatest one and + less than or equal to summation of `QUEUE_UPLOAD` and `QUEUE_DOWNLOAD`. - `QUEUE_DOWNLOAD`: Number of all parallel downloading tasks. `Int` - `QUEUE_UPLOAD`: Number of all parallel uploading tasks. `Int` ### Torrent Search -- `SEARCH_API_LINK`: Search api app link. Get your api from deploying this [repository](https://github.com/Ryuk-me/Torrent-Api-py). `Str` - - Supported Sites: - >1337x, Piratebay, Nyaasi, Torlock, Torrent Galaxy, Zooqle, Kickass, Bitsearch, MagnetDL, Libgen, YTS, Limetorrent, TorrentFunk, Glodls, TorrentProject and YourBittorrent -- `SEARCH_LIMIT`: Search limit for search api, limit for each site and not overall result limit. Default is zero (Default api limit for each site). `Int` -- `SEARCH_PLUGINS`: List of qBittorrent search plugins (github raw links). I have added some plugins, you can remove/add plugins as you want. Main Source: [qBittorrent Search Plugins (Official/Unofficial)](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins). `List` +- `SEARCH_API_LINK`: Search api app link. Get your api from deploying + this [repository](https://github.com/Ryuk-me/Torrent-Api-py). `Str` + - Supported Sites: + > 1337x, Piratebay, Nyaasi, Torlock, Torrent Galaxy, Zooqle, Kickass, Bitsearch, MagnetDL, Libgen, YTS, Limetorrent, + TorrentFunk, Glodls, TorrentProject and YourBittorrent +- `SEARCH_LIMIT`: Search limit for search api, limit for each site and not overall result limit. Default is zero ( + Default api limit for each site). `Int` +- `SEARCH_PLUGINS`: List of qBittorrent search plugins (github raw links). I have added some plugins, you can remove/add + plugins as you want. Main + Source: [qBittorrent Search Plugins (Official/Unofficial)](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins). `List` ------ @@ -265,8 +348,8 @@ Fill up rest of the fields. Meaning of each field is discussed below. **NOTE**: Make sure you still mount the app folder and installed the docker from official documentation. - There are two methods to build and run the docker: - 1. Using official docker commands. - 2. Using docker-compose. (Recommended) + 1. Using official docker commands. + 2. Using docker-compose. (Recommended) ------ @@ -304,7 +387,9 @@ sudo docker stop id #### Build And Run The Docker Image Using docker-compose -**NOTE**: If you want to use ports other than 80 and 8080 for torrent file selection and rclone serve respectively, change it in [docker-compose.yml](https://github.com/anasty17/mirror-leech-telegram-bot/blob/master/docker-compose.yml) also. +**NOTE**: If you want to use ports other than 80 and 8080 for torrent file selection and rclone serve respectively, +change it in [docker-compose.yml](https://github.com/anasty17/mirror-leech-telegram-bot/blob/master/docker-compose.yml) +also. - Install docker-compose @@ -350,9 +435,11 @@ sudo docker-compose up **IMPORTANT NOTES**: -1. Set `BASE_URL_PORT` and `RCLONE_SERVE_PORT` variables to any port you want to use. Default is `80` and `8080` respectively. +1. Set `BASE_URL_PORT` and `RCLONE_SERVE_PORT` variables to any port you want to use. Default is `80` and `8080` + respectively. -2. Check the number of processing units of your machine with `nproc` cmd and times it by 4, then edit `AsyncIOThreadsCount` in qBittorrent.conf. +2. Check the number of processing units of your machine with `nproc` cmd and times it by 4, then + edit `AsyncIOThreadsCount` in qBittorrent.conf. ------ @@ -397,8 +484,11 @@ help - All cmds with description **NOTES** -- Old authentication changed, now we can't use bot or replit to generate token.pickle. You need OS with a local browser. For example `Termux`. -- Windows users should install python3 and pip. You can find how to install and use them from google or from this [telegraph](https://telegra.ph/Create-Telegram-Mirror-Leech-Bot-by-Deploying-App-with-Heroku-Branch-using-Github-Workflow-12-06) from [Wiszky](https://github.com/vishnoe115) tutorial. +- Old authentication changed, now we can't use bot or replit to generate token.pickle. You need OS with a local browser. + For example `Termux`. +- Windows users should install python3 and pip. You can find how to install and use them from google or from + this [telegraph](https://telegra.ph/Create-Telegram-Mirror-Leech-Bot-by-Deploying-App-with-Heroku-Branch-using-Github-Workflow-12-06) + from [Wiszky](https://github.com/vishnoe115) tutorial. - You can ONLY open the generated link from `generate_drive_token.py` in local browser. 1. Visit the [Google Cloud Console](https://console.developers.google.com/apis/credentials) @@ -429,13 +519,18 @@ python3 generate_drive_token.py ## Upload -- `RCLONE_PATH` is like `GDRIVE_ID` a default path for mirror. In additional to those variables `DEFAULT_UPLOAD` to choose the default tool whether it's rclone or google-api-python-client. -- If `DEFAULT_UPLOAD` = 'rc' then you must fill `RCLONE_PATH` with path as default one or with `rcl` to select destination path on each new task. +- `RCLONE_PATH` is like `GDRIVE_ID` a default path for mirror. In additional to those variables `DEFAULT_UPLOAD` to + choose the default tool whether it's rclone or google-api-python-client. +- If `DEFAULT_UPLOAD` = 'rc' then you must fill `RCLONE_PATH` with path as default one or with `rcl` to select + destination path on each new task. - If `DEFAULT_UPLOAD` = 'gd' then you must fill `GDRIVE_ID` with folder/TD id. -- rclone.conf can be added before deploy like token.pickle to repo folder root or use bsetting to upload it as private file. +- rclone.conf can be added before deploy like token.pickle to repo folder root or use bsetting to upload it as private + file. - If rclone.conf uploaded from usetting or added in `rclone/{user_id}.conf` then `RCLONE_PATH` must start with `mrcc:`. -- Whenever you want to write path manually to use user rclone.conf that added from usetting then you must add the `mrcc:` at the beginning. -- So in short, up: has 4 possible values which is: gd(Upload to GDRIVE_ID), rc(Upload to RCLONE_PATH), rcl(Select Rclone Path) and rclone_path(remote:path(owner rclone.conf) or mrcc:remote:path(user rclone.conf)) +- Whenever you want to write path manually to use user rclone.conf that added from usetting then you must add + the `mrcc:` at the beginning. +- So in short, up: has 4 possible values which is: gd(Upload to GDRIVE_ID), rc(Upload to RCLONE_PATH), rcl(Select Rclone + Path) and rclone_path(remote:path(owner rclone.conf) or mrcc:remote:path(user rclone.conf)) ------ @@ -443,10 +538,17 @@ python3 generate_drive_token.py - `UPSTREAM_REPO` variable can be used for edit/add any file in repository. - You can add private/public repository link to grab/overwrite all files from it. -- You can skip adding the privates files like token.pickle or accounts folder before deploying, simply fill `UPSTREAM_REPO` private one in case you want to grab all files including private files. -- If you added private files while deploying and you have added private `UPSTREAM_REPO` and your private files in this private repository, so your private files will be overwritten from this repository. Also if you are using database for private files, then all files from database will override the private files that added before deploying or from private `UPSTREAM_REPO`. -- If you filled `UPSTREAM_REPO` with the official repository link, then be carefull incase any change in requirements.txt your bot will not start after restart. In this case you need to deploy again with updated code to install the new requirements or simply by changing the `UPSTREAM_REPO` to you fork link with that old updates. -- In case you you filled `UPSTREAM_REPO` with your fork link be carefull also if you fetched the commits from the official repository. +- You can skip adding the privates files like token.pickle or accounts folder before deploying, simply + fill `UPSTREAM_REPO` private one in case you want to grab all files including private files. +- If you added private files while deploying and you have added private `UPSTREAM_REPO` and your private files in this + private repository, so your private files will be overwritten from this repository. Also if you are using database for + private files, then all files from database will override the private files that added before deploying or from + private `UPSTREAM_REPO`. +- If you filled `UPSTREAM_REPO` with the official repository link, then be carefull incase any change in + requirements.txt your bot will not start after restart. In this case you need to deploy again with updated code to + install the new requirements or simply by changing the `UPSTREAM_REPO` to you fork link with that old updates. +- In case you you filled `UPSTREAM_REPO` with your fork link be carefull also if you fetched the commits from the + official repository. - The changes in your `UPSTREAM_REPO` will take affect only after restart. ------ @@ -457,8 +559,9 @@ python3 generate_drive_token.py ### Qbittorrent -- Global options: `GlobalMaxRatio` and `GlobalMaxSeedingMinutes` in qbittorrent.conf, `-1` means no limit, but you can cancel manually. - - **NOTE**: Don't change `MaxRatioAction`. +- Global options: `GlobalMaxRatio` and `GlobalMaxSeedingMinutes` in qbittorrent.conf, `-1` means no limit, but you can + cancel manually. + - **NOTE**: Don't change `MaxRatioAction`. ### Aria2c @@ -468,24 +571,29 @@ python3 generate_drive_token.py ## Using Service Accounts for uploading to avoid user rate limit ->For Service Account to work, you must set `USE_SERVICE_ACCOUNTS` = "True" in config file or environment variables. ->**NOTE**: Using Service Accounts is only recommended while uploading to a Team Drive. +> For Service Account to work, you must set `USE_SERVICE_ACCOUNTS` = "True" in config file or environment variables. +> **NOTE**: Using Service Accounts is only recommended while uploading to a Team Drive. ### 1. Generate Service Accounts. [What is Service Account?](https://cloud.google.com/iam/docs/service-accounts) Let us create only the Service Accounts that we need. -**Warning**: Abuse of this feature is not the aim of this project and we do **NOT** recommend that you make a lot of projects, just one project and 100 SAs allow you plenty of use, its also possible that over abuse might get your projects banned by Google. +**Warning**: Abuse of this feature is not the aim of this project and we do **NOT** recommend that you make a lot of +projects, just one project and 100 SAs allow you plenty of use, its also possible that over abuse might get your +projects banned by Google. ->**NOTE**: If you have created SAs in past from this script, you can also just re download the keys by running: +> **NOTE**: If you have created SAs in past from this script, you can also just re download the keys by running: ``` python3 gen_sa_accounts.py --download-keys $PROJECTID ``` ->**NOTE:** 1 Service Account can upload/copy around 750 GB a day, 1 project can make 100 Service Accounts so you can upload 75 TB a day. +> **NOTE:** 1 Service Account can upload/copy around 750 GB a day, 1 project can make 100 Service Accounts so you can +> upload 75 TB a day. ->**NOTE:** All people can copy `2TB/DAY` from each file creator (uploader account), so if you got error `userRateLimitExceeded` that doesn't mean your limit exceeded but file creator limit have been exceeded which is `2TB/DAY`. +> **NOTE:** All people can copy `2TB/DAY` from each file creator (uploader account), so if you got +> error `userRateLimitExceeded` that doesn't mean your limit exceeded but file creator limit have been exceeded which +> is `2TB/DAY`. #### Two methods to create service accounts @@ -558,7 +666,8 @@ grep -oPh '"client_email": "\K[^"]+' *.json > emails.txt cd .. ``` -Then add emails from emails.txt to Google Group, after that add this Google Group to your Shared Drive and promote it to manager and delete email.txt file from accounts folder +Then add emails from emails.txt to Google Group, after that add this Google Group to your Shared Drive and promote it to +manager and delete email.txt file from accounts folder ##### 2. Add Them To Team Drive Directly @@ -575,15 +684,18 @@ python3 add_to_team_drive.py -d SharedTeamDriveSrcID 1. Go to `https://mongodb.com/` and sign-up. 2. Create Shared Cluster. 3. Press on `Database` under `Deployment` Header, your created cluster will be there. -5. Press on connect, choose `Allow Access From Anywhere` and press on `Add IP Address` without editing the ip, then create user. -6. After creating user press on `Choose a connection`, then press on `Connect your application`. Choose `Driver` **python** and `version` **3.6 or later**. +5. Press on connect, choose `Allow Access From Anywhere` and press on `Add IP Address` without editing the ip, then + create user. +6. After creating user press on `Choose a connection`, then press on `Connect your application`. Choose `Driver` * + *python** and `version` **3.6 or later**. 7. Copy your `connection string` and replace `` with the password of your user, then press close. ------ ## Multi Drive List -To use list from multi TD/folder. Run driveid.py in your terminal and follow it. It will generate **list_drives.txt** file or u can simply create `list_drives.txt` file in working directory and fill it, check below format: +To use list from multi TD/folder. Run driveid.py in your terminal and follow it. It will generate **list_drives.txt** +file or u can simply create `list_drives.txt` file in working directory and fill it, check below format: ``` DriveName folderID/tdID or `root` IndexLink(if available) @@ -601,7 +713,8 @@ TD2 0AO1JDB1t3i5jUk9PVA https://example.dev ## Yt-dlp and Aria2c Authentication Using .netrc File -For using your premium accounts in yt-dlp or for protected Index Links, create .netrc file according to following format: +For using your premium accounts in yt-dlp or for protected Index Links, create .netrc file according to following +format: **Note**: Create .netrc and not netrc, this file will be hidden, so view hidden files to edit it after creation. @@ -617,22 +730,28 @@ Example: machine instagram login anas.tayyar password mypassword ``` -**Instagram Note**: You must login even if you want to download public posts and after first try you must confirm that this was you logged in from different ip(you can confirm from phone app). +**Instagram Note**: You must login even if you want to download public posts and after first try you must confirm that +this was you logged in from different ip(you can confirm from phone app). -**Youtube Note**: For `youtube` authentication use [cookies.txt](https://github.com/ytdl-org/youtube-dl#how-do-i-pass-cookies-to-youtube-dl) file. +**Youtube Note**: For `youtube` authentication +use [cookies.txt](https://github.com/ytdl-org/youtube-dl#how-do-i-pass-cookies-to-youtube-dl) file. -Using Aria2c you can also use built in feature from bot with or without username. Here example for index link without username. +Using Aria2c you can also use built in feature from bot with or without username. Here example for index link without +username. ``` machine example.workers.dev password index_password ``` -Where host is the name of extractor (eg. instagram, Twitch). Multiple accounts of different hosts can be added each separated by a new line. +Where host is the name of extractor (eg. instagram, Twitch). Multiple accounts of different hosts can be added each +separated by a new line. ----- - > +> + ## All Thanks To Our Contributors + diff --git a/add_to_team_drive.py b/add_to_team_drive.py index 9e2951fb350..2e2d461d41d 100644 --- a/add_to_team_drive.py +++ b/add_to_team_drive.py @@ -1,15 +1,16 @@ from __future__ import print_function + +import argparse +import glob import googleapiclient.discovery import json +import os +import pickle import progress.bar -import glob import sys -import argparse import time -from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request -import os -import pickle +from google_auth_oauthlib.flow import InstalledAppFlow stt = time.time() @@ -65,7 +66,7 @@ drive = googleapiclient.discovery.build("drive", "v3", credentials=creds) batch = drive.new_batch_http_request() -aa = glob.glob('%s/*.json' % acc_dir) +aa = glob.glob(f'{acc_dir}/*.json') pbar = progress.bar.Bar("Readying accounts", max=len(aa)) for i in aa: ce = json.loads(open(i, 'r').read())['client_email'] diff --git a/bot/__init__.py b/bot/__init__.py index 5557ddced05..aacc009a379 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -1,16 +1,7 @@ -from tzlocal import get_localzone from apscheduler.schedulers.asyncio import AsyncIOScheduler -from pyrogram import Client as tgClient, enums -from pymongo import MongoClient +from aria2p import API as ariaAPI, Client as ariaClient from asyncio import Lock from dotenv import load_dotenv, dotenv_values -from time import time -from subprocess import Popen, run -from os import remove, path as ospath, environ, getcwd -from aria2p import API as ariaAPI, Client as ariaClient -from qbittorrentapi import Client as qbClient -from socket import setdefaulttimeout -from uvloop import install from logging import ( getLogger, FileHandler, @@ -22,6 +13,15 @@ warning as log_warning, ERROR, ) +from os import remove, path as ospath, environ, getcwd +from pymongo import MongoClient +from pyrogram import Client as tgClient, enums +from qbittorrentapi import Client as qbClient +from socket import setdefaulttimeout +from subprocess import Popen, run +from time import time +from tzlocal import get_localzone +from uvloop import install # from faulthandler import enable as faulthandler_enable # faulthandler_enable() @@ -249,9 +249,9 @@ LEECH_SPLIT_SIZE = environ.get("LEECH_SPLIT_SIZE", "") if ( - len(LEECH_SPLIT_SIZE) == 0 - or int(LEECH_SPLIT_SIZE) > MAX_SPLIT_SIZE - or LEECH_SPLIT_SIZE == "2097152000" + len(LEECH_SPLIT_SIZE) == 0 + or int(LEECH_SPLIT_SIZE) > MAX_SPLIT_SIZE + or LEECH_SPLIT_SIZE == "2097152000" ): LEECH_SPLIT_SIZE = MAX_SPLIT_SIZE else: diff --git a/bot/__main__.py b/bot/__main__.py index 115795f05c6..b8cc9a73355 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -1,12 +1,7 @@ -from signal import signal, SIGINT -from aiofiles.os import path as aiopath, remove from aiofiles import open as aiopen -from os import execl as osexecl -from time import time -from sys import executable -from pyrogram.handlers import MessageHandler -from pyrogram.filters import command +from aiofiles.os import path as aiopath, remove from asyncio import gather, create_subprocess_exec +from os import execl as osexecl from psutil import ( disk_usage, cpu_percent, @@ -16,19 +11,12 @@ net_io_counters, boot_time, ) +from pyrogram.filters import command +from pyrogram.handlers import MessageHandler +from signal import signal, SIGINT +from sys import executable +from time import time -from .helper.mirror_utils.rclone_utils.serve import rclone_serve_booter -from .helper.ext_utils.jdownloader_booter import jdownloader -from .helper.ext_utils.telegraph_helper import telegraph -from .helper.ext_utils.files_utils import clean_all, exit_clean_up -from .helper.ext_utils.bot_utils import cmd_exec, sync_to_async, create_help_buttons -from .helper.ext_utils.status_utils import get_readable_file_size, get_readable_time -from .helper.ext_utils.db_handler import DbManger -from .helper.telegram_helper.bot_commands import BotCommands -from .helper.telegram_helper.message_utils import sendMessage, editMessage, sendFile -from .helper.telegram_helper.filters import CustomFilters -from .helper.telegram_helper.button_build import ButtonMaker -from .helper.listeners.aria2_listener import start_aria2_listener from bot import ( bot, botStartTime, @@ -38,6 +26,18 @@ INCOMPLETE_TASK_NOTIFIER, scheduler, ) +from .helper.ext_utils.bot_utils import cmd_exec, sync_to_async, create_help_buttons +from .helper.ext_utils.db_handler import DbManager +from .helper.ext_utils.files_utils import clean_all, exit_clean_up +from .helper.ext_utils.jdownloader_booter import jdownloader +from .helper.ext_utils.status_utils import get_readable_file_size, get_readable_time +from .helper.ext_utils.telegraph_helper import telegraph +from .helper.listeners.aria2_listener import start_aria2_listener +from .helper.mirror_utils.rclone_utils.serve import rclone_serve_booter +from .helper.telegram_helper.bot_commands import BotCommands +from .helper.telegram_helper.button_build import ButtonMaker +from .helper.telegram_helper.filters import CustomFilters +from .helper.telegram_helper.message_utils import sendMessage, editMessage, sendFile from .modules import ( authorize, cancel_task, @@ -210,7 +210,7 @@ async def send_incompelete_task_message(cid, msg): LOGGER.error(e) if INCOMPLETE_TASK_NOTIFIER and DATABASE_URL: - if notifier_dict := await DbManger().get_incomplete_tasks(): + if notifier_dict := await DbManager().get_incomplete_tasks(): for cid, data in notifier_dict.items(): msg = "Restarted Successfully!" if cid == chat_id else "Bot Restarted!" for tag, links in data.items(): diff --git a/bot/helper/common.py b/bot/helper/common.py index 1263fc9b5ba..886691bed23 100644 --- a/bot/helper/common.py +++ b/bot/helper/common.py @@ -1,8 +1,8 @@ from aiofiles.os import path as aiopath, remove from asyncio import sleep, create_subprocess_exec from asyncio.subprocess import PIPE -from secrets import token_urlsafe from os import walk, path as ospath +from secrets import token_urlsafe from bot import ( DOWNLOAD_DIR, @@ -19,19 +19,9 @@ cpu_eater_lock, subprocess_lock, ) -from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.ext_utils.bot_utils import new_task, sync_to_async -from bot.helper.ext_utils.links_utils import ( - is_gdrive_id, - is_rclone_path, - is_gdrive_link, - is_telegram_link, -) -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - sendStatusMessage, - get_tg_link_message, -) +from bot.helper.ext_utils.bulk_links import extractBulkLinks +from bot.helper.ext_utils.exceptions import NotSupportedExtractionArchive from bot.helper.ext_utils.files_utils import ( get_base_name, is_first_archive_split, @@ -40,20 +30,30 @@ get_path_size, clean_target, ) -from bot.helper.ext_utils.bulk_links import extractBulkLinks -from bot.helper.ext_utils.media_utils import split_file, get_document_type +from bot.helper.ext_utils.links_utils import ( + is_gdrive_id, + is_rclone_path, + is_gdrive_link, + is_telegram_link, +) from bot.helper.ext_utils.media_utils import ( createThumb, getSplitSizeBytes, createSampleVideo, ) -from bot.helper.mirror_utils.rclone_utils.list import RcloneList +from bot.helper.ext_utils.media_utils import split_file, get_document_type from bot.helper.mirror_utils.gdrive_utils.list import gdriveList +from bot.helper.mirror_utils.rclone_utils.list import RcloneList from bot.helper.mirror_utils.status_utils.extract_status import ExtractStatus -from bot.helper.mirror_utils.status_utils.zip_status import ZipStatus -from bot.helper.mirror_utils.status_utils.split_status import SplitStatus from bot.helper.mirror_utils.status_utils.sample_video_status import SampleVideoStatus -from bot.helper.ext_utils.exceptions import NotSupportedExtractionArchive +from bot.helper.mirror_utils.status_utils.split_status import SplitStatus +from bot.helper.mirror_utils.status_utils.zip_status import ZipStatus +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + sendStatusMessage, + get_tg_link_message, +) class TaskConfig: @@ -101,9 +101,9 @@ def getTokenPath(self, dest): if dest.startswith("mtp:"): return f"tokens/{self.user_id}.pickle" elif ( - dest.startswith("sa:") - or config_dict["USE_SERVICE_ACCOUNTS"] - and not dest.startswith("tp:") + dest.startswith("sa:") + or config_dict["USE_SERVICE_ACCOUNTS"] + and not dest.startswith("tp:") ): return "accounts" else: @@ -122,10 +122,10 @@ async def isTokenExists(self, path, status): if not await aiopath.exists(config_path): raise ValueError(f"Rclone Config: {config_path} not Exists!") elif ( - status == "dl" - and is_gdrive_link(path) - or status == "up" - and is_gdrive_id(path) + status == "dl" + and is_gdrive_link(path) + or status == "up" + and is_gdrive_id(path) ): token_path = self.getTokenPath(path) if token_path.startswith("tokens/") and status == "up": @@ -152,28 +152,28 @@ async def beforeStart(self): raise ValueError(self.link) self.userTransmission = IS_PREMIUM_USER and ( - self.user_dict.get("user_transmission") - or config_dict["USER_TRANSMISSION"] - and "user_transmission" not in self.user_dict + self.user_dict.get("user_transmission") + or config_dict["USER_TRANSMISSION"] + and "user_transmission" not in self.user_dict ) if not self.isLeech: self.stopDuplicate = ( - self.user_dict.get("stop_duplicate") - or "stop_duplicate" not in self.user_dict - and config_dict["STOP_DUPLICATE"] + self.user_dict.get("stop_duplicate") + or "stop_duplicate" not in self.user_dict + and config_dict["STOP_DUPLICATE"] ) default_upload = ( - self.user_dict.get("default_upload", "") - or config_dict["DEFAULT_UPLOAD"] + self.user_dict.get("default_upload", "") + or config_dict["DEFAULT_UPLOAD"] ) if (not self.upDest and default_upload == "rc") or self.upDest == "rc": self.upDest = ( - self.user_dict.get("rclone_path") or config_dict["RCLONE_PATH"] + self.user_dict.get("rclone_path") or config_dict["RCLONE_PATH"] ) elif (not self.upDest and default_upload == "gd") or self.upDest == "gd": self.upDest = ( - self.user_dict.get("gdrive_id") or config_dict["GDRIVE_ID"] + self.user_dict.get("gdrive_id") or config_dict["GDRIVE_ID"] ) if not self.upDest: raise ValueError("No Upload Destination!") @@ -208,11 +208,11 @@ async def beforeStart(self): raise ValueError(self.upDest) elif self.isClone: if is_gdrive_link(self.link) and self.getTokenPath( - self.link + self.link ) != self.getTokenPath(self.upDest): raise ValueError("You must use the same token to clone!") elif is_rclone_path(self.link) and self.getConfigPath( - self.link + self.link ) != self.getConfigPath(self.upDest): raise ValueError("You must use the same config to clone!") else: @@ -229,8 +229,8 @@ async def beforeStart(self): ) member = await chat.get_member(uploader_id) if ( - not member.privileges.can_manage_chat - or not member.privileges.can_delete_messages + not member.privileges.can_manage_chat + or not member.privileges.can_delete_messages ): raise ValueError("You don't have enough privileges in this chat!") elif self.userTransmission and not self.isSuperChat: @@ -243,21 +243,21 @@ async def beforeStart(self): else: self.splitSize = getSplitSizeBytes(self.splitSize) self.splitSize = ( - self.splitSize - or self.user_dict.get("split_size") - or config_dict["LEECH_SPLIT_SIZE"] + self.splitSize + or self.user_dict.get("split_size") + or config_dict["LEECH_SPLIT_SIZE"] ) self.equalSplits = ( - self.user_dict.get("equal_splits") - or config_dict["EQUAL_SPLITS"] - and "equal_splits" not in self.user_dict + self.user_dict.get("equal_splits") + or config_dict["EQUAL_SPLITS"] + and "equal_splits" not in self.user_dict ) self.maxSplitSize = MAX_SPLIT_SIZE if self.userTransmission else 2097152000 self.splitSize = min(self.splitSize, self.maxSplitSize) self.upDest = ( - self.upDest - or self.user_dict.get("leech_dest") - or config_dict["LEECH_DUMP_CHAT"] + self.upDest + or self.user_dict.get("leech_dest") + or config_dict["LEECH_DUMP_CHAT"] ) if not isinstance(self.upDest, int): if self.upDest.startswith("b:"): @@ -270,9 +270,9 @@ async def beforeStart(self): self.upDest = int(self.upDest) self.as_doc = ( - self.user_dict.get("as_doc", False) - or config_dict["AS_DOCUMENT"] - and "as_doc" not in self.user_dict + self.user_dict.get("as_doc", False) + or config_dict["AS_DOCUMENT"] + and "as_doc" not in self.user_dict ) if is_telegram_link(self.thumb): @@ -400,13 +400,13 @@ async def proceedExtract(self, dl_path, size, gid): else: up_path = dl_path for dirpath, _, files in await sync_to_async( - walk, dl_path, topdown=False + walk, dl_path, topdown=False ): for file_ in files: if ( - is_first_archive_split(file_) - or is_archive(file_) - and not file_.endswith(".rar") + is_first_archive_split(file_) + or is_archive(file_) + and not file_.endswith(".rar") ): f_path = ospath.join(dirpath, file_) t_path = ( @@ -441,9 +441,9 @@ async def proceedExtract(self, dl_path, size, gid): f"{stderr}. Unable to extract archive splits!. Path: {f_path}" ) if ( - not self.seed - and self.suproc is not None - and self.suproc.returncode == 0 + not self.seed + and self.suproc is not None + and self.suproc.returncode == 0 ): for file_ in files: if is_archive_split(file_) or is_archive(file_): @@ -610,7 +610,7 @@ async def generateSampleVideo(self, dl_path, size, gid): ) else: for dirpath, _, files in await sync_to_async( - walk, dl_path, topdown=False + walk, dl_path, topdown=False ): for file_ in files: f_path = ospath.join(dirpath, file_) diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py index c0076afc733..952b4a9d754 100644 --- a/bot/helper/ext_utils/bot_utils.py +++ b/bot/helper/ext_utils/bot_utils.py @@ -1,6 +1,3 @@ -from asyncio.subprocess import PIPE -from functools import partial, wraps -from concurrent.futures import ThreadPoolExecutor from aiohttp import ClientSession from asyncio import ( create_subprocess_exec, @@ -8,11 +5,14 @@ run_coroutine_threadsafe, sleep, ) +from asyncio.subprocess import PIPE +from concurrent.futures import ThreadPoolExecutor +from functools import partial, wraps from bot import user_data, config_dict, bot_loop from bot.helper.ext_utils.help_messages import YT_HELP_DICT, MIRROR_HELP_DICT -from bot.helper.telegram_helper.button_build import ButtonMaker from bot.helper.ext_utils.telegraph_helper import telegraph +from bot.helper.telegram_helper.button_build import ButtonMaker THREADPOOL = ThreadPoolExecutor(max_workers=1000) @@ -38,12 +38,12 @@ def create_help_buttons(): buttons = ButtonMaker() for name in list(MIRROR_HELP_DICT.keys())[1:]: buttons.ibutton(name, f"help m {name}") - buttons.ibutton("Close", f"help close") + buttons.ibutton("Close", "help close") COMMAND_USAGE["mirror"] = [MIRROR_HELP_DICT["main"], buttons.build_menu(3)] buttons.reset() for name in list(YT_HELP_DICT.keys())[1:]: buttons.ibutton(name, f"help yt {name}") - buttons.ibutton("Close", f"help close") + buttons.ibutton("Close", "help close") COMMAND_USAGE["yt"] = [YT_HELP_DICT["main"], buttons.build_menu(3)] diff --git a/bot/helper/ext_utils/db_handler.py b/bot/helper/ext_utils/db_handler.py index bb2657e0677..8f8634eba84 100644 --- a/bot/helper/ext_utils/db_handler.py +++ b/bot/helper/ext_utils/db_handler.py @@ -1,8 +1,8 @@ -from aiofiles.os import path as aiopath, makedirs from aiofiles import open as aiopen +from aiofiles.os import path as aiopath, makedirs +from dotenv import dotenv_values from motor.motor_asyncio import AsyncIOMotorClient from pymongo.errors import PyMongoError -from dotenv import dotenv_values from bot import ( DATABASE_URL, @@ -17,7 +17,7 @@ ) -class DbManger: +class DbManager: def __init__(self): self._err = False self._db = None @@ -233,4 +233,4 @@ async def trunc_table(self, name): if DATABASE_URL: - bot_loop.run_until_complete(DbManger().db_load()) + bot_loop.run_until_complete(DbManager().db_load()) diff --git a/bot/helper/ext_utils/files_utils.py b/bot/helper/ext_utils/files_utils.py index 98e20a4c215..9b24a4d04bb 100644 --- a/bot/helper/ext_utils/files_utils.py +++ b/bot/helper/ext_utils/files_utils.py @@ -1,15 +1,15 @@ -from os import walk, path as ospath, makedirs from aiofiles.os import remove, path as aiopath, listdir, rmdir from aioshutil import rmtree as aiormtree from magic import Magic +from os import walk, path as ospath, makedirs from re import split as re_split, I, search as re_search, escape +from shutil import rmtree from subprocess import run as srun from sys import exit as sexit -from shutil import rmtree -from .exceptions import NotSupportedExtractionArchive from bot import aria2, LOGGER, DOWNLOAD_DIR, get_client from bot.helper.ext_utils.bot_utils import sync_to_async, cmd_exec +from .exceptions import NotSupportedExtractionArchive ARCH_EXT = [ ".tar.bz2", @@ -115,9 +115,9 @@ async def clean_unwanted(path): for dirpath, _, files in await sync_to_async(walk, path, topdown=False): for filee in files: if ( - filee.endswith(".!qB") - or filee.endswith(".parts") - and filee.startswith(".") + filee.endswith(".!qB") + or filee.endswith(".parts") + and filee.startswith(".") ): await remove(ospath.join(dirpath, filee)) if dirpath.endswith((".unwanted", "splited_files_mltb", "copied_mltb")): @@ -171,7 +171,7 @@ async def join_files(path): exists = False for file_ in files: if re_search(r"\.0+2$", file_) and await sync_to_async( - get_mime_type, f"{path}/{file_}" + get_mime_type, f"{path}/{file_}" ) not in ["application/x-7z-compressed", "application/zip"]: exists = True final_name = file_.rsplit(".", 1)[0] diff --git a/bot/helper/ext_utils/jdownloader_booter.py b/bot/helper/ext_utils/jdownloader_booter.py index 01218297fe2..8396b71b8ef 100644 --- a/bot/helper/ext_utils/jdownloader_booter.py +++ b/bot/helper/ext_utils/jdownloader_booter.py @@ -1,15 +1,7 @@ -from myjd import Myjdapi -from json import dump +from aiofiles.os import listdir from asyncio import sleep as aiosleep +from json import dump from random import randint -from aiofiles.os import listdir -from myjd.exception import ( - MYJDException, - MYJDAuthFailedException, - MYJDEmailForbiddenException, - MYJDEmailInvalidException, - MYJDErrorEmailNotConfirmedException, -) from bot import config_dict, LOGGER, jd_lock from bot.helper.ext_utils.bot_utils import ( @@ -17,6 +9,14 @@ new_task, sync_to_async, ) +from myjd import Myjdapi +from myjd.exception import ( + MYJDException, + MYJDAuthFailedException, + MYJDEmailForbiddenException, + MYJDEmailInvalidException, + MYJDErrorEmailNotConfirmedException, +) class JDownloader(Myjdapi): @@ -59,8 +59,8 @@ async def boot(self): "email": config_dict["JD_EMAIL"], } with open( - "/JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json", - "w", + "/JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json", + "w", ) as sf: sf.truncate(0) dump(jdata, sf) @@ -77,10 +77,10 @@ def jdconnect(self): LOGGER.info("JDownloader is connected!") return True except ( - MYJDAuthFailedException, - MYJDEmailForbiddenException, - MYJDEmailInvalidException, - MYJDErrorEmailNotConfirmedException, + MYJDAuthFailedException, + MYJDEmailForbiddenException, + MYJDEmailInvalidException, + MYJDErrorEmailNotConfirmedException, ) as err: self.error = f"{err}".strip() LOGGER.info(f"Failed to connect with jdownloader! ERROR: {self.error}") diff --git a/bot/helper/ext_utils/media_utils.py b/bot/helper/ext_utils/media_utils.py index 1776c3e7c10..c91ff48ee69 100644 --- a/bot/helper/ext_utils/media_utils.py +++ b/bot/helper/ext_utils/media_utils.py @@ -1,11 +1,11 @@ -from os import path as ospath, cpu_count +from PIL import Image from aiofiles.os import remove, path as aiopath, makedirs -from time import time -from re import search as re_search +from aioshutil import move from asyncio import create_subprocess_exec, gather, wait_for from asyncio.subprocess import PIPE -from PIL import Image -from aioshutil import move +from os import path as ospath, cpu_count +from re import search as re_search +from time import time from bot import LOGGER, subprocess_lock from bot.helper.ext_utils.bot_utils import cmd_exec @@ -104,7 +104,7 @@ async def get_media_info(path): async def get_document_type(path): is_video, is_audio, is_image = False, False, False if path.endswith(tuple(ARCH_EXT)) or re_search( - r".+(\.|_)(rar|7z|zip|bin)(\.0*\d+)?$", path + r".+(\.|_)(rar|7z|zip|bin)(\.0*\d+)?$", path ): return is_video, is_audio, is_image mime_type = await sync_to_async(get_mime_type, path) @@ -260,15 +260,15 @@ async def create_thumbnail(video_file, duration): async def split_file( - path, - size, - dirpath, - split_size, - listener, - start_time=0, - i=1, - inLoop=False, - multi_streams=True, + path, + size, + dirpath, + split_size, + listener, + start_time=0, + i=1, + inLoop=False, + multi_streams=True, ): if listener.seed and not listener.newDir: dirpath = f"{dirpath}/splited_files_mltb" @@ -401,7 +401,7 @@ async def split_file( async def createSampleVideo( - listener, video_file, sample_duration, part_duration, oneFile=False + listener, video_file, sample_duration, part_duration, oneFile=False ): filter_complex = "" dir, name = video_file.rsplit("/", 1) @@ -445,7 +445,7 @@ async def createSampleVideo( "-c:a", "aac", "-threads", - f"{cpu_count()//2}", + f"{cpu_count() // 2}", output_file, ] diff --git a/bot/helper/ext_utils/status_utils.py b/bot/helper/ext_utils/status_utils.py index 7de54c4209e..cd675185e43 100644 --- a/bot/helper/ext_utils/status_utils.py +++ b/bot/helper/ext_utils/status_utils.py @@ -1,12 +1,11 @@ -from time import time from html import escape from psutil import virtual_memory, cpu_percent, disk_usage +from time import time from bot import DOWNLOAD_DIR, task_dict, task_dict_lock, botStartTime, config_dict from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.button_build import ButtonMaker - SIZE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"] @@ -128,13 +127,13 @@ def get_readable_message(sid, is_user, page_no=1, status="All", page_step=1): start_position = (page_no - 1) * STATUS_LIMIT for index, task in enumerate( - tasks[start_position : STATUS_LIMIT + start_position], start=1 + tasks[start_position: STATUS_LIMIT + start_position], start=1 ): tstatus = task.status() if task.listener.isSuperChat: - msg += f"{index+start_position}.{tstatus}: " + msg += f"{index + start_position}.{tstatus}: " else: - msg += f"{index+start_position}.{tstatus}: " + msg += f"{index + start_position}.{tstatus}: " msg += f"{escape(f'{task.name()}')}" if tstatus not in [ MirrorStatus.STATUS_SPLITTING, diff --git a/bot/helper/ext_utils/task_manager.py b/bot/helper/ext_utils/task_manager.py index 1dfa7568e3f..d09e960e0f8 100644 --- a/bot/helper/ext_utils/task_manager.py +++ b/bot/helper/ext_utils/task_manager.py @@ -1,9 +1,5 @@ from asyncio import Event, sleep -from bot.helper.mirror_utils.gdrive_utils.search import gdSearch -from bot.helper.ext_utils.files_utils import get_base_name -from bot.helper.ext_utils.bot_utils import sync_to_async, get_telegraph_list -from bot.helper.ext_utils.links_utils import is_gdrive_id from bot import ( config_dict, queued_dl, @@ -13,18 +9,22 @@ queue_dict_lock, LOGGER, ) +from bot.helper.ext_utils.bot_utils import sync_to_async, get_telegraph_list +from bot.helper.ext_utils.files_utils import get_base_name +from bot.helper.ext_utils.links_utils import is_gdrive_id +from bot.helper.mirror_utils.gdrive_utils.search import gdSearch async def stop_duplicate_check(listener): if ( - isinstance(listener.upDest, int) - or listener.isLeech - or listener.select - or not is_gdrive_id(listener.upDest) - or listener.upDest.startswith("mtp:") - and listener.stopDuplicate - or not listener.stopDuplicate - or listener.sameDir + isinstance(listener.upDest, int) + or listener.isLeech + or listener.select + or not is_gdrive_id(listener.upDest) + or listener.upDest.startswith("mtp:") + and listener.stopDuplicate + or not listener.stopDuplicate + or listener.sameDir ): return False, None name = listener.name @@ -60,7 +60,7 @@ async def is_queued(mid): dl = len(non_queued_dl) up = len(non_queued_up) if ( - all_limit and dl + up >= all_limit and (not dl_limit or dl >= dl_limit) + all_limit and dl + up >= all_limit and (not dl_limit or dl >= dl_limit) ) or (dl_limit and dl >= dl_limit): add_to_queue = True event = Event() diff --git a/bot/helper/ext_utils/telegraph_helper.py b/bot/helper/ext_utils/telegraph_helper.py index 3b4523d9add..66245464e2d 100644 --- a/bot/helper/ext_utils/telegraph_helper.py +++ b/bot/helper/ext_utils/telegraph_helper.py @@ -1,5 +1,5 @@ -from secrets import token_urlsafe from asyncio import sleep +from secrets import token_urlsafe from telegraph.aio import Telegraph from telegraph.exceptions import RetryAfterError diff --git a/bot/helper/listeners/aria2_listener.py b/bot/helper/listeners/aria2_listener.py index 4310af7eaee..887d0f5f91c 100644 --- a/bot/helper/listeners/aria2_listener.py +++ b/bot/helper/listeners/aria2_listener.py @@ -1,17 +1,17 @@ +from aiofiles.os import remove, path as aiopath from asyncio import sleep from time import time -from aiofiles.os import remove, path as aiopath from bot import aria2, task_dict_lock, task_dict, LOGGER, config_dict -from bot.helper.mirror_utils.status_utils.aria2_status import Aria2Status -from bot.helper.ext_utils.files_utils import clean_unwanted -from bot.helper.ext_utils.status_utils import getTaskByGid -from bot.helper.ext_utils.task_manager import stop_duplicate_check from bot.helper.ext_utils.bot_utils import ( new_thread, bt_selection_buttons, sync_to_async, ) +from bot.helper.ext_utils.files_utils import clean_unwanted +from bot.helper.ext_utils.status_utils import getTaskByGid +from bot.helper.ext_utils.task_manager import stop_duplicate_check +from bot.helper.mirror_utils.status_utils.aria2_status import Aria2Status from bot.helper.telegram_helper.message_utils import ( sendMessage, deleteMessage, diff --git a/bot/helper/listeners/jdownloader_listener.py b/bot/helper/listeners/jdownloader_listener.py index 9375d9b4ab5..73a1d097a27 100644 --- a/bot/helper/listeners/jdownloader_listener.py +++ b/bot/helper/listeners/jdownloader_listener.py @@ -2,8 +2,8 @@ from bot import Intervals, jd_lock, jd_downloads from bot.helper.ext_utils.bot_utils import new_task, sync_to_async, retry_function -from bot.helper.ext_utils.status_utils import getTaskByGid from bot.helper.ext_utils.jdownloader_booter import jdownloader +from bot.helper.ext_utils.status_utils import getTaskByGid @new_task @@ -41,16 +41,10 @@ async def _jd_listener(): ) except: continue - finished = [] - for pack in packages: - if pack.get("finished", False): - finished.append(pack["uuid"]) + finished = [pack["uuid"] for pack in packages if pack.get("finished", False)] for gid in finished: if gid in jd_downloads and jd_downloads[gid]["status"] != "done": - is_finished = True - for did in jd_downloads[gid]["ids"]: - if did not in finished: - is_finished = False + is_finished = all(did in finished for did in jd_downloads[gid]["ids"]) if is_finished: jd_downloads[gid]["status"] = "done" _onDownloadComplete(gid) diff --git a/bot/helper/listeners/qbit_listener.py b/bot/helper/listeners/qbit_listener.py index 3a0c59059f4..feafc07184a 100644 --- a/bot/helper/listeners/qbit_listener.py +++ b/bot/helper/listeners/qbit_listener.py @@ -1,13 +1,7 @@ +from aiofiles.os import remove, path as aiopath from asyncio import sleep, gather from time import time -from aiofiles.os import remove, path as aiopath -from bot.helper.mirror_utils.status_utils.qbit_status import QbittorrentStatus -from bot.helper.telegram_helper.message_utils import update_status_message -from bot.helper.ext_utils.bot_utils import new_task, sync_to_async -from bot.helper.ext_utils.status_utils import get_readable_time, getTaskByGid -from bot.helper.ext_utils.files_utils import clean_unwanted -from bot.helper.ext_utils.task_manager import stop_duplicate_check from bot import ( task_dict, task_dict_lock, @@ -19,6 +13,12 @@ LOGGER, bot_loop, ) +from bot.helper.ext_utils.bot_utils import new_task, sync_to_async +from bot.helper.ext_utils.files_utils import clean_unwanted +from bot.helper.ext_utils.status_utils import get_readable_time, getTaskByGid +from bot.helper.ext_utils.task_manager import stop_duplicate_check +from bot.helper.mirror_utils.status_utils.qbit_status import QbittorrentStatus +from bot.helper.telegram_helper.message_utils import update_status_message async def _remove_torrent(client, hash_, tag): @@ -129,8 +129,8 @@ async def _qb_listener(): TORRENT_TIMEOUT = config_dict["TORRENT_TIMEOUT"] QbTorrents[tag]["stalled_time"] = time() if ( - TORRENT_TIMEOUT - and time() - tor_info.added_on >= TORRENT_TIMEOUT + TORRENT_TIMEOUT + and time() - tor_info.added_on >= TORRENT_TIMEOUT ): _onDownloadError("Dead Torrent!", tor_info) else: @@ -140,16 +140,16 @@ async def _qb_listener(): elif state == "downloading": QbTorrents[tag]["stalled_time"] = time() if ( - config_dict["STOP_DUPLICATE"] - and not QbTorrents[tag]["stop_dup_check"] + config_dict["STOP_DUPLICATE"] + and not QbTorrents[tag]["stop_dup_check"] ): QbTorrents[tag]["stop_dup_check"] = True _stop_duplicate(tor_info) elif state == "stalledDL": TORRENT_TIMEOUT = config_dict["TORRENT_TIMEOUT"] if ( - not QbTorrents[tag]["rechecked"] - and 0.99989999999999999 < tor_info.progress < 1 + not QbTorrents[tag]["rechecked"] + and 0.99989999999999999 < tor_info.progress < 1 ): msg = f"Force recheck - Name: {tor_info.name} Hash: " msg += f"{tor_info.hash} Downloaded Bytes: {tor_info.downloaded} " @@ -160,9 +160,9 @@ async def _qb_listener(): ) QbTorrents[tag]["rechecked"] = True elif ( - TORRENT_TIMEOUT - and time() - QbTorrents[tag]["stalled_time"] - >= TORRENT_TIMEOUT + TORRENT_TIMEOUT + and time() - QbTorrents[tag]["stalled_time"] + >= TORRENT_TIMEOUT ): _onDownloadError("Dead Torrent!", tor_info) else: @@ -178,15 +178,15 @@ async def _qb_listener(): "No enough space for this torrent on device", tor_info ) elif ( - tor_info.completion_on != 0 - and not QbTorrents[tag]["uploaded"] - and state - not in ["checkingUP", "checkingDL", "checkingResumeData"] + tor_info.completion_on != 0 + and not QbTorrents[tag]["uploaded"] + and state + not in ["checkingUP", "checkingDL", "checkingResumeData"] ): QbTorrents[tag]["uploaded"] = True _onDownloadComplete(tor_info) elif ( - state in ["pausedUP", "pausedDL"] and QbTorrents[tag]["seeding"] + state in ["pausedUP", "pausedDL"] and QbTorrents[tag]["seeding"] ): QbTorrents[tag]["seeding"] = False _onSeedFinish(tor_info) diff --git a/bot/helper/listeners/task_listener.py b/bot/helper/listeners/task_listener.py index dac86b288db..347fc98b0e0 100644 --- a/bot/helper/listeners/task_listener.py +++ b/bot/helper/listeners/task_listener.py @@ -1,34 +1,9 @@ -from requests import utils as rutils from aiofiles.os import path as aiopath, listdir, makedirs -from html import escape from aioshutil import move from asyncio import sleep, Event, gather +from html import escape +from requests import utils as rutils -from bot.helper.ext_utils.status_utils import get_readable_file_size -from bot.helper.ext_utils.bot_utils import sync_to_async -from bot.helper.ext_utils.links_utils import is_gdrive_id -from bot.helper.ext_utils.task_manager import start_from_queued -from bot.helper.mirror_utils.status_utils.gdrive_status import GdriveStatus -from bot.helper.mirror_utils.status_utils.telegram_status import TelegramStatus -from bot.helper.mirror_utils.status_utils.rclone_status import RcloneStatus -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus -from bot.helper.mirror_utils.gdrive_utils.upload import gdUpload -from bot.helper.mirror_utils.telegram_uploader import TgUploader -from bot.helper.mirror_utils.rclone_utils.transfer import RcloneTransferHelper -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.db_handler import DbManger -from bot.helper.common import TaskConfig -from bot.helper.ext_utils.files_utils import ( - get_path_size, - clean_download, - clean_target, - join_files, -) -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - delete_status, - update_status_message, -) from bot import ( Intervals, aria2, @@ -44,6 +19,31 @@ queued_dl, queue_dict_lock, ) +from bot.helper.common import TaskConfig +from bot.helper.ext_utils.bot_utils import sync_to_async +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.ext_utils.files_utils import ( + get_path_size, + clean_download, + clean_target, + join_files, +) +from bot.helper.ext_utils.links_utils import is_gdrive_id +from bot.helper.ext_utils.status_utils import get_readable_file_size +from bot.helper.ext_utils.task_manager import start_from_queued +from bot.helper.mirror_utils.gdrive_utils.upload import gdUpload +from bot.helper.mirror_utils.rclone_utils.transfer import RcloneTransferHelper +from bot.helper.mirror_utils.status_utils.gdrive_status import GdriveStatus +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.mirror_utils.status_utils.rclone_status import RcloneStatus +from bot.helper.mirror_utils.status_utils.telegram_status import TelegramStatus +from bot.helper.mirror_utils.telegram_uploader import TgUploader +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + delete_status, + update_status_message, +) class TaskListener(TaskConfig): @@ -67,11 +67,11 @@ def removeFromSameDir(self): async def onDownloadStart(self): if ( - self.isSuperChat - and config_dict["INCOMPLETE_TASK_NOTIFIER"] - and DATABASE_URL + self.isSuperChat + and config_dict["INCOMPLETE_TASK_NOTIFIER"] + and DATABASE_URL ): - await DbManger().add_incomplete_task( + await DbManager().add_incomplete_task( self.message.chat.id, self.message.link, self.tag ) @@ -79,17 +79,17 @@ async def onDownloadComplete(self): multi_links = False if self.sameDir and self.mid in self.sameDir["tasks"]: while not ( - self.sameDir["total"] in [1, 0] - or self.sameDir["total"] > 1 - and len(self.sameDir["tasks"]) > 1 + self.sameDir["total"] in [1, 0] + or self.sameDir["total"] > 1 + and len(self.sameDir["tasks"]) > 1 ): await sleep(0.5) async with task_dict_lock: if ( - self.sameDir - and self.sameDir["total"] > 1 - and self.mid in self.sameDir["tasks"] + self.sameDir + and self.sameDir["total"] > 1 + and self.mid in self.sameDir["tasks"] ): self.sameDir["tasks"].remove(self.mid) self.sameDir["total"] -= 1 @@ -177,7 +177,7 @@ async def onDownloadComplete(self): dl = len(non_queued_dl) up = len(non_queued_up) if ( - all_limit and dl + up >= all_limit and (not up_limit or up >= up_limit) + all_limit and dl + up >= all_limit and (not up_limit or up >= up_limit) ) or (up_limit and up >= up_limit): add_to_queue = True LOGGER.info(f"Added to Queue/Upload: {self.name}") @@ -228,14 +228,14 @@ async def onDownloadComplete(self): ) async def onUploadComplete( - self, link, size, files, folders, mime_type, rclonePath="", dir_id="" + self, link, size, files, folders, mime_type, rclonePath="", dir_id="" ): if ( - self.isSuperChat - and config_dict["INCOMPLETE_TASK_NOTIFIER"] - and DATABASE_URL + self.isSuperChat + and config_dict["INCOMPLETE_TASK_NOTIFIER"] + and DATABASE_URL ): - await DbManger().rm_complete_task(self.message.link) + await DbManager().rm_complete_task(self.message.link) msg = f"Name: {escape(self.name)}\n\nSize: {get_readable_file_size(size)}" LOGGER.info(f"Task Done: {self.name}") if self.isLeech: @@ -269,10 +269,10 @@ async def onUploadComplete( msg += f"\nSubFolders: {folders}" msg += f"\nFiles: {files}" if ( - link - or rclonePath - and config_dict["RCLONE_SERVE_URL"] - and not self.privateLink + link + or rclonePath + and config_dict["RCLONE_SERVE_URL"] + and not self.privateLink ): buttons = ButtonMaker() if link: @@ -280,9 +280,9 @@ async def onUploadComplete( else: msg += f"\n\nPath: {rclonePath}" if ( - rclonePath - and (RCLONE_SERVE_URL := config_dict["RCLONE_SERVE_URL"]) - and not self.privateLink + rclonePath + and (RCLONE_SERVE_URL := config_dict["RCLONE_SERVE_URL"]) + and not self.privateLink ): remote, path = rclonePath.split(":", 1) url_path = rutils.quote(f"{path}") @@ -353,11 +353,11 @@ async def onDownloadError(self, error, button=None): await update_status_message(self.message.chat.id) if ( - self.isSuperChat - and config_dict["INCOMPLETE_TASK_NOTIFIER"] - and DATABASE_URL + self.isSuperChat + and config_dict["INCOMPLETE_TASK_NOTIFIER"] + and DATABASE_URL ): - await DbManger().rm_complete_task(self.message.link) + await DbManager().rm_complete_task(self.message.link) async with queue_dict_lock: if self.mid in queued_dl: @@ -389,11 +389,11 @@ async def onUploadError(self, error): await update_status_message(self.message.chat.id) if ( - self.isSuperChat - and config_dict["INCOMPLETE_TASK_NOTIFIER"] - and DATABASE_URL + self.isSuperChat + and config_dict["INCOMPLETE_TASK_NOTIFIER"] + and DATABASE_URL ): - await DbManger().rm_complete_task(self.message.link) + await DbManager().rm_complete_task(self.message.link) async with queue_dict_lock: if self.mid in queued_dl: diff --git a/bot/helper/mirror_utils/download_utils/aria2_download.py b/bot/helper/mirror_utils/download_utils/aria2_download.py index aa0fe04f001..e9fb4447fb8 100644 --- a/bot/helper/mirror_utils/download_utils/aria2_download.py +++ b/bot/helper/mirror_utils/download_utils/aria2_download.py @@ -1,9 +1,5 @@ from aiofiles.os import remove, path as aiopath -from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async -from bot.helper.mirror_utils.status_utils.aria2_status import Aria2Status -from bot.helper.telegram_helper.message_utils import sendStatusMessage, sendMessage -from bot.helper.ext_utils.task_manager import is_queued from bot import ( aria2, task_dict_lock, @@ -15,6 +11,10 @@ non_queued_dl, queue_dict_lock, ) +from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async +from bot.helper.ext_utils.task_manager import is_queued +from bot.helper.mirror_utils.status_utils.aria2_status import Aria2Status +from bot.helper.telegram_helper.message_utils import sendStatusMessage, sendMessage async def add_aria2c_download(listener, dpath, header, ratio, seed_time): @@ -67,9 +67,9 @@ async def add_aria2c_download(listener, dpath, header, ratio, seed_time): await listener.onDownloadStart() if ( - not add_to_queue - and (not listener.select or not config_dict["BASE_URL"]) - and listener.multi <= 1 + not add_to_queue + and (not listener.select or not config_dict["BASE_URL"]) + and listener.multi <= 1 ): await sendStatusMessage(listener.message) elif listener.select and download.is_torrent and not download.is_metadata: diff --git a/bot/helper/mirror_utils/download_utils/direct_downloader.py b/bot/helper/mirror_utils/download_utils/direct_downloader.py index 4a4f26932b8..dd2cce23afb 100644 --- a/bot/helper/mirror_utils/download_utils/direct_downloader.py +++ b/bot/helper/mirror_utils/download_utils/direct_downloader.py @@ -1,11 +1,5 @@ from secrets import token_urlsafe -from bot.helper.ext_utils.bot_utils import sync_to_async -from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check -from bot.helper.listeners.direct_listener import DirectListener -from bot.helper.mirror_utils.status_utils.direct_status import DirectStatus -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus -from bot.helper.telegram_helper.message_utils import sendStatusMessage from bot import ( LOGGER, aria2_options, @@ -15,6 +9,12 @@ non_queued_dl, queue_dict_lock, ) +from bot.helper.ext_utils.bot_utils import sync_to_async +from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check +from bot.helper.listeners.direct_listener import DirectListener +from bot.helper.mirror_utils.status_utils.direct_status import DirectStatus +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.telegram_helper.message_utils import sendStatusMessage async def add_direct_download(listener, path): diff --git a/bot/helper/mirror_utils/download_utils/direct_link_generator.py b/bot/helper/mirror_utils/download_utils/direct_link_generator.py index db555f30f03..d863e278b72 100644 --- a/bot/helper/mirror_utils/download_utils/direct_link_generator.py +++ b/bot/helper/mirror_utils/download_utils/direct_link_generator.py @@ -1,23 +1,23 @@ +from cloudscraper import create_scraper from hashlib import sha256 from http.cookiejar import MozillaCookieJar from json import loads +from lxml.etree import HTML from os import path as ospath from re import findall, match, search -from time import sleep -from urllib.parse import parse_qs, urlparse -from uuid import uuid4 -from cloudscraper import create_scraper -from lxml.etree import HTML from requests import Session, post from requests import session as req_session from requests.adapters import HTTPAdapter +from time import sleep +from urllib.parse import parse_qs, urlparse from urllib3.util.retry import Retry +from uuid import uuid4 from bot import config_dict -from bot.helper.ext_utils.status_utils import speed_string_to_bytes -from bot.helper.ext_utils.links_utils import is_share_link from bot.helper.ext_utils.exceptions import DirectDownloadLinkException from bot.helper.ext_utils.help_messages import PASSWORD_ERROR_MESSAGE +from bot.helper.ext_utils.links_utils import is_share_link +from bot.helper.ext_utils.status_utils import speed_string_to_bytes _caches = {} @@ -68,74 +68,74 @@ def direct_link_generator(link): elif any(x in domain for x in ["akmfiles.com", "akmfls.xyz"]): return akmfiles(link) elif any( - x in domain - for x in [ - "dood.watch", - "doodstream.com", - "dood.to", - "dood.so", - "dood.cx", - "dood.la", - "dood.ws", - "dood.sh", - "doodstream.co", - "dood.pm", - "dood.wf", - "dood.re", - "dood.video", - "dooood.com", - "dood.yt", - "doods.yt", - "dood.stream", - "doods.pro", - "ds2play.com", - ] + x in domain + for x in [ + "dood.watch", + "doodstream.com", + "dood.to", + "dood.so", + "dood.cx", + "dood.la", + "dood.ws", + "dood.sh", + "doodstream.co", + "dood.pm", + "dood.wf", + "dood.re", + "dood.video", + "dooood.com", + "dood.yt", + "doods.yt", + "dood.stream", + "doods.pro", + "ds2play.com", + ] ): return doods(link) elif any( - x in domain - for x in [ - "streamtape.com", - "streamtape.co", - "streamtape.cc", - "streamtape.to", - "streamtape.net", - "streamta.pe", - "streamtape.xyz", - ] + x in domain + for x in [ + "streamtape.com", + "streamtape.co", + "streamtape.cc", + "streamtape.to", + "streamtape.net", + "streamta.pe", + "streamtape.xyz", + ] ): return streamtape(link) elif any(x in domain for x in ["wetransfer.com", "we.tl"]): return wetransfer(link) elif any( - x in domain - for x in [ - "terabox.com", - "nephobox.com", - "4funbox.com", - "mirrobox.com", - "momerybox.com", - "teraboxapp.com", - "1024tera.com", - "terabox.app", - ] + x in domain + for x in [ + "terabox.com", + "nephobox.com", + "4funbox.com", + "mirrobox.com", + "momerybox.com", + "teraboxapp.com", + "1024tera.com", + "terabox.app", + ] ): return terabox(link) elif any( - x in domain - for x in [ - "filelions.co", - "filelions.site", - "filelions.live", - "filelions.to", - "cabecabean.lol", - "filelions.online", - "embedwish.com", - "streamwish.com", - "kitabmarkaz.xyz", - "wishfast.top", - "streamwish.to", - ] + x in domain + for x in [ + "filelions.co", + "filelions.site", + "filelions.live", + "filelions.to", + "cabecabean.lol", + "filelions.online", + "embedwish.com", + "streamwish.com", + "kitabmarkaz.xyz", + "wishfast.top", + "streamwish.to", + ] ): return filelions_and_streamwish(link) elif any(x in domain for x in ["streamhub.ink", "streamhub.to"]): @@ -150,26 +150,26 @@ def direct_link_generator(link): else: return sharer_scraper(link) elif any( - x in domain - for x in [ - "anonfiles.com", - "zippyshare.com", - "letsupload.io", - "hotfile.io", - "bayfiles.com", - "megaupload.nz", - "letsupload.cc", - "filechan.org", - "myfile.is", - "vshare.is", - "rapidshare.nu", - "lolabits.se", - "openload.cc", - "share-online.is", - "upvid.cc", - "uptobox.com", - "uptobox.fr", - ] + x in domain + for x in [ + "anonfiles.com", + "zippyshare.com", + "letsupload.io", + "hotfile.io", + "bayfiles.com", + "megaupload.nz", + "letsupload.cc", + "filechan.org", + "myfile.is", + "vshare.is", + "rapidshare.nu", + "lolabits.se", + "openload.cc", + "share-online.is", + "upvid.cc", + "uptobox.com", + "uptobox.fr", + ] ): raise DirectDownloadLinkException(f"ERROR: R.I.P {domain}") else: @@ -193,7 +193,7 @@ def mediafire(url, session=None): if "/folder/" in url: return mediafireFolder(url) if final_link := findall( - r"https?:\/\/download\d+\.mediafire\.com\/\S+\/\S+\/\S+", url + r"https?:\/\/download\d+\.mediafire\.com\/\S+\/\S+\/\S+", url ): return final_link[0] if session is None: @@ -614,7 +614,7 @@ def gdtot(url): except Exception as e: raise DirectDownloadLinkException(f"ERROR: {e.__class__.__name__}") from e if ( - drive_link := findall(r"myDl\('(.*?)'\)", res.text) + drive_link := findall(r"myDl\('(.*?)'\)", res.text) ) and "drive.google.com" in drive_link[0]: return drive_link[0] else: @@ -684,7 +684,7 @@ def sharer_scraper(url): except Exception as e: raise DirectDownloadLinkException(f"ERROR: {e.__class__.__name__}") from e if ( - drive_link := HTML(res.text).xpath("//a[contains(@class,'btn')]/@href") + drive_link := HTML(res.text).xpath("//a[contains(@class,'btn')]/@href") ) and "drive.google.com" in drive_link[0]: return drive_link[0] else: @@ -833,7 +833,7 @@ def __fetch_links(session, _id=0, folderPath=""): folderPath = details["title"] filename = content["name"] if (sub_type := content.get("sub_type")) and not filename.endswith( - sub_type + sub_type ): filename += f".{sub_type}" item = { @@ -1269,16 +1269,16 @@ def easyupload(url): raise DirectDownloadLinkException(f"ERROR: {e.__class__.__name__}") first_page_html = HTML(_res.text) if ( - first_page_html.xpath("//h6[contains(text(),'Password Protected')]") - and not _password + first_page_html.xpath("//h6[contains(text(),'Password Protected')]") + and not _password ): raise DirectDownloadLinkException( f"ERROR:\n{PASSWORD_ERROR_MESSAGE.format(url)}" ) if not ( - match := search( - r"https://eu(?:[1-9][0-9]?|100)\.easyupload\.io/action\.php", _res.text - ) + match := search( + r"https://eu(?:[1-9][0-9]?|100)\.easyupload\.io/action\.php", _res.text + ) ): raise DirectDownloadLinkException( "ERROR: Failed to get server for EasyUpload Link" @@ -1323,27 +1323,27 @@ def filelions_and_streamwish(url): hostname = parsed_url.hostname scheme = parsed_url.scheme if any( - x in hostname - for x in [ - "filelions.co", - "filelions.live", - "filelions.to", - "filelions.site", - "cabecabean.lol", - "filelions.online", - ] + x in hostname + for x in [ + "filelions.co", + "filelions.live", + "filelions.to", + "filelions.site", + "cabecabean.lol", + "filelions.online", + ] ): apiKey = config_dict["FILELION_API"] apiUrl = "https://api.filelions.co" elif any( - x in hostname - for x in [ - "embedwish.com", - "streamwish.com", - "kitabmarkaz.xyz", - "wishfast.top", - "streamwish.to", - ] + x in hostname + for x in [ + "embedwish.com", + "streamwish.com", + "kitabmarkaz.xyz", + "wishfast.top", + "streamwish.to", + ] ): apiKey = config_dict["STREAMWISH_API"] apiUrl = "https://api.streamwish.com" @@ -1411,12 +1411,12 @@ def streamvid(url: str): f"ERROR: {e.__class__.__name__}" ) from e if not ( - script := html.xpath( - '//script[contains(text(),"document.location.href")]/text()' - ) + script := html.xpath( + '//script[contains(text(),"document.location.href")]/text()' + ) ): if error := html.xpath( - '//div[@class="alert alert-danger"][1]/text()[2]' + '//div[@class="alert alert-danger"][1]/text()[2]' ): raise DirectDownloadLinkException(f"ERROR: {error[0]}") raise DirectDownloadLinkException( @@ -1428,7 +1428,7 @@ def streamvid(url: str): "ERROR: direct link not found! in the script" ) elif (qualities_urls := html.xpath('//div[@id="dl_versions"]/a/@href')) and ( - qualities := html.xpath('//div[@id="dl_versions"]/a/text()[2]') + qualities := html.xpath('//div[@id="dl_versions"]/a/text()[2]') ): error = "\nProvide a quality to download the video\nAvailable Quality:" for quality_url, quality in zip(qualities_urls, qualities): @@ -1461,7 +1461,7 @@ def streamhub(url): except Exception as e: raise DirectDownloadLinkException(f"ERROR: {e.__class__.__name__}") from e if directLink := html.xpath( - '//a[@class="btn btn-primary btn-go downloadbtn"]/@href' + '//a[@class="btn btn-primary btn-go downloadbtn"]/@href' ): return directLink[0] if error := html.xpath('//div[@class="alert alert-danger"]/text()[2]'): @@ -1482,7 +1482,7 @@ def pcloud(url): def tmpsend(url): parsed_url = urlparse(url) - if any(x in parsed_url.path for x in ['thank-you','download']): + if any(x in parsed_url.path for x in ['thank-you', 'download']): query_params = parse_qs(parsed_url.query) if file_id := query_params.get('d'): file_id = file_id[0] diff --git a/bot/helper/mirror_utils/download_utils/direct_link_generator_license.md b/bot/helper/mirror_utils/download_utils/direct_link_generator_license.md index 4dfa2b27dbe..3e1d62680a1 100644 --- a/bot/helper/mirror_utils/download_utils/direct_link_generator_license.md +++ b/bot/helper/mirror_utils/download_utils/direct_link_generator_license.md @@ -1,12 +1,12 @@ RAPHIELSCAPE PUBLIC LICENSE Version 1.c, June 2019 - Copyright (C) 2019 Raphielscape LLC. - Copyright (C) 2019 Devscapes Open Source Holding GmbH. +Copyright (C) 2019 Raphielscape LLC. +Copyright (C) 2019 Devscapes Open Source Holding GmbH. - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. RAPHIELSCAPE PUBLIC LICENSE A-1. DEFINITIONS @@ -25,18 +25,19 @@ 4. Source Form. The “source form” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and - (for an executable work) run the object code and to modify the work, including scripts to control those activities. +The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and +(for an executable work) run the object code and to modify the work, including scripts to control those activities. - The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - The Corresponding Source for a work in source code form is that same work. +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the +Corresponding Source. +The Corresponding Source for a work in source code form is that same work. 5. "The author" refers to "author" of the code, which is the one that made the particular code which exists inside of the Corresponding Source. 6. "Owner" refers to any parties which is made the early form of the Corresponding Source. - A-2. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + A-2. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You must give any other recipients of the Work or Derivative Works a copy of this License; and @@ -48,7 +49,7 @@ 3. Respecting the author and owner of works that are distributed in any way. - You may add Your own copyright statement to Your modifications and may provide +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies @@ -56,7 +57,7 @@ with the conditions stated in this License. B. DISCLAIMER OF WARRANTY - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES @@ -67,14 +68,14 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. C. REVISED VERSION OF THIS LICENSE - The Devscapes Open Source Holding GmbH. may publish revised and/or new versions of the -Raphielscape Public License from time to time. Such new versions will be similar in spirit +The Devscapes Open Source Holding GmbH. may publish revised and/or new versions of the +Raphielscape Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number. If the Program specifies that a +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the Raphielscape Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of -any later version published by the Devscapes Open Source Holding GmbH. If the Program does not specify a +any later version published by the Devscapes Open Source Holding GmbH. If the Program does not specify a version number of the Raphielscape Public License, you may choose any version ever published by the Devscapes Open Source Holding GmbH. diff --git a/bot/helper/mirror_utils/download_utils/gd_download.py b/bot/helper/mirror_utils/download_utils/gd_download.py index 664fce6bb6f..2592d97bdf7 100644 --- a/bot/helper/mirror_utils/download_utils/gd_download.py +++ b/bot/helper/mirror_utils/download_utils/gd_download.py @@ -1,13 +1,13 @@ from secrets import token_urlsafe from bot import task_dict, task_dict_lock, LOGGER, non_queued_dl, queue_dict_lock -from bot.helper.mirror_utils.gdrive_utils.download import gdDownload +from bot.helper.ext_utils.bot_utils import sync_to_async +from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check from bot.helper.mirror_utils.gdrive_utils.count import gdCount +from bot.helper.mirror_utils.gdrive_utils.download import gdDownload from bot.helper.mirror_utils.status_utils.gdrive_status import GdriveStatus from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus from bot.helper.telegram_helper.message_utils import sendStatusMessage -from bot.helper.ext_utils.bot_utils import sync_to_async -from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check async def add_gd_download(listener, path): diff --git a/bot/helper/mirror_utils/download_utils/jd_download.py b/bot/helper/mirror_utils/download_utils/jd_download.py index 87a5c678e24..3adbf54894f 100644 --- a/bot/helper/mirror_utils/download_utils/jd_download.py +++ b/bot/helper/mirror_utils/download_utils/jd_download.py @@ -1,21 +1,8 @@ -from pyrogram.handlers import CallbackQueryHandler -from pyrogram.filters import regex, user -from functools import partial from asyncio import wait_for, Event, wrap_future, sleep +from functools import partial +from pyrogram.filters import regex, user +from pyrogram.handlers import CallbackQueryHandler -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus -from bot.helper.mirror_utils.status_utils.jdownloader_status import JDownloaderStatus -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.bot_utils import new_thread, retry_function -from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check -from bot.helper.ext_utils.jdownloader_booter import jdownloader -from bot.helper.listeners.jdownloader_listener import onDownloadStart -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - sendStatusMessage, - editMessage, - deleteMessage, -) from bot import ( task_dict, task_dict_lock, @@ -25,6 +12,19 @@ jd_lock, jd_downloads, ) +from bot.helper.ext_utils.bot_utils import new_thread, retry_function +from bot.helper.ext_utils.jdownloader_booter import jdownloader +from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check +from bot.helper.listeners.jdownloader_listener import onDownloadStart +from bot.helper.mirror_utils.status_utils.jdownloader_status import JDownloaderStatus +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + sendStatusMessage, + editMessage, + deleteMessage, +) async def configureDownload(_, query, obj): @@ -89,7 +89,7 @@ async def add_jd_download(listener, path): if not jd_downloads: await retry_function(jdownloader.device.linkgrabber.clear_list) if odl := await retry_function( - jdownloader.device.downloads.query_packages, [{}] + jdownloader.device.downloads.query_packages, [{}] ): odl_list = [od["uuid"] for od in odl] await retry_function( @@ -157,7 +157,7 @@ async def add_jd_download(listener, path): if not online_packages: error = ( - name or "Download Not Added! Maybe some issues in jdownloader or site!" + name or "Download Not Added! Maybe some issues in jdownloader or site!" ) await listener.onDownloadError(error) return diff --git a/bot/helper/mirror_utils/download_utils/qbit_download.py b/bot/helper/mirror_utils/download_utils/qbit_download.py index 43960d3d298..b02553fe4c7 100644 --- a/bot/helper/mirror_utils/download_utils/qbit_download.py +++ b/bot/helper/mirror_utils/download_utils/qbit_download.py @@ -1,9 +1,6 @@ -from time import time from aiofiles.os import remove, path as aiopath +from time import time -from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async -from bot.helper.listeners.qbit_listener import onDownloadStart -from bot.helper.ext_utils.task_manager import is_queued from bot import ( task_dict, task_dict_lock, @@ -13,6 +10,9 @@ non_queued_dl, queue_dict_lock, ) +from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async +from bot.helper.ext_utils.task_manager import is_queued +from bot.helper.listeners.qbit_listener import onDownloadStart from bot.helper.mirror_utils.status_utils.qbit_status import QbittorrentStatus from bot.helper.telegram_helper.message_utils import ( sendMessage, diff --git a/bot/helper/mirror_utils/download_utils/rclone_download.py b/bot/helper/mirror_utils/download_utils/rclone_download.py index 8e58dc3c213..a073b35fecd 100644 --- a/bot/helper/mirror_utils/download_utils/rclone_download.py +++ b/bot/helper/mirror_utils/download_utils/rclone_download.py @@ -4,11 +4,11 @@ from bot import task_dict, task_dict_lock, queue_dict_lock, non_queued_dl, LOGGER from bot.helper.ext_utils.bot_utils import cmd_exec -from bot.helper.telegram_helper.message_utils import sendStatusMessage from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check -from bot.helper.mirror_utils.status_utils.rclone_status import RcloneStatus -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus from bot.helper.mirror_utils.rclone_utils.transfer import RcloneTransferHelper +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.mirror_utils.status_utils.rclone_status import RcloneStatus +from bot.helper.telegram_helper.message_utils import sendStatusMessage async def add_rclone_download(listener, path): diff --git a/bot/helper/mirror_utils/download_utils/telegram_download.py b/bot/helper/mirror_utils/download_utils/telegram_download.py index 6bb3ee4a5ff..8dddd3c1085 100644 --- a/bot/helper/mirror_utils/download_utils/telegram_download.py +++ b/bot/helper/mirror_utils/download_utils/telegram_download.py @@ -1,10 +1,6 @@ -from time import time from asyncio import Lock +from time import time -from bot.helper.mirror_utils.status_utils.telegram_status import TelegramStatus -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus -from bot.helper.telegram_helper.message_utils import sendStatusMessage -from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check from bot import ( LOGGER, task_dict, @@ -14,6 +10,10 @@ bot, user, ) +from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.mirror_utils.status_utils.telegram_status import TelegramStatus +from bot.helper.telegram_helper.message_utils import sendStatusMessage global_lock = Lock() GLOBAL_GID = set() @@ -93,8 +93,8 @@ async def _download(self, message, path): async def add_download(self, message, path): if ( - self._listener.session not in ["user", "bot"] - and self._listener.userTransmission + self._listener.session not in ["user", "bot"] + and self._listener.userTransmission ): self._listener.session = "user" message = await user.get_messages( @@ -104,15 +104,15 @@ async def add_download(self, message, path): self._listener.session = "bot" media = ( - message.document - or message.photo - or message.video - or message.audio - or message.voice - or message.video_note - or message.sticker - or message.animation - or None + message.document + or message.photo + or message.video + or message.audio + or message.voice + or message.video_note + or message.sticker + or message.animation + or None ) if media is not None: diff --git a/bot/helper/mirror_utils/download_utils/yt_dlp_download.py b/bot/helper/mirror_utils/download_utils/yt_dlp_download.py index 4d7990e35e0..3925b0922ff 100644 --- a/bot/helper/mirror_utils/download_utils/yt_dlp_download.py +++ b/bot/helper/mirror_utils/download_utils/yt_dlp_download.py @@ -1,15 +1,15 @@ +from logging import getLogger from os import path as ospath, listdir +from re import search as re_search from secrets import token_urlsafe -from logging import getLogger from yt_dlp import YoutubeDL, DownloadError -from re import search as re_search from bot import task_dict_lock, task_dict, non_queued_dl, queue_dict_lock -from bot.helper.telegram_helper.message_utils import sendStatusMessage -from ..status_utils.yt_dlp_download_status import YtDlpDownloadStatus -from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus from bot.helper.ext_utils.bot_utils import sync_to_async, async_to_sync from bot.helper.ext_utils.task_manager import is_queued, stop_duplicate_check +from bot.helper.mirror_utils.status_utils.queue_status import QueueStatus +from bot.helper.telegram_helper.message_utils import sendStatusMessage +from ..status_utils.yt_dlp_download_status import YtDlpDownloadStatus LOGGER = getLogger(__name__) @@ -23,7 +23,7 @@ def debug(self, msg): # Hack to fix changing extension if not self._obj.is_playlist: if match := re_search( - r".Merger..Merging formats into..(.*?).$", msg + r".Merger..Merging formats into..(.*?).$", msg ) or re_search(r".ExtractAudio..Destination..(.*?)$", msg): LOGGER.info(msg) newname = match.group(1) @@ -179,7 +179,7 @@ def _download(self, path): self._onDownloadError(str(e)) return if self.is_playlist and ( - not ospath.exists(path) or len(listdir(path)) == 0 + not ospath.exists(path) or len(listdir(path)) == 0 ): self._onDownloadError( "No video available to download from this playlist. Check logs for more details" @@ -253,17 +253,17 @@ async def add_download(self, path, qual, playlist, options): "thumbnail": f"{path}/yt-dlp-thumb/%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s", } elif any( - key in options - for key in [ - "writedescription", - "writeinfojson", - "writeannotations", - "writedesktoplink", - "writewebloclink", - "writeurllink", - "writesubtitles", - "writeautomaticsub", - ] + key in options + for key in [ + "writedescription", + "writeinfojson", + "writeannotations", + "writedesktoplink", + "writewebloclink", + "writeurllink", + "writesubtitles", + "writeautomaticsub", + ] ): self.opts["outtmpl"] = { "default": f"{path}/{base_name}/{self._listener.name}", diff --git a/bot/helper/mirror_utils/gdrive_utils/clone.py b/bot/helper/mirror_utils/gdrive_utils/clone.py index 23d214d7f4b..fd638828cdb 100644 --- a/bot/helper/mirror_utils/gdrive_utils/clone.py +++ b/bot/helper/mirror_utils/gdrive_utils/clone.py @@ -1,7 +1,6 @@ +from googleapiclient.errors import HttpError from logging import getLogger -from time import time from os import path as ospath -from googleapiclient.errors import HttpError from tenacity import ( retry, wait_exponential, @@ -9,6 +8,7 @@ retry_if_exception_type, RetryError, ) +from time import time from bot.helper.ext_utils.bot_utils import async_to_sync from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper @@ -26,7 +26,7 @@ def __init__(self, listener): def user_setting(self): if self.listener.upDest.startswith("mtp:") or self.listener.link.startswith( - "mtp:" + "mtp:" ): self.token_path = f"tokens/{self.listener.user_id}.pickle" self.listener.upDest = self.listener.upDest.replace("mtp:", "", 1) @@ -35,7 +35,7 @@ def user_setting(self): self.listener.upDest = self.listener.upDest.replave("tp:", "", 1) self.use_sa = False elif self.listener.upDest.startswith("sa:") or self.listener.link.startswith( - "sa:" + "sa:" ): self.listener.upDest = self.listener.upDest.replace("sa:", "", 1) self.use_sa = True @@ -116,9 +116,9 @@ def _cloneFolder(self, folder_name, folder_id, dest_id): current_dir_id = self.create_directory(file.get("name"), dest_id) self._cloneFolder(file_path, file.get("id"), current_dir_id) elif ( - not file.get("name") - .lower() - .endswith(tuple(self.listener.extension_filter)) + not file.get("name") + .lower() + .endswith(tuple(self.listener.extension_filter)) ): self.total_files += 1 self._copyFile(file.get("id"), dest_id) diff --git a/bot/helper/mirror_utils/gdrive_utils/delete.py b/bot/helper/mirror_utils/gdrive_utils/delete.py index 66559b20916..316ac336e28 100644 --- a/bot/helper/mirror_utils/gdrive_utils/delete.py +++ b/bot/helper/mirror_utils/gdrive_utils/delete.py @@ -1,5 +1,5 @@ -from logging import getLogger from googleapiclient.errors import HttpError +from logging import getLogger from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper @@ -25,7 +25,7 @@ def deletefile(self, link, user_id): LOGGER.info(f"Delete Result: {msg}") except HttpError as err: if "File not found" in str(err) or "insufficientFilePermissions" in str( - err + err ): if not self.alt_auth and self.use_sa: self.alt_auth = True diff --git a/bot/helper/mirror_utils/gdrive_utils/download.py b/bot/helper/mirror_utils/gdrive_utils/download.py index 3e13ec87883..7146a1106b8 100644 --- a/bot/helper/mirror_utils/gdrive_utils/download.py +++ b/bot/helper/mirror_utils/gdrive_utils/download.py @@ -1,8 +1,8 @@ -from logging import getLogger -from os import makedirs, path as ospath -from io import FileIO from googleapiclient.errors import HttpError from googleapiclient.http import MediaIoBaseDownload +from io import FileIO +from logging import getLogger +from os import makedirs, path as ospath from tenacity import ( retry, wait_exponential, @@ -11,8 +11,8 @@ RetryError, ) -from bot.helper.ext_utils.bot_utils import setInterval from bot.helper.ext_utils.bot_utils import async_to_sync +from bot.helper.ext_utils.bot_utils import setInterval from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper LOGGER = getLogger(__name__) @@ -83,7 +83,7 @@ def _download_folder(self, folder_id, path, folder_name): if mime_type == self.G_DRIVE_DIR_MIME_TYPE: self._download_folder(file_id, path, filename) elif not ospath.isfile( - f"{path}{filename}" + f"{path}{filename}" ) and not filename.lower().endswith(tuple(self.listener.extension_filter)): self._download_file(file_id, path, filename, mime_type) if self.is_cancelled: diff --git a/bot/helper/mirror_utils/gdrive_utils/helper.py b/bot/helper/mirror_utils/gdrive_utils/helper.py index 179e35e01d6..07fca001ddb 100644 --- a/bot/helper/mirror_utils/gdrive_utils/helper.py +++ b/bot/helper/mirror_utils/gdrive_utils/helper.py @@ -1,17 +1,17 @@ +from google.oauth2 import service_account +from googleapiclient.discovery import build from logging import getLogger, ERROR -from pickle import load as pload from os import path as ospath, listdir -from re import search as re_search -from urllib.parse import parse_qs, urlparse +from pickle import load as pload from random import randrange -from google.oauth2 import service_account -from googleapiclient.discovery import build +from re import search as re_search from tenacity import ( retry, wait_exponential, stop_after_attempt, retry_if_exception_type, ) +from urllib.parse import parse_qs, urlparse from bot import config_dict from bot.helper.ext_utils.links_utils import is_gdrive_id @@ -61,8 +61,8 @@ def processed_bytes(self): async def progress(self): if self.status is not None: chunk_size = ( - self.status.total_size * self.status.progress() - - self.file_processed_bytes + self.status.total_size * self.status.progress() + - self.file_processed_bytes ) self.file_processed_bytes = self.status.total_size * self.status.progress() self.proc_bytes += chunk_size diff --git a/bot/helper/mirror_utils/gdrive_utils/list.py b/bot/helper/mirror_utils/gdrive_utils/list.py index 98dc37f32e3..c20b9861386 100644 --- a/bot/helper/mirror_utils/gdrive_utils/list.py +++ b/bot/helper/mirror_utils/gdrive_utils/list.py @@ -1,18 +1,18 @@ -from logging import getLogger -from asyncio import wait_for, Event, wrap_future, gather from aiofiles.os import path as aiopath -from pyrogram.handlers import CallbackQueryHandler -from pyrogram.filters import regex, user +from asyncio import wait_for, Event, wrap_future, gather from functools import partial -from time import time -from tenacity import RetryError +from logging import getLogger from natsort import natsorted +from pyrogram.filters import regex, user +from pyrogram.handlers import CallbackQueryHandler +from tenacity import RetryError +from time import time from bot import config_dict from bot.helper.ext_utils.bot_utils import new_thread, new_task, update_user_ldata -from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper +from bot.helper.ext_utils.db_handler import DbManager from bot.helper.ext_utils.status_utils import get_readable_file_size, get_readable_time -from bot.helper.ext_utils.db_handler import DbManger +from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper from bot.helper.telegram_helper.button_build import ButtonMaker from bot.helper.telegram_helper.message_utils import ( sendMessage, @@ -20,10 +20,8 @@ deleteMessage, ) - LOGGER = getLogger(__name__) - LIST_LIMIT = 6 @@ -89,7 +87,7 @@ async def id_updates(_, query, obj): update_user_ldata(obj.listener.user_id, "gdrive_id", id_) await obj.get_items_buttons() if config_dict["DATABASE_URL"]: - await DbManger().update_user_data(obj.listener.user_id) + await DbManager().update_user_data(obj.listener.user_id) elif data[1] == "owner": obj.token_path = "token.pickle" obj.use_sa = False @@ -168,7 +166,7 @@ async def get_items_buttons(self): page = (self.iter_start / LIST_LIMIT) + 1 if self.iter_start != 0 else 1 buttons = ButtonMaker() for index, item in enumerate( - self.items_list[self.iter_start : LIST_LIMIT + self.iter_start] + self.items_list[self.iter_start: LIST_LIMIT + self.iter_start] ): orig_index = index + self.iter_start if item["mimeType"] == self.G_DRIVE_DIR_MIME_TYPE: @@ -193,10 +191,10 @@ async def get_items_buttons(self): if self.list_status == "gdu": buttons.ibutton("Set as Default Path", "gdq def", position="footer") if ( - len(self.parents) > 1 - and len(self.drives) > 1 - or self._token_user - and self._token_owner + len(self.parents) > 1 + and len(self.drives) > 1 + or self._token_user + and self._token_owner ): buttons.ibutton("Back", "gdq back pa", position="footer") if len(self.parents) > 1: @@ -210,7 +208,7 @@ async def get_items_buttons(self): ) if self.list_status == "gdu": default_id = ( - self.listener.user_dict.get("gdrive_id") or config_dict["GDRIVE_ID"] + self.listener.user_dict.get("gdrive_id") or config_dict["GDRIVE_ID"] ) msg += f"\nDefault Gdrive ID: {default_id}" if default_id else "" msg += f"\n\nItems: {items_no}" @@ -219,7 +217,7 @@ async def get_items_buttons(self): msg += f"\n\nItem Type: {self.item_type}\nToken Path: {self.token_path}" msg += f"\n\nCurrent ID: {self.id}" msg += f"\nCurrent Path: {('/').join(i['name'] for i in self.parents)}" - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await self._send_list_message(msg, button) async def get_items(self, itype=""): @@ -279,7 +277,7 @@ async def list_drives(self): else "\nTransfer Type: Upload" ) msg += f"\nToken Path: {self.token_path}" - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" buttons = ButtonMaker() self.drives.clear() self.parents.clear() @@ -297,19 +295,19 @@ async def list_drives(self): async def choose_token(self): if ( - self._token_user - and self._token_owner - or self._sa_owner - and self._token_owner - or self._sa_owner - and self._token_user + self._token_user + and self._token_owner + or self._sa_owner + and self._token_owner + or self._sa_owner + and self._token_user ): msg = "Choose Token:" + ( "\nTransfer Type: Download" if self.list_status == "gdd" else "\nTransfer Type: Upload" ) - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" buttons = ButtonMaker() if self._token_owner: buttons.ibutton("Owner Token", "gdq owner") diff --git a/bot/helper/mirror_utils/gdrive_utils/search.py b/bot/helper/mirror_utils/gdrive_utils/search.py index 1790ba56e28..8ff377729c2 100644 --- a/bot/helper/mirror_utils/gdrive_utils/search.py +++ b/bot/helper/mirror_utils/gdrive_utils/search.py @@ -112,9 +112,9 @@ def drive_list(self, fileName, target_id="", user_id=""): else: drives = zip(DRIVES_NAMES, DRIVES_IDS, INDEX_URLS) if ( - not target_id.startswith("mtp:") - and len(DRIVES_IDS) > 1 - or target_id.startswith("tp:") + not target_id.startswith("mtp:") + and len(DRIVES_IDS) > 1 + or target_id.startswith("tp:") ): self.use_sa = False diff --git a/bot/helper/mirror_utils/gdrive_utils/upload.py b/bot/helper/mirror_utils/gdrive_utils/upload.py index 9762ef5442d..d855cb9c1ff 100644 --- a/bot/helper/mirror_utils/gdrive_utils/upload.py +++ b/bot/helper/mirror_utils/gdrive_utils/upload.py @@ -1,7 +1,7 @@ -from logging import getLogger -from os import path as ospath, listdir, remove from googleapiclient.errors import HttpError from googleapiclient.http import MediaFileUpload +from logging import getLogger +from os import path as ospath, listdir, remove from tenacity import ( retry, wait_exponential, @@ -11,8 +11,8 @@ ) from bot import config_dict -from bot.helper.ext_utils.files_utils import get_mime_type from bot.helper.ext_utils.bot_utils import async_to_sync, setInterval +from bot.helper.ext_utils.files_utils import get_mime_type from bot.helper.mirror_utils.gdrive_utils.helper import GoogleDriveHelper LOGGER = getLogger(__name__) diff --git a/bot/helper/mirror_utils/rclone_utils/list.py b/bot/helper/mirror_utils/rclone_utils/list.py index b1499493055..99a9dc98248 100644 --- a/bot/helper/mirror_utils/rclone_utils/list.py +++ b/bot/helper/mirror_utils/rclone_utils/list.py @@ -1,28 +1,28 @@ -from asyncio import wait_for, Event, wrap_future, gather -from aiofiles.os import path as aiopath from aiofiles import open as aiopen +from aiofiles.os import path as aiopath +from asyncio import wait_for, Event, wrap_future, gather from configparser import ConfigParser -from pyrogram.handlers import CallbackQueryHandler -from pyrogram.filters import regex, user from functools import partial from json import loads +from pyrogram.filters import regex, user +from pyrogram.handlers import CallbackQueryHandler from time import time from bot import LOGGER, config_dict -from bot.helper.ext_utils.db_handler import DbManger -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.status_utils import get_readable_file_size, get_readable_time -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - editMessage, - deleteMessage, -) from bot.helper.ext_utils.bot_utils import ( cmd_exec, new_thread, new_task, update_user_ldata, ) +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.ext_utils.status_utils import get_readable_file_size, get_readable_time +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + editMessage, + deleteMessage, +) LIST_LIMIT = 6 @@ -94,7 +94,7 @@ async def path_updates(_, query, obj): update_user_ldata(obj.listener.user_id, "rclone_path", path) await obj.get_path_buttons() if config_dict["DATABASE_URL"]: - await DbManger().update_user_data(obj.listener.user_id) + await DbManager().update_user_data(obj.listener.user_id) elif data[1] == "owner": obj.config_path = "rclone.conf" obj.path = "" @@ -166,7 +166,7 @@ async def get_path_buttons(self): page = (self.iter_start / LIST_LIMIT) + 1 if self.iter_start != 0 else 1 buttons = ButtonMaker() for index, idict in enumerate( - self.path_list[self.iter_start : LIST_LIMIT + self.iter_start] + self.path_list[self.iter_start: LIST_LIMIT + self.iter_start] ): orig_index = index + self.iter_start if idict["IsDir"]: @@ -209,7 +209,7 @@ async def get_path_buttons(self): msg += f" | Page: {int(page)}/{pages} | Page Step: {self.page_step}" msg += f"\n\nItem Type: {self.item_type}\nConfig Path: {self.config_path}" msg += f"\nCurrent Path: {self.remote}{self.path}" - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await self._send_list_message(msg, button) async def get_path(self, itype=""): @@ -268,7 +268,7 @@ async def list_remotes(self): else "\nTransfer Type: Upload" ) msg += f"\nConfig Path: {self.config_path}" - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" buttons = ButtonMaker() for remote in self._sections: buttons.ibutton(remote, f"rcq re {remote}:") @@ -285,7 +285,7 @@ async def list_config(self): if self.list_status == "rcd" else "\nTransfer Type: Upload" ) - msg += f"\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg += f"\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" buttons = ButtonMaker() buttons.ibutton("Owner Config", "rcq owner") buttons.ibutton("My Config", "rcq user") diff --git a/bot/helper/mirror_utils/rclone_utils/serve.py b/bot/helper/mirror_utils/rclone_utils/serve.py index 029519e531a..20097e4e2d0 100644 --- a/bot/helper/mirror_utils/rclone_utils/serve.py +++ b/bot/helper/mirror_utils/rclone_utils/serve.py @@ -1,6 +1,6 @@ -from asyncio import create_subprocess_exec -from aiofiles.os import path as aiopath from aiofiles import open as aiopen +from aiofiles.os import path as aiopath +from asyncio import create_subprocess_exec from configparser import ConfigParser from bot import config_dict @@ -52,7 +52,7 @@ async def rclone_serve_booter(): "64M", ] if (user := config_dict["RCLONE_SERVE_USER"]) and ( - pswd := config_dict["RCLONE_SERVE_PASS"] + pswd := config_dict["RCLONE_SERVE_PASS"] ): cmd.extend(("--user", user, "--pass", pswd)) rcs = await create_subprocess_exec(*cmd) diff --git a/bot/helper/mirror_utils/rclone_utils/transfer.py b/bot/helper/mirror_utils/rclone_utils/transfer.py index 7b0c1f79d8e..14aa2ed7d41 100644 --- a/bot/helper/mirror_utils/rclone_utils/transfer.py +++ b/bot/helper/mirror_utils/rclone_utils/transfer.py @@ -1,18 +1,17 @@ +from aiofiles import open as aiopen +from aiofiles.os import path as aiopath, makedirs, listdir from asyncio import create_subprocess_exec, gather from asyncio.subprocess import PIPE -from re import findall as re_findall -from json import loads -from aiofiles.os import path as aiopath, makedirs, listdir -from aiofiles import open as aiopen from configparser import ConfigParser -from random import randrange +from json import loads from logging import getLogger +from random import randrange +from re import findall as re_findall from bot import config_dict from bot.helper.ext_utils.bot_utils import cmd_exec, sync_to_async from bot.helper.ext_utils.files_utils import get_mime_type, count_files_and_folders - LOGGER = getLogger(__name__) @@ -61,8 +60,8 @@ async def _progress(self): if not data: break if data := re_findall( - r"Transferred:\s+([\d.]+\s*\w+)\s+/\s+([\d.]+\s*\w+),\s+([\d.]+%)\s*,\s+([\d.]+\s*\w+/s),\s+ETA\s+([\dwdhms]+)", - data, + r"Transferred:\s+([\d.]+\s*\w+)\s+/\s+([\d.]+\s*\w+),\s+([\d.]+%)\s*,\s+([\d.]+\s*\w+/s),\s+ETA\s+([\dwdhms]+)", + data, ): ( self._transferred_size, @@ -118,18 +117,18 @@ async def _start_download(self, cmd, remote_type): elif return_code != -9: error = (await self._proc.stderr.read()).decode().strip() if ( - not error - and remote_type == "drive" - and config_dict["USE_SERVICE_ACCOUNTS"] + not error + and remote_type == "drive" + and config_dict["USE_SERVICE_ACCOUNTS"] ): error = "Mostly your service accounts don't have access to this drive!" LOGGER.error(error) if ( - self._sa_number != 0 - and remote_type == "drive" - and "RATE_LIMIT_EXCEEDED" in error - and config_dict["USE_SERVICE_ACCOUNTS"] + self._sa_number != 0 + and remote_type == "drive" + and "RATE_LIMIT_EXCEEDED" in error + and config_dict["USE_SERVICE_ACCOUNTS"] ): if self._sa_count < self._sa_number: remote = self._switchServiceAccount() @@ -154,11 +153,11 @@ async def download(self, remote, config_path, path): remote_type = remote_opts["type"] if ( - remote_type == "drive" - and config_dict["USE_SERVICE_ACCOUNTS"] - and config_path == "rclone.conf" - and await aiopath.isdir("accounts") - and not remote_opts.get("service_account_file") + remote_type == "drive" + and config_dict["USE_SERVICE_ACCOUNTS"] + and config_path == "rclone.conf" + and await aiopath.isdir("accounts") + and not remote_opts.get("service_account_file") ): config_path = await self._create_rc_sa(remote, remote_opts) if config_path != "rclone.conf": @@ -173,9 +172,9 @@ async def download(self, remote, config_path, path): ) if ( - remote_type == "drive" - and not config_dict["RCLONE_FLAGS"] - and not self._listener.rcFlags + remote_type == "drive" + and not config_dict["RCLONE_FLAGS"] + and not self._listener.rcFlags ): cmd.append("--drive-acknowledge-abuse") elif remote_type != "drive": @@ -236,17 +235,17 @@ async def _start_upload(self, cmd, remote_type): elif return_code != 0: error = (await self._proc.stderr.read()).decode().strip() if ( - not error - and remote_type == "drive" - and config_dict["USE_SERVICE_ACCOUNTS"] + not error + and remote_type == "drive" + and config_dict["USE_SERVICE_ACCOUNTS"] ): error = "Mostly your service accounts don't have access to this drive!" LOGGER.error(error) if ( - self._sa_number != 0 - and remote_type == "drive" - and "RATE_LIMIT_EXCEEDED" in error - and config_dict["USE_SERVICE_ACCOUNTS"] + self._sa_number != 0 + and remote_type == "drive" + and "RATE_LIMIT_EXCEEDED" in error + and config_dict["USE_SERVICE_ACCOUNTS"] ): if self._sa_count < self._sa_number: remote = self._switchServiceAccount() @@ -302,11 +301,11 @@ async def upload(self, path, size): fremote = oremote fconfig_path = oconfig_path if ( - remote_type == "drive" - and config_dict["USE_SERVICE_ACCOUNTS"] - and fconfig_path == "rclone.conf" - and await aiopath.isdir("accounts") - and not remote_opts.get("service_account_file") + remote_type == "drive" + and config_dict["USE_SERVICE_ACCOUNTS"] + and fconfig_path == "rclone.conf" + and await aiopath.isdir("accounts") + and not remote_opts.get("service_account_file") ): fconfig_path = await self._create_rc_sa(oremote, remote_opts) if fconfig_path != "rclone.conf": @@ -321,9 +320,9 @@ async def upload(self, path, size): fconfig_path, path, f"{fremote}:{rc_path}", method ) if ( - remote_type == "drive" - and not config_dict["RCLONE_FLAGS"] - and not self._listener.rcFlags + remote_type == "drive" + and not config_dict["RCLONE_FLAGS"] + and not self._listener.rcFlags ): cmd.extend(("--drive-chunk-size", "128M", "--drive-upload-cutoff", "128M")) diff --git a/bot/helper/mirror_utils/status_utils/aria2_status.py b/bot/helper/mirror_utils/status_utils/aria2_status.py index f212ec536ca..ccca2b09cac 100644 --- a/bot/helper/mirror_utils/status_utils/aria2_status.py +++ b/bot/helper/mirror_utils/status_utils/aria2_status.py @@ -1,8 +1,8 @@ from time import time from bot import aria2, LOGGER -from bot.helper.ext_utils.status_utils import MirrorStatus, get_readable_time from bot.helper.ext_utils.bot_utils import sync_to_async +from bot.helper.ext_utils.status_utils import MirrorStatus, get_readable_time def get_download(gid, old_info=None): diff --git a/bot/helper/mirror_utils/status_utils/direct_status.py b/bot/helper/mirror_utils/status_utils/direct_status.py index 133c3d1036a..021c41b2ec5 100644 --- a/bot/helper/mirror_utils/status_utils/direct_status.py +++ b/bot/helper/mirror_utils/status_utils/direct_status.py @@ -35,8 +35,8 @@ def size(self): def eta(self): try: seconds = ( - self._obj.total_size - self._obj.processed_bytes - ) / self._obj.speed + self._obj.total_size - self._obj.processed_bytes + ) / self._obj.speed return get_readable_time(seconds) except: return "-" diff --git a/bot/helper/mirror_utils/status_utils/extract_status.py b/bot/helper/mirror_utils/status_utils/extract_status.py index 958cc9b36be..f206dfd8a7e 100644 --- a/bot/helper/mirror_utils/status_utils/extract_status.py +++ b/bot/helper/mirror_utils/status_utils/extract_status.py @@ -1,8 +1,8 @@ from time import time -from bot.helper.ext_utils.files_utils import get_path_size -from bot.helper.ext_utils.bot_utils import async_to_sync from bot import LOGGER, subprocess_lock +from bot.helper.ext_utils.bot_utils import async_to_sync +from bot.helper.ext_utils.files_utils import get_path_size from bot.helper.ext_utils.status_utils import ( get_readable_file_size, MirrorStatus, @@ -67,8 +67,8 @@ async def cancel_task(self): LOGGER.info(f"Cancelling Extract: {self.listener.name}") async with subprocess_lock: if ( - self.listener.suproc is not None - and self.listener.suproc.returncode is None + self.listener.suproc is not None + and self.listener.suproc.returncode is None ): self.listener.suproc.kill() else: diff --git a/bot/helper/mirror_utils/status_utils/jdownloader_status.py b/bot/helper/mirror_utils/status_utils/jdownloader_status.py index 409d5b4e244..d912423c147 100644 --- a/bot/helper/mirror_utils/status_utils/jdownloader_status.py +++ b/bot/helper/mirror_utils/status_utils/jdownloader_status.py @@ -1,8 +1,8 @@ from time import time from bot import LOGGER, jd_lock, jd_downloads -from bot.helper.ext_utils.jdownloader_booter import jdownloader from bot.helper.ext_utils.bot_utils import retry_function +from bot.helper.ext_utils.jdownloader_booter import jdownloader from bot.helper.ext_utils.status_utils import ( MirrorStatus, get_readable_file_size, diff --git a/bot/helper/mirror_utils/status_utils/qbit_status.py b/bot/helper/mirror_utils/status_utils/qbit_status.py index 0902db4aa2e..51b8a73d627 100644 --- a/bot/helper/mirror_utils/status_utils/qbit_status.py +++ b/bot/helper/mirror_utils/status_utils/qbit_status.py @@ -29,7 +29,7 @@ def _update(self): self._info = get_download(self.client, f"{self.listener.mid}", self._info) def progress(self): - return f"{round(self._info.progress*100, 2)}%" + return f"{round(self._info.progress * 100, 2)}%" def processed_bytes(self): return get_readable_file_size(self._info.downloaded) diff --git a/bot/helper/mirror_utils/status_utils/split_status.py b/bot/helper/mirror_utils/status_utils/split_status.py index 3b6f4d30a0e..eda3e5418c7 100644 --- a/bot/helper/mirror_utils/status_utils/split_status.py +++ b/bot/helper/mirror_utils/status_utils/split_status.py @@ -39,8 +39,8 @@ async def cancel_task(self): LOGGER.info(f"Cancelling Split: {self.listener.name}") async with subprocess_lock: if ( - self.listener.suproc is not None - and self.listener.suproc.returncode is None + self.listener.suproc is not None + and self.listener.suproc.returncode is None ): self.listener.suproc.kill() else: diff --git a/bot/helper/mirror_utils/status_utils/zip_status.py b/bot/helper/mirror_utils/status_utils/zip_status.py index 3bc1742afab..1f9b9165ed7 100644 --- a/bot/helper/mirror_utils/status_utils/zip_status.py +++ b/bot/helper/mirror_utils/status_utils/zip_status.py @@ -67,8 +67,8 @@ async def cancel_task(self): LOGGER.info(f"Cancelling Archive: {self.listener.name}") async with subprocess_lock: if ( - self.listener.suproc is not None - and self.listener.suproc.returncode is None + self.listener.suproc is not None + and self.listener.suproc.returncode is None ): self.listener.suproc.kill() else: diff --git a/bot/helper/mirror_utils/telegram_uploader.py b/bot/helper/mirror_utils/telegram_uploader.py index 28994359f4f..67adb7d00c0 100644 --- a/bot/helper/mirror_utils/telegram_uploader.py +++ b/bot/helper/mirror_utils/telegram_uploader.py @@ -1,19 +1,18 @@ -from logging import getLogger +from PIL import Image from aiofiles.os import ( remove, path as aiopath, rename, makedirs, ) +from aioshutil import copy +from asyncio import sleep +from logging import getLogger +from natsort import natsorted from os import walk, path as ospath -from time import time -from PIL import Image -from pyrogram.types import InputMediaVideo, InputMediaDocument, InputMediaPhoto from pyrogram.errors import FloodWait, RPCError -from asyncio import sleep +from pyrogram.types import InputMediaVideo, InputMediaDocument, InputMediaPhoto from re import match as re_match, sub as re_sub -from natsort import natsorted -from aioshutil import copy from tenacity import ( retry, wait_exponential, @@ -21,11 +20,11 @@ retry_if_exception_type, RetryError, ) +from time import time from bot import config_dict, user -from bot.helper.ext_utils.files_utils import clean_unwanted, is_archive, get_base_name from bot.helper.ext_utils.bot_utils import sync_to_async -from bot.helper.telegram_helper.message_utils import deleteMessage +from bot.helper.ext_utils.files_utils import clean_unwanted, is_archive, get_base_name from bot.helper.ext_utils.media_utils import ( get_media_info, get_document_type, @@ -33,6 +32,7 @@ get_audio_thumb, take_ss, ) +from bot.helper.telegram_helper.message_utils import deleteMessage LOGGER = getLogger(__name__) @@ -125,9 +125,9 @@ async def _prepare_file(self, file_, dirpath): cap_mono = f"{self._lprefix} {file_}" self._lprefix = re_sub("<.*?>", "", self._lprefix) if ( - self._listener.seed - and not self._listener.newDir - and not dirpath.endswith("/splited_files_mltb") + self._listener.seed + and not self._listener.newDir + and not dirpath.endswith("/splited_files_mltb") ): dirpath = f"{dirpath}/copied_mltb" await makedirs(dirpath, exist_ok=True) @@ -156,9 +156,9 @@ async def _prepare_file(self, file_, dirpath): remain = 60 - extn name = name[:remain] if ( - self._listener.seed - and not self._listener.newDir - and not dirpath.endswith("/splited_files_mltb") + self._listener.seed + and not self._listener.newDir + and not dirpath.endswith("/splited_files_mltb") ): dirpath = f"{dirpath}/copied_mltb" await makedirs(dirpath, exist_ok=True) @@ -271,7 +271,7 @@ async def upload(self, o_files, m_size, size): if self._is_cancelled: return if not self._is_corrupted and ( - self._listener.isSuperChat or self._listener.upDest + self._listener.isSuperChat or self._listener.upDest ): self._msgs_dict[self._sent_msg.link] = file_ await sleep(1) @@ -288,14 +288,14 @@ async def upload(self, o_files, m_size, size): continue finally: if ( - not self._is_cancelled - and await aiopath.exists(self._up_path) - and ( + not self._is_cancelled + and await aiopath.exists(self._up_path) + and ( not self._listener.seed or self._listener.newDir or dirpath.endswith("/splited_files_mltb") or "/copied_mltb/" in self._up_path - ) + ) ): await remove(self._up_path) for key, value in list(self._media_dict.items()): @@ -348,9 +348,9 @@ async def _upload_file(self, cap_mono, file, force_document=False): thumb = await get_audio_thumb(self._up_path) if ( - self._listener.as_doc - or force_document - or (not is_video and not is_audio and not is_image) + self._listener.as_doc + or force_document + or (not is_video and not is_audio and not is_image) ): key = "documents" if is_video: @@ -386,9 +386,9 @@ async def _upload_file(self, cap_mono, file, force_document=False): if not self._up_path.upper().endswith(("MP4", "MKV")): dirpath, file_ = self._up_path.rsplit("/", 1) if ( - self._listener.seed - and not self._listener.newDir - and not dirpath.endswith("/splited_files_mltb") + self._listener.seed + and not self._listener.newDir + and not dirpath.endswith("/splited_files_mltb") ): dirpath = f"{dirpath}/copied_mltb" await makedirs(dirpath, exist_ok=True) @@ -443,13 +443,13 @@ async def _upload_file(self, cap_mono, file, force_document=False): ) if ( - not self._is_cancelled - and self._media_group - and (self._sent_msg.video or self._sent_msg.document) + not self._is_cancelled + and self._media_group + and (self._sent_msg.video or self._sent_msg.document) ): key = "documents" if self._sent_msg.document else "videos" if match := re_match( - r".+(?=\.0*\d+$)|.+(?=\.part\d+\..+$)", self._up_path + r".+(?=\.0*\d+$)|.+(?=\.part\d+\..+$)", self._up_path ): pname = match.group(0) if pname in self._media_dict[key].keys(): @@ -463,9 +463,9 @@ async def _upload_file(self, cap_mono, file, force_document=False): self._last_msg_in_group = True if ( - self._thumb is None - and thumb is not None - and await aiopath.exists(thumb) + self._thumb is None + and thumb is not None + and await aiopath.exists(thumb) ): await remove(thumb) except FloodWait as f: @@ -473,9 +473,9 @@ async def _upload_file(self, cap_mono, file, force_document=False): await sleep(f.value) except Exception as err: if ( - self._thumb is None - and thumb is not None - and await aiopath.exists(thumb) + self._thumb is None + and thumb is not None + and await aiopath.exists(thumb) ): await remove(thumb) err_type = "RPCError: " if isinstance(err, RPCError) else "" diff --git a/bot/helper/telegram_helper/button_build.py b/bot/helper/telegram_helper/button_build.py index 04c327088eb..2007238644f 100644 --- a/bot/helper/telegram_helper/button_build.py +++ b/bot/helper/telegram_helper/button_build.py @@ -29,13 +29,13 @@ def ibutton(self, key, data, position=None): def build_menu(self, b_cols=1, h_cols=8, f_cols=8): menu = [ - self._button[i : i + b_cols] for i in range(0, len(self._button), b_cols) + self._button[i: i + b_cols] for i in range(0, len(self._button), b_cols) ] if self._header_button: h_cnt = len(self._header_button) if h_cnt > h_cols: header_buttons = [ - self._header_button[i : i + h_cols] + self._header_button[i: i + h_cols] for i in range(0, len(self._header_button), h_cols) ] menu = header_buttons + menu @@ -44,7 +44,7 @@ def build_menu(self, b_cols=1, h_cols=8, f_cols=8): if self._footer_button: if len(self._footer_button) > f_cols: [ - menu.append(self._footer_button[i : i + f_cols]) + menu.append(self._footer_button[i: i + f_cols]) for i in range(0, len(self._footer_button), f_cols) ] else: diff --git a/bot/helper/telegram_helper/filters.py b/bot/helper/telegram_helper/filters.py index 2796ead241e..6eeba5771dc 100644 --- a/bot/helper/telegram_helper/filters.py +++ b/bot/helper/telegram_helper/filters.py @@ -18,11 +18,11 @@ async def authorized_user(self, _, update): return bool( uid == OWNER_ID or ( - uid in user_data - and ( - user_data[uid].get("is_auth", False) - or user_data[uid].get("is_sudo", False) - ) + uid in user_data + and ( + user_data[uid].get("is_auth", False) + or user_data[uid].get("is_sudo", False) + ) ) or (chat_id in user_data and user_data[chat_id].get("is_auth", False)) ) diff --git a/bot/helper/telegram_helper/message_utils.py b/bot/helper/telegram_helper/message_utils.py index bea87ff6a92..3f592c102f1 100644 --- a/bot/helper/telegram_helper/message_utils.py +++ b/bot/helper/telegram_helper/message_utils.py @@ -1,12 +1,12 @@ from asyncio import sleep from pyrogram.errors import FloodWait -from time import time from re import match as re_match +from time import time from bot import config_dict, LOGGER, status_dict, task_dict_lock, Intervals, bot, user from bot.helper.ext_utils.bot_utils import setInterval, sync_to_async -from bot.helper.ext_utils.status_utils import get_readable_message from bot.helper.ext_utils.exceptions import TgLinkException +from bot.helper.ext_utils.status_utils import get_readable_message async def sendMessage(message, text, buttons=None, block=True): diff --git a/bot/modules/authorize.py b/bot/modules/authorize.py index 6d40971b952..dd8af8ebd22 100644 --- a/bot/modules/authorize.py +++ b/bot/modules/authorize.py @@ -1,12 +1,12 @@ -from pyrogram.handlers import MessageHandler from pyrogram.filters import command +from pyrogram.handlers import MessageHandler from bot import user_data, DATABASE_URL, bot -from bot.helper.telegram_helper.message_utils import sendMessage -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.ext_utils.db_handler import DbManger from bot.helper.ext_utils.bot_utils import update_user_ldata +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import sendMessage async def authorize(client, message): @@ -22,7 +22,7 @@ async def authorize(client, message): else: update_user_ldata(id_, "is_auth", True) if DATABASE_URL: - await DbManger().update_user_data(id_) + await DbManager().update_user_data(id_) msg = "Authorized" await sendMessage(message, msg) @@ -38,7 +38,7 @@ async def unauthorize(client, message): if id_ not in user_data or user_data[id_].get("is_auth"): update_user_ldata(id_, "is_auth", False) if DATABASE_URL: - await DbManger().update_user_data(id_) + await DbManager().update_user_data(id_) msg = "Unauthorized" else: msg = "Already Unauthorized!" @@ -58,7 +58,7 @@ async def addSudo(client, message): else: update_user_ldata(id_, "is_sudo", True) if DATABASE_URL: - await DbManger().update_user_data(id_) + await DbManager().update_user_data(id_) msg = "Promoted as Sudo" else: msg = "Give ID or Reply To message of whom you want to Promote." @@ -75,7 +75,7 @@ async def removeSudo(client, message): if id_ and id_ not in user_data or user_data[id_].get("is_sudo"): update_user_ldata(id_, "is_sudo", False) if DATABASE_URL: - await DbManger().update_user_data(id_) + await DbManager().update_user_data(id_) msg = "Demoted" else: msg = "Give ID or Reply To message of whom you want to remove from Sudo" diff --git a/bot/modules/bot_settings.py b/bot/modules/bot_settings.py index f771b991b63..c8f3e53a5b1 100644 --- a/bot/modules/bot_settings.py +++ b/bot/modules/bot_settings.py @@ -1,29 +1,15 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex, create -from functools import partial -from asyncio import create_subprocess_exec, create_subprocess_shell, sleep, gather -from aiofiles.os import remove, rename, path as aiopath from aiofiles import open as aiopen -from os import environ, getcwd +from aiofiles.os import remove, rename, path as aiopath +from aioshutil import rmtree +from asyncio import create_subprocess_exec, create_subprocess_shell, sleep, gather from dotenv import load_dotenv -from time import time +from functools import partial from io import BytesIO -from aioshutil import rmtree +from os import environ, getcwd +from pyrogram.filters import command, regex, create +from pyrogram.handlers import MessageHandler, CallbackQueryHandler +from time import time -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.bot_utils import ( - setInterval, - sync_to_async, - new_thread, -) -from bot.helper.ext_utils.db_handler import DbManger -from bot.helper.ext_utils.task_manager import start_from_queued -from bot.helper.ext_utils.jdownloader_booter import jdownloader -from bot.helper.mirror_utils.rclone_utils.serve import rclone_serve_booter -from bot.modules.torrent_search import initiate_search_tools -from bot.modules.rss import addJob from bot import ( config_dict, user_data, @@ -44,6 +30,18 @@ LOGGER, bot, ) +from bot.helper.ext_utils.bot_utils import ( + setInterval, + sync_to_async, + new_thread, +) +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.ext_utils.jdownloader_booter import jdownloader +from bot.helper.ext_utils.task_manager import start_from_queued +from bot.helper.mirror_utils.rclone_utils.serve import rclone_serve_booter +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( sendMessage, sendFile, @@ -51,6 +49,8 @@ update_status_message, deleteMessage, ) +from bot.modules.rss import addJob +from bot.modules.torrent_search import initiate_search_tools START = 0 STATE = "view" @@ -114,7 +114,7 @@ async def get_buttons(key=None, edit_type=None): buttons.ibutton("Close", "botset close") msg = f"Send a valid value for {key}. Current value is '{qbit_options[key]}'. Timeout: 60 sec" elif key == "var": - for k in list(config_dict.keys())[START : 10 + START]: + for k in list(config_dict.keys())[START: 10 + START]: buttons.ibutton(k, f"botset botvar {k}") if STATE == "view": buttons.ibutton("Edit", "botset edit var") @@ -123,8 +123,8 @@ async def get_buttons(key=None, edit_type=None): buttons.ibutton("Back", "botset back") buttons.ibutton("Close", "botset close") for x in range(0, len(config_dict), 10): - buttons.ibutton(f"{int(x/10)}", f"botset start var {x}", position="footer") - msg = f"Config Variables | Page: {int(START/10)} | State: {STATE}" + buttons.ibutton(f"{int(x / 10)}", f"botset start var {x}", position="footer") + msg = f"Config Variables | Page: {int(START / 10)} | State: {STATE}" elif key == "private": buttons.ibutton("Back", "botset back") buttons.ibutton("Close", "botset close") @@ -133,7 +133,7 @@ async def get_buttons(key=None, edit_type=None): Note: Changing .netrc will not take effect for aria2c until restart. Timeout: 60 sec""" elif key == "aria": - for k in list(aria2_options.keys())[START : 10 + START]: + for k in list(aria2_options.keys())[START: 10 + START]: buttons.ibutton(k, f"botset ariavar {k}") if STATE == "view": buttons.ibutton("Edit", "botset edit aria") @@ -143,10 +143,10 @@ async def get_buttons(key=None, edit_type=None): buttons.ibutton("Back", "botset back") buttons.ibutton("Close", "botset close") for x in range(0, len(aria2_options), 10): - buttons.ibutton(f"{int(x/10)}", f"botset start aria {x}", position="footer") - msg = f"Aria2c Options | Page: {int(START/10)} | State: {STATE}" + buttons.ibutton(f"{int(x / 10)}", f"botset start aria {x}", position="footer") + msg = f"Aria2c Options | Page: {int(START / 10)} | State: {STATE}" elif key == "qbit": - for k in list(qbit_options.keys())[START : 10 + START]: + for k in list(qbit_options.keys())[START: 10 + START]: buttons.ibutton(k, f"botset qbitvar {k}") if STATE == "view": buttons.ibutton("Edit", "botset edit qbit") @@ -155,8 +155,8 @@ async def get_buttons(key=None, edit_type=None): buttons.ibutton("Back", "botset back") buttons.ibutton("Close", "botset close") for x in range(0, len(qbit_options), 10): - buttons.ibutton(f"{int(x/10)}", f"botset start qbit {x}", position="footer") - msg = f"Qbittorrent Options | Page: {int(START/10)} | State: {STATE}" + buttons.ibutton(f"{int(x / 10)}", f"botset start qbit {x}", position="footer") + msg = f"Qbittorrent Options | Page: {int(START / 10)} | State: {STATE}" button = buttons.build_menu(1) if key is None else buttons.build_menu(2) return msg, button @@ -174,7 +174,7 @@ async def edit_variable(_, message, pre_message, key): elif value.lower() == "false": value = False if key == "INCOMPLETE_TASK_NOTIFIER" and DATABASE_URL: - await DbManger().trunc_table("tasks") + await DbManager().trunc_table("tasks") elif key == "DOWNLOAD_DIR": if not value.endswith("/"): value += "/" @@ -235,7 +235,7 @@ async def edit_variable(_, message, pre_message, key): await update_buttons(pre_message, "var") await deleteMessage(message) if DATABASE_URL: - await DbManger().update_config({key: value}) + await DbManager().update_config({key: value}) if key in ["SEARCH_PLUGINS", "SEARCH_API_LINK"]: await initiate_search_tools() elif key in ["QUEUE_ALL", "QUEUE_DOWNLOAD", "QUEUE_UPLOAD"]: @@ -278,7 +278,7 @@ async def edit_aria(_, message, pre_message, key): await update_buttons(pre_message, "aria") await deleteMessage(message) if DATABASE_URL: - await DbManger().update_aria2(key, value) + await DbManager().update_aria2(key, value) async def edit_qbit(_, message, pre_message, key): @@ -297,7 +297,7 @@ async def edit_qbit(_, message, pre_message, key): await update_buttons(pre_message, "qbit") await deleteMessage(message) if DATABASE_URL: - await DbManger().update_qbittorrent(key, value) + await DbManager().update_qbittorrent(key, value) async def sync_jdownloader(): @@ -308,7 +308,7 @@ async def sync_jdownloader(): await ( await create_subprocess_exec("7z", "a", "cfg.zip", "/JDownloader/cfg") ).wait() - await DbManger().update_private_file("cfg.zip") + await DbManager().update_private_file("cfg.zip") await sync_to_async(jdownloader.connectToDevice) @@ -325,7 +325,7 @@ async def update_private_file(_, message, pre_message): await rmtree("rclone_sa") config_dict["USE_SERVICE_ACCOUNTS"] = False if DATABASE_URL: - await DbManger().update_config({"USE_SERVICE_ACCOUNTS": False}) + await DbManager().update_config({"USE_SERVICE_ACCOUNTS": False}) elif file_name in [".netrc", "netrc"]: await (await create_subprocess_exec("touch", ".netrc")).wait() await (await create_subprocess_exec("chmod", "600", ".netrc")).wait() @@ -386,7 +386,7 @@ async def update_private_file(_, message, pre_message): await rclone_serve_booter() await update_buttons(pre_message) if DATABASE_URL: - await DbManger().update_private_file(file_name) + await DbManager().update_private_file(file_name) if await aiopath.exists("accounts.zip"): await remove("accounts.zip") @@ -449,9 +449,9 @@ async def edit_bot_settings(client, query): if data[2] in default_values: value = default_values[data[2]] if ( - data[2] == "STATUS_UPDATE_INTERVAL" - and len(task_dict) != 0 - and (st := Intervals["status"]) + data[2] == "STATUS_UPDATE_INTERVAL" + and len(task_dict) != 0 + and (st := Intervals["status"]) ): for key, intvl in list(st.items()): intvl.cancel() @@ -475,7 +475,7 @@ async def edit_bot_settings(client, query): LOGGER.error(e) aria2_options["bt-stop-timeout"] = "0" if DATABASE_URL: - await DbManger().update_aria2("bt-stop-timeout", "0") + await DbManager().update_aria2("bt-stop-timeout", "0") elif data[2] == "BASE_URL": await (await create_subprocess_exec("pkill", "-9", "-f", "gunicorn")).wait() elif data[2] == "BASE_URL_PORT": @@ -496,13 +496,13 @@ async def edit_bot_settings(client, query): if DRIVES_NAMES and DRIVES_NAMES[0] == "Main": INDEX_URLS[0] = "" elif data[2] == "INCOMPLETE_TASK_NOTIFIER" and DATABASE_URL: - await DbManger().trunc_table("tasks") + await DbManager().trunc_table("tasks") elif data[2] in ["JD_EMAIL", "JD_PASS"]: jdownloader.device = None config_dict[data[2]] = value await update_buttons(message, "var") if DATABASE_URL: - await DbManger().update_config({data[2]: value}) + await DbManager().update_config({data[2]: value}) if data[2] in ["SEARCH_PLUGINS", "SEARCH_API_LINK"]: await initiate_search_tools() elif data[2] in ["QUEUE_ALL", "QUEUE_DOWNLOAD", "QUEUE_UPLOAD"]: @@ -533,7 +533,7 @@ async def edit_bot_settings(client, query): except Exception as e: LOGGER.error(e) if DATABASE_URL: - await DbManger().update_aria2(data[2], value) + await DbManager().update_aria2(data[2], value) elif data[1] == "emptyaria": await query.answer() aria2_options[data[2]] = "" @@ -548,14 +548,14 @@ async def edit_bot_settings(client, query): except Exception as e: LOGGER.error(e) if DATABASE_URL: - await DbManger().update_aria2(data[2], "") + await DbManager().update_aria2(data[2], "") elif data[1] == "emptyqbit": await query.answer() await sync_to_async(get_client().app_set_preferences, {data[2]: value}) qbit_options[data[2]] = "" await update_buttons(message, "qbit") if DATABASE_URL: - await DbManger().update_qbittorrent(data[2], "") + await DbManager().update_qbittorrent(data[2], "") elif data[1] == "private": await query.answer() await update_buttons(message, data[1]) @@ -814,7 +814,7 @@ async def load_config(): LOGGER.error(e) aria2_options["bt-stop-timeout"] = "0" if DATABASE_URL: - await DbManger().update_aria2("bt-stop-timeout", "0") + await DbManager().update_aria2("bt-stop-timeout", "0") TORRENT_TIMEOUT = "" else: for download in downloads: @@ -829,7 +829,7 @@ async def load_config(): LOGGER.error(e) aria2_options["bt-stop-timeout"] = TORRENT_TIMEOUT if DATABASE_URL: - await DbManger().update_aria2("bt-stop-timeout", TORRENT_TIMEOUT) + await DbManager().update_aria2("bt-stop-timeout", TORRENT_TIMEOUT) TORRENT_TIMEOUT = int(TORRENT_TIMEOUT) QUEUE_ALL = environ.get("QUEUE_ALL", "") @@ -844,7 +844,7 @@ async def load_config(): INCOMPLETE_TASK_NOTIFIER = environ.get("INCOMPLETE_TASK_NOTIFIER", "") INCOMPLETE_TASK_NOTIFIER = INCOMPLETE_TASK_NOTIFIER.lower() == "true" if not INCOMPLETE_TASK_NOTIFIER and DATABASE_URL: - await DbManger().trunc_table("tasks") + await DbManager().trunc_table("tasks") STOP_DUPLICATE = environ.get("STOP_DUPLICATE", "") STOP_DUPLICATE = STOP_DUPLICATE.lower() == "true" @@ -984,7 +984,7 @@ async def load_config(): ) if DATABASE_URL: - await DbManger().update_config(config_dict) + await DbManager().update_config(config_dict) await gather(initiate_search_tools(), start_from_queued(), rclone_serve_booter()) addJob() diff --git a/bot/modules/cancel_task.py b/bot/modules/cancel_task.py index 2c4b96a08d6..c6d21c9b3c2 100644 --- a/bot/modules/cancel_task.py +++ b/bot/modules/cancel_task.py @@ -1,8 +1,11 @@ from asyncio import sleep -from pyrogram.handlers import MessageHandler, CallbackQueryHandler from pyrogram.filters import command, regex +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from bot import task_dict, bot, task_dict_lock, OWNER_ID, user_data, multi_tags +from bot.helper.ext_utils.bot_utils import new_task +from bot.helper.ext_utils.status_utils import getTaskByGid, getAllTasks, MirrorStatus +from bot.helper.telegram_helper import button_build from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( @@ -11,9 +14,6 @@ deleteMessage, editMessage, ) -from bot.helper.ext_utils.status_utils import getTaskByGid, getAllTasks, MirrorStatus -from bot.helper.ext_utils.bot_utils import new_task -from bot.helper.telegram_helper import button_build async def cancel_task(_, message): @@ -43,9 +43,9 @@ async def cancel_task(_, message): await sendMessage(message, msg) return if ( - OWNER_ID != user_id - and task.listener.user_id != user_id - and (user_id not in user_data or not user_data[user_id].get("is_sudo")) + OWNER_ID != user_id + and task.listener.user_id != user_id + and (user_id not in user_data or not user_data[user_id].get("is_sudo")) ): await sendMessage(message, "This task is not for you!") return diff --git a/bot/modules/clone.py b/bot/modules/clone.py index 1f6a463002a..b6f21cc4268 100644 --- a/bot/modules/clone.py +++ b/bot/modules/clone.py @@ -1,21 +1,10 @@ -from pyrogram.handlers import MessageHandler -from pyrogram.filters import command -from secrets import token_urlsafe from asyncio import gather from json import loads +from pyrogram.filters import command +from pyrogram.handlers import MessageHandler +from secrets import token_urlsafe from bot import LOGGER, task_dict, task_dict_lock, bot -from bot.helper.mirror_utils.gdrive_utils.clone import gdClone -from bot.helper.mirror_utils.gdrive_utils.count import gdCount -from bot.helper.ext_utils.help_messages import CLONE_HELP_MESSAGE -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - deleteMessage, - sendStatusMessage, -) -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.mirror_utils.status_utils.gdrive_status import GdriveStatus from bot.helper.ext_utils.bot_utils import ( new_task, sync_to_async, @@ -23,35 +12,45 @@ cmd_exec, arg_parser, ) - +from bot.helper.ext_utils.exceptions import DirectDownloadLinkException +from bot.helper.ext_utils.help_messages import CLONE_HELP_MESSAGE from bot.helper.ext_utils.links_utils import ( is_gdrive_link, is_share_link, is_rclone_path, is_gdrive_id, ) -from bot.helper.ext_utils.exceptions import DirectDownloadLinkException +from bot.helper.ext_utils.task_manager import stop_duplicate_check +from bot.helper.listeners.task_listener import TaskListener from bot.helper.mirror_utils.download_utils.direct_link_generator import ( direct_link_generator, ) +from bot.helper.mirror_utils.gdrive_utils.clone import gdClone +from bot.helper.mirror_utils.gdrive_utils.count import gdCount from bot.helper.mirror_utils.rclone_utils.transfer import RcloneTransferHelper +from bot.helper.mirror_utils.status_utils.gdrive_status import GdriveStatus from bot.helper.mirror_utils.status_utils.rclone_status import RcloneStatus -from bot.helper.listeners.task_listener import TaskListener -from bot.helper.ext_utils.task_manager import stop_duplicate_check +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + deleteMessage, + sendStatusMessage, +) class Clone(TaskListener): def __init__( - self, - client, - message, - _=None, - __=None, - ___=None, - ____=None, - bulk=None, - multiTag=None, - options="", + self, + client, + message, + _=None, + __=None, + ___=None, + ____=None, + bulk=None, + multiTag=None, + options="", ): if bulk is None: bulk = [] diff --git a/bot/modules/exec.py b/bot/modules/exec.py index 5cb85f6b6b8..2fb3db4739e 100644 --- a/bot/modules/exec.py +++ b/bot/modules/exec.py @@ -1,17 +1,17 @@ -from pyrogram.handlers import MessageHandler -from pyrogram.filters import command +from aiofiles import open as aiopen +from contextlib import redirect_stdout +from io import StringIO, BytesIO from os import path as ospath, getcwd, chdir -from traceback import format_exc +from pyrogram.filters import command +from pyrogram.handlers import MessageHandler from textwrap import indent -from io import StringIO, BytesIO -from contextlib import redirect_stdout -from aiofiles import open as aiopen +from traceback import format_exc from bot import LOGGER, bot -from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.ext_utils.bot_utils import sync_to_async, new_task from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import sendFile, sendMessage -from bot.helper.ext_utils.bot_utils import sync_to_async, new_task namespaces = {} diff --git a/bot/modules/gd_count.py b/bot/modules/gd_count.py index a243e4dd703..0d3f9177375 100644 --- a/bot/modules/gd_count.py +++ b/bot/modules/gd_count.py @@ -1,14 +1,14 @@ -from pyrogram.handlers import MessageHandler from pyrogram.filters import command +from pyrogram.handlers import MessageHandler from bot import bot -from bot.helper.mirror_utils.gdrive_utils.count import gdCount -from bot.helper.telegram_helper.message_utils import deleteMessage, sendMessage -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.ext_utils.bot_utils import sync_to_async, new_task from bot.helper.ext_utils.links_utils import is_gdrive_link from bot.helper.ext_utils.status_utils import get_readable_file_size +from bot.helper.mirror_utils.gdrive_utils.count import gdCount +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import deleteMessage, sendMessage @new_task diff --git a/bot/modules/gd_delete.py b/bot/modules/gd_delete.py index fe800533b25..69dc127ab57 100644 --- a/bot/modules/gd_delete.py +++ b/bot/modules/gd_delete.py @@ -1,13 +1,13 @@ -from pyrogram.handlers import MessageHandler from pyrogram.filters import command +from pyrogram.handlers import MessageHandler from bot import bot, LOGGER -from bot.helper.telegram_helper.message_utils import auto_delete_message, sendMessage -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.mirror_utils.gdrive_utils.delete import gdDelete from bot.helper.ext_utils.bot_utils import sync_to_async, new_task from bot.helper.ext_utils.links_utils import is_gdrive_link +from bot.helper.mirror_utils.gdrive_utils.delete import gdDelete +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import auto_delete_message, sendMessage @new_task diff --git a/bot/modules/gd_search.py b/bot/modules/gd_search.py index dba13530bbe..6a976b390ae 100644 --- a/bot/modules/gd_search.py +++ b/bot/modules/gd_search.py @@ -1,13 +1,13 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler from pyrogram.filters import command, regex +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from bot import LOGGER, bot, user_data +from bot.helper.ext_utils.bot_utils import sync_to_async, new_task, get_telegraph_list from bot.helper.mirror_utils.gdrive_utils.search import gdSearch -from bot.helper.telegram_helper.message_utils import sendMessage, editMessage -from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.bot_utils import sync_to_async, new_task, get_telegraph_list +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import sendMessage, editMessage async def list_buttons(user_id, isRecursive=True, user_token=False): diff --git a/bot/modules/help.py b/bot/modules/help.py index a0e85c2f8c7..e76280e49a4 100644 --- a/bot/modules/help.py +++ b/bot/modules/help.py @@ -1,11 +1,11 @@ -from pyrogram.handlers import CallbackQueryHandler from pyrogram.filters import regex +from pyrogram.handlers import CallbackQueryHandler from bot import bot -from bot.helper.telegram_helper.message_utils import editMessage, deleteMessage -from bot.helper.telegram_helper.button_build import ButtonMaker from bot.helper.ext_utils.bot_utils import COMMAND_USAGE from bot.helper.ext_utils.help_messages import YT_HELP_DICT, MIRROR_HELP_DICT +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.message_utils import editMessage, deleteMessage async def argUsage(_, query): @@ -27,7 +27,7 @@ async def argUsage(_, query): await editMessage(message, MIRROR_HELP_DICT[data[2]], button) elif data[1] == "yt": buttons = ButtonMaker() - buttons.ibutton("Back", f"help back y") + buttons.ibutton("Back", "help back y") button = buttons.build_menu() await editMessage(message, YT_HELP_DICT[data[2]], button) diff --git a/bot/modules/mirror_leech.py b/bot/modules/mirror_leech.py index a7a7b3f660f..4c2bd77dc8a 100644 --- a/bot/modules/mirror_leech.py +++ b/bot/modules/mirror_leech.py @@ -1,28 +1,18 @@ -from pyrogram.handlers import MessageHandler -from pyrogram.filters import command +from aiofiles.os import path as aiopath from base64 import b64encode +from pyrogram.filters import command +from pyrogram.handlers import MessageHandler from re import match as re_match -from aiofiles.os import path as aiopath -from myjd.exception import MYJDException -from bot.helper.ext_utils.exceptions import DirectDownloadLinkException -from bot.helper.mirror_utils.download_utils.direct_downloader import add_direct_download -from bot.helper.mirror_utils.download_utils.aria2_download import add_aria2c_download -from bot.helper.mirror_utils.download_utils.gd_download import add_gd_download -from bot.helper.mirror_utils.download_utils.qbit_download import add_qb_torrent -from bot.helper.mirror_utils.download_utils.rclone_download import add_rclone_download -from bot.helper.mirror_utils.download_utils.jd_download import add_jd_download -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.message_utils import sendMessage, get_tg_link_message -from bot.helper.listeners.task_listener import TaskListener -from bot.helper.mirror_utils.download_utils.telegram_download import ( - TelegramDownloadHelper, -) -from bot.helper.mirror_utils.download_utils.direct_link_generator import ( - direct_link_generator, -) from bot import bot, DOWNLOAD_DIR, LOGGER +from bot.helper.ext_utils.bot_utils import ( + get_content_type, + new_task, + sync_to_async, + arg_parser, + COMMAND_USAGE, +) +from bot.helper.ext_utils.exceptions import DirectDownloadLinkException from bot.helper.ext_utils.links_utils import ( is_url, is_magnet, @@ -31,27 +21,37 @@ is_telegram_link, is_gdrive_id, ) -from bot.helper.ext_utils.bot_utils import ( - get_content_type, - new_task, - sync_to_async, - arg_parser, - COMMAND_USAGE, +from bot.helper.listeners.task_listener import TaskListener +from bot.helper.mirror_utils.download_utils.aria2_download import add_aria2c_download +from bot.helper.mirror_utils.download_utils.direct_downloader import add_direct_download +from bot.helper.mirror_utils.download_utils.direct_link_generator import ( + direct_link_generator, ) +from bot.helper.mirror_utils.download_utils.gd_download import add_gd_download +from bot.helper.mirror_utils.download_utils.jd_download import add_jd_download +from bot.helper.mirror_utils.download_utils.qbit_download import add_qb_torrent +from bot.helper.mirror_utils.download_utils.rclone_download import add_rclone_download +from bot.helper.mirror_utils.download_utils.telegram_download import ( + TelegramDownloadHelper, +) +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import sendMessage, get_tg_link_message +from myjd.exception import MYJDException class Mirror(TaskListener): def __init__( - self, - client, - message, - isQbit=False, - isLeech=False, - isJd=False, - sameDir=None, - bulk=None, - multiTag=None, - options="", + self, + client, + message, + isQbit=False, + isLeech=False, + isJd=False, + sameDir=None, + bulk=None, + multiTag=None, + options="", ): if sameDir is None: sameDir = {} @@ -210,15 +210,15 @@ async def newEvent(self): if reply_to: file_ = ( - reply_to.document - or reply_to.photo - or reply_to.video - or reply_to.audio - or reply_to.voice - or reply_to.video_note - or reply_to.sticker - or reply_to.animation - or None + reply_to.document + or reply_to.photo + or reply_to.video + or reply_to.audio + or reply_to.voice + or reply_to.video_note + or reply_to.sticker + or reply_to.animation + or None ) if file_ is None: @@ -227,23 +227,23 @@ async def newEvent(self): else: reply_to = None elif reply_to.document and ( - file_.mime_type == "application/x-bittorrent" - or file_.file_name.endswith(".torrent") + file_.mime_type == "application/x-bittorrent" + or file_.file_name.endswith(".torrent") ): self.link = await reply_to.download() file_ = None if ( - not self.link - and file_ is None - or is_telegram_link(self.link) - and reply_to is None - or file_ is None - and not is_url(self.link) - and not is_magnet(self.link) - and not await aiopath.exists(self.link) - and not is_rclone_path(self.link) - and not is_gdrive_id(self.link) + not self.link + and file_ is None + or is_telegram_link(self.link) + and reply_to is None + or file_ is None + and not is_url(self.link) + and not is_magnet(self.link) + and not await aiopath.exists(self.link) + and not is_rclone_path(self.link) + and not is_gdrive_id(self.link) ): await sendMessage( self.message, COMMAND_USAGE["mirror"][0], COMMAND_USAGE["mirror"][1] @@ -262,14 +262,14 @@ async def newEvent(self): return if ( - not self.isJd - and not self.isQbit - and not is_magnet(self.link) - and not is_rclone_path(self.link) - and not is_gdrive_link(self.link) - and not self.link.endswith(".torrent") - and file_ is None - and not is_gdrive_id(self.link) + not self.isJd + and not self.isQbit + and not is_magnet(self.link) + and not is_rclone_path(self.link) + and not is_gdrive_link(self.link) + and not self.link.endswith(".torrent") + and file_ is None + and not is_gdrive_id(self.link) ): content_type = await get_content_type(self.link) if content_type is None or re_match(r"text/html|text/plain", content_type): diff --git a/bot/modules/rss.py b/bot/modules/rss.py index d53d2918ae7..602236c6f60 100644 --- a/bot/modules/rss.py +++ b/bot/modules/rss.py @@ -1,16 +1,23 @@ -from feedparser import parse as feedparse -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex, create +from aiohttp import ClientSession +from apscheduler.triggers.interval import IntervalTrigger from asyncio import Lock, sleep from datetime import datetime, timedelta -from time import time +from feedparser import parse as feedparse from functools import partial -from aiohttp import ClientSession -from apscheduler.triggers.interval import IntervalTrigger -from re import split as re_split from io import BytesIO +from pyrogram.filters import command, regex, create +from pyrogram.handlers import MessageHandler, CallbackQueryHandler +from re import split as re_split +from time import time from bot import scheduler, rss_dict, LOGGER, DATABASE_URL, config_dict, bot +from bot.helper.ext_utils.bot_utils import new_thread +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.ext_utils.exceptions import RssShutdownException +from bot.helper.ext_utils.help_messages import RSS_HELP_MESSAGE +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( sendMessage, editMessage, @@ -18,13 +25,6 @@ sendFile, deleteMessage, ) -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.ext_utils.db_handler import DbManger -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.bot_utils import new_thread -from bot.helper.ext_utils.exceptions import RssShutdownException -from bot.helper.ext_utils.help_messages import RSS_HELP_MESSAGE rss_dict_lock = Lock() handler_dict = {} @@ -174,7 +174,7 @@ async def rssSub(_, message, pre_event): except Exception as e: await sendMessage(message, str(e)) if DATABASE_URL: - await DbManger().rss_update(user_id) + await DbManager().rss_update(user_id) if msg: await sendMessage(message, msg) await updateRssMenu(pre_event) @@ -232,20 +232,20 @@ async def rssUpdate(_, message, pre_event, state): addJob() scheduler.start() if is_sudo and DATABASE_URL and user_id != message.from_user.id: - await DbManger().rss_update(user_id) + await DbManager().rss_update(user_id) if not rss_dict[user_id]: async with rss_dict_lock: del rss_dict[user_id] if DATABASE_URL: - await DbManger().rss_delete(user_id) + await DbManager().rss_delete(user_id) if not rss_dict: - await DbManger().trunc_table("rss") + await DbManager().trunc_table("rss") LOGGER.info(f"Rss link with Title(s): {updated} has been {state}d!") await sendMessage( message, f"Rss links with Title(s): {updated} has been {state}d!" ) if DATABASE_URL and rss_dict.get(user_id): - await DbManger().rss_update(user_id) + await DbManager().rss_update(user_id) await updateRssMenu(pre_event) @@ -253,13 +253,13 @@ async def rssList(query, start, all_users=False): user_id = query.from_user.id buttons = ButtonMaker() if all_users: - list_feed = f"All subscriptions | Page: {int(start/5)} " + list_feed = f"All subscriptions | Page: {int(start / 5)} " async with rss_dict_lock: keysCount = sum(len(v.keys()) for v in list(rss_dict.values())) index = 0 for titles in list(rss_dict.values()): for index, (title, data) in enumerate( - list(titles.items())[start : 5 + start] + list(titles.items())[start: 5 + start] ): list_feed += f"\n\nTitle: {title}\n" list_feed += f"Feed Url: {data['link']}\n" @@ -272,10 +272,10 @@ async def rssList(query, start, all_users=False): if index == 5: break else: - list_feed = f"Your subscriptions | Page: {int(start/5)} " + list_feed = f"Your subscriptions | Page: {int(start / 5)} " async with rss_dict_lock: keysCount = len(rss_dict.get(user_id, {}).keys()) - for title, data in list(rss_dict[user_id].items())[start : 5 + start]: + for title, data in list(rss_dict[user_id].items())[start: 5 + start]: list_feed += f"\n\nTitle: {title}\nFeed Url: {data['link']}\n" list_feed += f"Command: {data['command']}\n" list_feed += f"Inf: {data['inf']}\n" @@ -285,7 +285,7 @@ async def rssList(query, start, all_users=False): buttons.ibutton("Close", f"rss close {user_id}") if keysCount > 5: for x in range(0, keysCount, 5): - buttons.ibutton(f"{int(x/5)}", f"rss list {user_id} {x}", position="footer") + buttons.ibutton(f"{int(x / 5)}", f"rss list {user_id} {x}", position="footer") button = buttons.build_menu(2) if query.message.text.html == list_feed: return @@ -390,7 +390,7 @@ async def rssEdit(_, message, pre_event): exf_lists.append(y) rss_dict[user_id][title]["exf"] = exf_lists if DATABASE_URL: - await DbManger().rss_update(user_id) + await DbManager().rss_update(user_id) await updateRssMenu(pre_event) @@ -402,7 +402,7 @@ async def rssDelete(_, message, pre_event): async with rss_dict_lock: del rss_dict[user] if DATABASE_URL: - await DbManger().rss_delete(user) + await DbManager().rss_delete(user) await updateRssMenu(pre_event) @@ -533,14 +533,14 @@ async def rssListener(client, query): async with rss_dict_lock: del rss_dict[int(data[2])] if DATABASE_URL: - await DbManger().rss_delete(int(data[2])) + await DbManager().rss_delete(int(data[2])) await updateRssMenu(query) elif data[1].endswith("pause"): async with rss_dict_lock: for title in list(rss_dict[int(data[2])].keys()): rss_dict[int(data[2])][title]["paused"] = True if DATABASE_URL: - await DbManger().rss_update(int(data[2])) + await DbManager().rss_update(int(data[2])) elif data[1].endswith("resume"): async with rss_dict_lock: for title in list(rss_dict[int(data[2])].keys()): @@ -548,7 +548,7 @@ async def rssListener(client, query): if scheduler.state == 2: scheduler.resume() if DATABASE_URL: - await DbManger().rss_update(int(data[2])) + await DbManager().rss_update(int(data[2])) await updateRssMenu(query) elif data[1].startswith("all"): if len(rss_dict) == 0: @@ -559,7 +559,7 @@ async def rssListener(client, query): async with rss_dict_lock: rss_dict.clear() if DATABASE_URL: - await DbManger().trunc_table("rss") + await DbManager().trunc_table("rss") await updateRssMenu(query) elif data[1].endswith("pause"): async with rss_dict_lock: @@ -569,7 +569,7 @@ async def rssListener(client, query): if scheduler.running: scheduler.pause() if DATABASE_URL: - await DbManger().rss_update_all() + await DbManager().rss_update_all() elif data[1].endswith("resume"): async with rss_dict_lock: for user in list(rss_dict.keys()): @@ -581,7 +581,7 @@ async def rssListener(client, query): addJob() scheduler.start() if DATABASE_URL: - await DbManger().rss_update_all() + await DbManager().rss_update_all() elif data[1] == "deluser": if len(rss_dict) == 0: await query.answer(text="No subscriptions!", show_alert=True) @@ -699,7 +699,7 @@ async def rssMonitor(): rss_dict[user][title].update( {"last_feed": last_link, "last_title": last_title} ) - await DbManger().rss_update(user) + await DbManager().rss_update(user) LOGGER.info(f"Feed Name: {title}") LOGGER.info(f"Last item: {last_link}") except RssShutdownException as ex: diff --git a/bot/modules/shell.py b/bot/modules/shell.py index 9958af51179..ffb7e690944 100644 --- a/bot/modules/shell.py +++ b/bot/modules/shell.py @@ -1,12 +1,12 @@ -from pyrogram.handlers import MessageHandler, EditedMessageHandler -from pyrogram.filters import command from io import BytesIO +from pyrogram.filters import command +from pyrogram.handlers import MessageHandler, EditedMessageHandler from bot import LOGGER, bot -from bot.helper.telegram_helper.message_utils import sendMessage, sendFile from bot.helper.ext_utils.bot_utils import cmd_exec, new_task -from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import sendMessage, sendFile @new_task diff --git a/bot/modules/status.py b/bot/modules/status.py index 9032411e12a..6e96719943e 100644 --- a/bot/modules/status.py +++ b/bot/modules/status.py @@ -1,6 +1,6 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex from psutil import cpu_percent, virtual_memory, disk_usage +from pyrogram.filters import command, regex +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from time import time from bot import ( @@ -12,8 +12,15 @@ Intervals, bot, ) -from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.ext_utils.bot_utils import new_task +from bot.helper.ext_utils.status_utils import ( + MirrorStatus, + get_readable_file_size, + get_readable_time, + speed_string_to_bytes, +) from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( sendMessage, deleteMessage, @@ -21,13 +28,6 @@ sendStatusMessage, update_status_message, ) -from bot.helper.ext_utils.bot_utils import new_task -from bot.helper.ext_utils.status_utils import ( - MirrorStatus, - get_readable_file_size, - get_readable_time, - speed_string_to_bytes, -) @new_task diff --git a/bot/modules/torrent_search.py b/bot/modules/torrent_search.py index df653476226..3435c8a24d5 100644 --- a/bot/modules/torrent_search.py +++ b/bot/modules/torrent_search.py @@ -1,17 +1,17 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex from aiohttp import ClientSession from html import escape +from pyrogram.filters import command, regex +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from urllib.parse import quote from bot import bot, LOGGER, config_dict, get_client -from bot.helper.telegram_helper.message_utils import editMessage, sendMessage +from bot.helper.ext_utils.bot_utils import sync_to_async, new_task +from bot.helper.ext_utils.status_utils import get_readable_file_size from bot.helper.ext_utils.telegraph_helper import telegraph -from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.ext_utils.bot_utils import sync_to_async, new_task from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.status_utils import get_readable_file_size +from bot.helper.telegram_helper.filters import CustomFilters +from bot.helper.telegram_helper.message_utils import editMessage, sendMessage PLUGINS = [] SITES = None diff --git a/bot/modules/torrent_select.py b/bot/modules/torrent_select.py index e5860e2bf07..30ac1126219 100644 --- a/bot/modules/torrent_select.py +++ b/bot/modules/torrent_select.py @@ -1,6 +1,6 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex from aiofiles.os import remove, path as aiopath +from pyrogram.filters import command, regex +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from bot import ( bot, @@ -12,6 +12,8 @@ LOGGER, config_dict, ) +from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async +from bot.helper.ext_utils.status_utils import getTaskByGid, MirrorStatus from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( @@ -19,8 +21,6 @@ sendStatusMessage, deleteMessage, ) -from bot.helper.ext_utils.bot_utils import bt_selection_buttons, sync_to_async -from bot.helper.ext_utils.status_utils import getTaskByGid, MirrorStatus async def select(_, message): @@ -43,17 +43,17 @@ async def select(_, message): return elif len(msg) == 1: msg = ( - "Reply to an active /cmd which was used to start the qb-download or add gid along with cmd\n\n" - + "This command mainly for selection incase you decided to select files from already added torrent. " - + "But you can always use /cmd with arg `s` to select files before download start." + "Reply to an active /cmd which was used to start the qb-download or add gid along with cmd\n\n" + + "This command mainly for selection incase you decided to select files from already added torrent. " + + "But you can always use /cmd with arg `s` to select files before download start." ) await sendMessage(message, msg) return if ( - OWNER_ID != user_id - and task.listener.user_id != user_id - and (user_id not in user_data or not user_data[user_id].get("is_sudo")) + OWNER_ID != user_id + and task.listener.user_id != user_id + and (user_id not in user_data or not user_data[user_id].get("is_sudo")) ): await sendMessage(message, "This task is not for you!") return diff --git a/bot/modules/users_settings.py b/bot/modules/users_settings.py index 3d2ababf8a1..6da6290774e 100644 --- a/bot/modules/users_settings.py +++ b/bot/modules/users_settings.py @@ -1,12 +1,12 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex, create from aiofiles.os import remove, path as aiopath, makedirs -from os import getcwd -from time import time +from asyncio import sleep from functools import partial from html import escape from io import BytesIO -from asyncio import sleep +from os import getcwd +from pyrogram.filters import command, regex, create +from pyrogram.handlers import MessageHandler, CallbackQueryHandler +from time import time from bot import ( bot, @@ -17,18 +17,18 @@ MAX_SPLIT_SIZE, GLOBAL_EXTENSION_FILTER, ) +from bot.helper.ext_utils.bot_utils import update_user_ldata, new_thread +from bot.helper.ext_utils.db_handler import DbManager +from bot.helper.ext_utils.media_utils import createThumb, getSplitSizeBytes +from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.button_build import ButtonMaker +from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import ( sendMessage, editMessage, sendFile, deleteMessage, ) -from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.telegram_helper.bot_commands import BotCommands -from bot.helper.telegram_helper.button_build import ButtonMaker -from bot.helper.ext_utils.db_handler import DbManger -from bot.helper.ext_utils.bot_utils import update_user_ldata, new_thread -from bot.helper.ext_utils.media_utils import createThumb, getSplitSizeBytes handler_dict = {} @@ -43,9 +43,9 @@ async def get_user_settings(from_user): user_dict = user_data.get(user_id, {}) if ( - user_dict.get("as_doc", False) - or "as_doc" not in user_dict - and config_dict["AS_DOCUMENT"] + user_dict.get("as_doc", False) + or "as_doc" not in user_dict + and config_dict["AS_DOCUMENT"] ): ltype = "DOCUMENT" else: @@ -59,18 +59,18 @@ async def get_user_settings(from_user): split_size = config_dict["LEECH_SPLIT_SIZE"] if ( - user_dict.get("equal_splits", False) - or "equal_splits" not in user_dict - and config_dict["EQUAL_SPLITS"] + user_dict.get("equal_splits", False) + or "equal_splits" not in user_dict + and config_dict["EQUAL_SPLITS"] ): equal_splits = "Enabled" else: equal_splits = "Disabled" if ( - user_dict.get("media_group", False) - or "media_group" not in user_dict - and config_dict["MEDIA_GROUP"] + user_dict.get("media_group", False) + or "media_group" not in user_dict + and config_dict["MEDIA_GROUP"] ): media_group = "Enabled" else: @@ -91,10 +91,10 @@ async def get_user_settings(from_user): leech_dest = "None" if ( - IS_PREMIUM_USER - and user_dict.get("user_transmission", False) - or "user_transmission" not in user_dict - and config_dict["USER_TRANSMISSION"] + IS_PREMIUM_USER + and user_dict.get("user_transmission", False) + or "user_transmission" not in user_dict + and config_dict["USER_TRANSMISSION"] ): leech_method = "user" else: @@ -121,16 +121,16 @@ async def get_user_settings(from_user): gdrive_id = "None" index = user_dict["index_url"] if user_dict.get("index_url", False) else "None" if ( - user_dict.get("stop_duplicate", False) - or "stop_duplicate" not in user_dict - and config_dict["STOP_DUPLICATE"] + user_dict.get("stop_duplicate", False) + or "stop_duplicate" not in user_dict + and config_dict["STOP_DUPLICATE"] ): sd_msg = "Enabled" else: sd_msg = "Disabled" default_upload = ( - user_dict.get("default_upload", "") or config_dict["DEFAULT_UPLOAD"] + user_dict.get("default_upload", "") or config_dict["DEFAULT_UPLOAD"] ) du = "Gdrive API" if default_upload == "gd" else "Rclone" dub = "Gdrive API" if default_upload != "gd" else "Rclone" @@ -197,7 +197,7 @@ async def set_thumb(_, message, pre_event): await deleteMessage(message) await update_user_settings(pre_event) if DATABASE_URL: - await DbManger().update_user_doc(user_id, "thumb", des_dir) + await DbManager().update_user_doc(user_id, "thumb", des_dir) async def add_rclone(_, message, pre_event): @@ -211,7 +211,7 @@ async def add_rclone(_, message, pre_event): await deleteMessage(message) await update_user_settings(pre_event) if DATABASE_URL: - await DbManger().update_user_doc(user_id, "rclone_config", des_dir) + await DbManager().update_user_doc(user_id, "rclone_config", des_dir) async def add_token_pickle(_, message, pre_event): @@ -225,7 +225,7 @@ async def add_token_pickle(_, message, pre_event): await deleteMessage(message) await update_user_settings(pre_event) if DATABASE_URL: - await DbManger().update_user_doc(user_id, "token_pickle", des_dir) + await DbManager().update_user_doc(user_id, "token_pickle", des_dir) async def set_option(_, message, pre_event, option): @@ -249,7 +249,7 @@ async def set_option(_, message, pre_event, option): await deleteMessage(message) await update_user_settings(pre_event) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) async def event_handler(client, query, pfunc, photo=False, document=False): @@ -306,7 +306,7 @@ async def edit_user_settings(client, query): await query.answer() await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) elif data[2] in ["thumb", "rclone_config", "token_pickle"]: if data[2] == "thumb": fpath = thumb_path @@ -320,7 +320,7 @@ async def edit_user_settings(client, query): update_user_ldata(user_id, data[2], "") await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_doc(user_id, data[2]) + await DbManager().update_user_doc(user_id, data[2]) else: await query.answer("Old Settings", show_alert=True) await update_user_settings(query) @@ -329,14 +329,14 @@ async def edit_user_settings(client, query): update_user_ldata(user_id, data[2], "") await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) elif data[2] in ["split_size", "leech_dest", "rclone_path", "gdrive_id"]: await query.answer() if data[2] in user_data.get(user_id, {}): del user_data[user_id][data[2]] await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) elif data[2] == "leech": await query.answer() thumbpath = f"Thumbnails/{user_id}.jpg" @@ -359,15 +359,15 @@ async def edit_user_settings(client, query): if user_dict.get("lprefix", False): lprefix = user_dict["lprefix"] elif "lprefix" not in user_dict and ( - LP := config_dict["LEECH_FILENAME_PREFIX"] + LP := config_dict["LEECH_FILENAME_PREFIX"] ): lprefix = LP else: lprefix = "None" if ( - user_dict.get("as_doc", False) - or "as_doc" not in user_dict - and config_dict["AS_DOCUMENT"] + user_dict.get("as_doc", False) + or "as_doc" not in user_dict + and config_dict["AS_DOCUMENT"] ): ltype = "DOCUMENT" buttons.ibutton("Send As Media", f"userset {user_id} as_doc false") @@ -375,9 +375,9 @@ async def edit_user_settings(client, query): ltype = "MEDIA" buttons.ibutton("Send As Document", f"userset {user_id} as_doc true") if ( - user_dict.get("equal_splits", False) - or "equal_splits" not in user_dict - and config_dict["EQUAL_SPLITS"] + user_dict.get("equal_splits", False) + or "equal_splits" not in user_dict + and config_dict["EQUAL_SPLITS"] ): buttons.ibutton( "Disable Equal Splits", f"userset {user_id} equal_splits false" @@ -389,9 +389,9 @@ async def edit_user_settings(client, query): ) equal_splits = "Disabled" if ( - user_dict.get("media_group", False) - or "media_group" not in user_dict - and config_dict["MEDIA_GROUP"] + user_dict.get("media_group", False) + or "media_group" not in user_dict + and config_dict["MEDIA_GROUP"] ): buttons.ibutton( "Disable Media Group", f"userset {user_id} media_group false" @@ -401,10 +401,10 @@ async def edit_user_settings(client, query): buttons.ibutton("Enable Media Group", f"userset {user_id} media_group true") media_group = "Disabled" if ( - IS_PREMIUM_USER - and user_dict.get("user_transmission", False) - or "user_transmission" not in user_dict - and config_dict["USER_TRANSMISSION"] + IS_PREMIUM_USER + and user_dict.get("user_transmission", False) + or "user_transmission" not in user_dict + and config_dict["USER_TRANSMISSION"] ): buttons.ibutton( "Leech by Bot", f"userset {user_id} user_transmission false" @@ -455,9 +455,9 @@ async def edit_user_settings(client, query): buttons.ibutton("Default Gdrive ID", f"userset {user_id} gdid") buttons.ibutton("Index URL", f"userset {user_id} index") if ( - user_dict.get("stop_duplicate", False) - or "stop_duplicate" not in user_dict - and config_dict["STOP_DUPLICATE"] + user_dict.get("stop_duplicate", False) + or "stop_duplicate" not in user_dict + and config_dict["STOP_DUPLICATE"] ): buttons.ibutton( "Disable Stop Duplicate", f"userset {user_id} stop_duplicate false" @@ -596,9 +596,9 @@ async def edit_user_settings(client, query): await query.answer() buttons = ButtonMaker() if ( - user_dict.get("lprefix", False) - or "lprefix" not in user_dict - and config_dict["LEECH_FILENAME_PREFIX"] + user_dict.get("lprefix", False) + or "lprefix" not in user_dict + and config_dict["LEECH_FILENAME_PREFIX"] ): buttons.ibutton("Remove Leech Prefix", f"userset {user_id} lprefix") buttons.ibutton("Back", f"userset {user_id} leech") @@ -614,9 +614,9 @@ async def edit_user_settings(client, query): await query.answer() buttons = ButtonMaker() if ( - user_dict.get("leech_dest", False) - or "leech_dest" not in user_dict - and config_dict["LEECH_DUMP_CHAT"] + user_dict.get("leech_dest", False) + or "leech_dest" not in user_dict + and config_dict["LEECH_DUMP_CHAT"] ): buttons.ibutton("Reset Leech Destination", f"userset {user_id} leech_dest") buttons.ibutton("Back", f"userset {user_id} leech") @@ -632,9 +632,9 @@ async def edit_user_settings(client, query): await query.answer() buttons = ButtonMaker() if ( - user_dict.get("excluded_extensions", False) - or "excluded_extensions" not in user_dict - and GLOBAL_EXTENSION_FILTER + user_dict.get("excluded_extensions", False) + or "excluded_extensions" not in user_dict + and GLOBAL_EXTENSION_FILTER ): buttons.ibutton( "Remove Excluded Extensions", f"userset {user_id} excluded_extensions" @@ -654,7 +654,7 @@ async def edit_user_settings(client, query): update_user_ldata(user_id, "default_upload", du) await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) elif data[2] == "reset": await query.answer() if ud := user_data.get(user_id, {}): @@ -666,7 +666,7 @@ async def edit_user_settings(client, query): user_data[user_id].clear() await update_user_settings(query) if DATABASE_URL: - await DbManger().update_user_data(user_id) + await DbManager().update_user_data(user_id) for fpath in [thumb_path, rclone_conf, token_pickle]: if await aiopath.exists(fpath): await remove(fpath) @@ -685,7 +685,7 @@ async def send_users_settings(_, message): for u, d in user_data.items(): kmsg = f"\n{u}:\n" if vmsg := "".join( - f"{k}: {v}\n" for k, v in d.items() if f"{v}" + f"{k}: {v}\n" for k, v in d.items() if f"{v}" ): msg += kmsg + vmsg diff --git a/bot/modules/ytdlp.py b/bot/modules/ytdlp.py index e6fc025e54d..31bb165a152 100644 --- a/bot/modules/ytdlp.py +++ b/bot/modules/ytdlp.py @@ -1,18 +1,12 @@ -from pyrogram.handlers import MessageHandler, CallbackQueryHandler -from pyrogram.filters import command, regex, user -from asyncio import wait_for, Event, wrap_future from aiohttp import ClientSession -from yt_dlp import YoutubeDL +from asyncio import wait_for, Event, wrap_future from functools import partial +from pyrogram.filters import command, regex, user +from pyrogram.handlers import MessageHandler, CallbackQueryHandler from time import time +from yt_dlp import YoutubeDL from bot import DOWNLOAD_DIR, bot, config_dict, LOGGER -from bot.helper.telegram_helper.message_utils import ( - sendMessage, - editMessage, - deleteMessage, -) -from bot.helper.telegram_helper.button_build import ButtonMaker from bot.helper.ext_utils.bot_utils import ( new_task, sync_to_async, @@ -20,12 +14,18 @@ arg_parser, COMMAND_USAGE, ) +from bot.helper.ext_utils.links_utils import is_url +from bot.helper.ext_utils.status_utils import get_readable_file_size, get_readable_time +from bot.helper.listeners.task_listener import TaskListener from bot.helper.mirror_utils.download_utils.yt_dlp_download import YoutubeDLHelper from bot.helper.telegram_helper.bot_commands import BotCommands +from bot.helper.telegram_helper.button_build import ButtonMaker from bot.helper.telegram_helper.filters import CustomFilters -from bot.helper.listeners.task_listener import TaskListener -from bot.helper.ext_utils.status_utils import get_readable_file_size, get_readable_time -from bot.helper.ext_utils.links_utils import is_url +from bot.helper.telegram_helper.message_utils import ( + sendMessage, + editMessage, + deleteMessage, +) @new_task @@ -116,7 +116,7 @@ async def get_quality(self, result): buttons.ibutton("Best Audios", "ytq ba/b") buttons.ibutton("Cancel", "ytq cancel", "footer") self._main_buttons = buttons.build_menu(3) - msg = f"Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" else: format_dict = result.get("formats") if format_dict is not None: @@ -132,8 +132,8 @@ async def get_quality(self, result): size = 0 if item.get("video_ext") == "none" and ( - item.get("resolution") == "audio only" - or item.get("acodec") != "none" + item.get("resolution") == "audio only" + or item.get("acodec") != "none" ): if item.get("audio_ext") == "m4a": self._is_m4a = True @@ -169,7 +169,7 @@ async def get_quality(self, result): buttons.ibutton("Best Audio", "ytq ba/b") buttons.ibutton("Cancel", "ytq cancel", "footer") self._main_buttons = buttons.build_menu(2) - msg = f"Choose Video Quality:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Video Quality:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" self._reply_to = await sendMessage( self._listener.message, msg, self._main_buttons ) @@ -180,9 +180,9 @@ async def get_quality(self, result): async def back_to_main(self): if self._is_playlist: - msg = f"Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" else: - msg = f"Choose Video Quality:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Video Quality:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await editMessage(self._reply_to, msg, self._main_buttons) async def qual_subbuttons(self, b_name): @@ -194,7 +194,7 @@ async def qual_subbuttons(self, b_name): buttons.ibutton("Back", "ytq back", "footer") buttons.ibutton("Cancel", "ytq cancel", "footer") subbuttons = buttons.build_menu(2) - msg = f"Choose Bit rate for {b_name}:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Bit rate for {b_name}:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await editMessage(self._reply_to, msg, subbuttons) async def mp3_subbuttons(self): @@ -207,7 +207,7 @@ async def mp3_subbuttons(self): buttons.ibutton("Back", "ytq back") buttons.ibutton("Cancel", "ytq cancel") subbuttons = buttons.build_menu(3) - msg = f"Choose mp3 Audio{i} Bitrate:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose mp3 Audio{i} Bitrate:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await editMessage(self._reply_to, msg, subbuttons) async def audio_format(self): @@ -219,7 +219,7 @@ async def audio_format(self): buttons.ibutton("Back", "ytq back", "footer") buttons.ibutton("Cancel", "ytq cancel", "footer") subbuttons = buttons.build_menu(3) - msg = f"Choose Audio{i} Format:\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Audio{i} Format:\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await editMessage(self._reply_to, msg, subbuttons) async def audio_quality(self, format): @@ -231,7 +231,7 @@ async def audio_quality(self, format): buttons.ibutton("Back", "ytq aq back") buttons.ibutton("Cancel", "ytq aq cancel") subbuttons = buttons.build_menu(5) - msg = f"Choose Audio{i} Qaulity:\n0 is best and 10 is worst\nTimeout: {get_readable_time(self._timeout-(time()-self._time))}" + msg = f"Choose Audio{i} Qaulity:\n0 is best and 10 is worst\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}" await editMessage(self._reply_to, msg, subbuttons) @@ -247,7 +247,7 @@ async def _mdisk(link, name): key = link.split("/")[-1] async with ClientSession() as session: async with session.get( - f"https://diskuploader.entertainvideo.com/v1/file/cdnurl?param={key}" + f"https://diskuploader.entertainvideo.com/v1/file/cdnurl?param={key}" ) as resp: if resp.status == 200: resp_json = await resp.json() @@ -259,16 +259,16 @@ async def _mdisk(link, name): class YtDlp(TaskListener): def __init__( - self, - client, - message, - _=None, - isLeech=False, - __=None, - sameDir=None, - bulk=None, - multiTag=None, - options="", + self, + client, + message, + _=None, + isLeech=False, + __=None, + sameDir=None, + bulk=None, + multiTag=None, + options="", ): if sameDir is None: sameDir = {} @@ -408,7 +408,7 @@ async def newEvent(self): elif value.lower() == "false": value = False elif value.startswith(("{", "[", "(")) and value.endswith( - ("}", "]", ")") + ("}", "]", ")") ): value = eval(value) options[key] = value diff --git a/gen_sa_accounts.py b/gen_sa_accounts.py index db96f7f5f56..81d4d869356 100644 --- a/gen_sa_accounts.py +++ b/gen_sa_accounts.py @@ -5,14 +5,13 @@ from argparse import ArgumentParser from base64 import b64decode from glob import glob -from json import loads -from random import choice -from time import sleep - from google.auth.transport.requests import Request from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError +from json import loads +from random import choice +from time import sleep SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/iam'] @@ -26,15 +25,23 @@ def _create_accounts(service, project, count): batch = service.new_batch_http_request(callback=_def_batch_resp) for _ in range(count): aid = _generate_id('mfc-') - batch.add(service.projects().serviceAccounts().create(name='projects/' + project, body={'accountId': aid, - 'serviceAccount': { - 'displayName': aid}})) + batch.add( + service.projects() + .serviceAccounts() + .create( + name=f'projects/{project}', + body={ + 'accountId': aid, + 'serviceAccount': {'displayName': aid}, + }, + ) + ) batch.execute() # Create accounts needed to fill project def _create_remaining_accounts(iam, project): - print('Creating accounts in %s' % project) + print(f'Creating accounts in {project}') sa_count = len(_list_sas(iam, project)) while sa_count != 100: _create_accounts(iam, project, 100 - sa_count) @@ -58,14 +65,14 @@ def _def_batch_resp(id, resp, exception): if str(exception).startswith(' 0: current_count = len(_get_projects(cloud)) if current_count + create_projects <= max_projects: @@ -238,7 +252,7 @@ def serviceaccountfactory( ste = selected_projects elif enable_services == '*': ste = _get_projects(cloud) - services = [i + '.googleapis.com' for i in services] + services = [f'{i}.googleapis.com' for i in services] print('Enabling services') _enable_services(serviceusage, ste, services) if create_sas: @@ -269,7 +283,7 @@ def serviceaccountfactory( elif delete_sas == '*': std = _get_projects(cloud) for i in std: - print('Deleting service accounts in %s' % i) + print(f'Deleting service accounts in {i}') _delete_sas(iam, i) @@ -311,7 +325,7 @@ def serviceaccountfactory( print('No credentials found at %s. Please enable the Drive API in:\n' 'https://developers.google.com/drive/api/v3/quickstart/python\n' 'and save the json file as credentials.json' % args.credentials) - if len(options) < 1: + if not options: exit(-1) else: print('Select a credentials file below.') @@ -325,8 +339,9 @@ def serviceaccountfactory( if inp in inp_options: break args.credentials = inp if inp in options else options[int(inp) - 1] - print('Use --credentials %s next time to use this credentials file.' % - args.credentials) + print( + f'Use --credentials {args.credentials} next time to use this credentials file.' + ) if args.quick_setup: opt = '~' if args.new_only else '*' args.services = ['iam', 'drive'] @@ -353,7 +368,7 @@ def serviceaccountfactory( if resp: print('Projects (%d):' % len(resp)) for i in resp: - print(' ' + i) + print(f' {i}') else: print('No projects.') elif args.list_sas: @@ -361,6 +376,6 @@ def serviceaccountfactory( print('Service accounts in %s (%d):' % (args.list_sas, len(resp))) for i in resp: - print(' %s (%s)' % (i['email'], i['uniqueId'])) + print(f" {i['email']} ({i['uniqueId']})") else: print('No service accounts.') diff --git a/generate_drive_token.py b/generate_drive_token.py index 42101514e52..68fb922f7e9 100644 --- a/generate_drive_token.py +++ b/generate_drive_token.py @@ -1,7 +1,7 @@ -import pickle import os -from google_auth_oauthlib.flow import InstalledAppFlow +import pickle from google.auth.transport.requests import Request +from google_auth_oauthlib.flow import InstalledAppFlow credentials = None __G_DRIVE_TOKEN_FILE = "token.pickle" @@ -10,10 +10,10 @@ with open(__G_DRIVE_TOKEN_FILE, "rb") as f: credentials = pickle.load(f) if ( - (credentials is None or not credentials.valid) - and credentials - and credentials.expired - and credentials.refresh_token + (credentials is None or not credentials.valid) + and credentials + and credentials.expired + and credentials.refresh_token ): credentials.refresh(Request()) else: diff --git a/myjd/__init__.py b/myjd/__init__.py index d5955c4be61..678c8a490cf 100644 --- a/myjd/__init__.py +++ b/myjd/__init__.py @@ -1,4 +1,3 @@ -from .myjdapi import Myjdapi from .exception import ( MYJDException, MYJDConnectionException, @@ -33,5 +32,6 @@ MYJDTooManyRequestsException, MYJDUnknownException, ) +from .myjdapi import Myjdapi __version__ = "1.1.7" diff --git a/myjd/exception.py b/myjd/exception.py index dd307ebb72a..fbf0070310b 100644 --- a/myjd/exception.py +++ b/myjd/exception.py @@ -60,7 +60,7 @@ class MYJDApiException(MYJDException): @classmethod def get_exception( - cls, exception_source, exception_type=EXCEPTION_UNKNOWN, *args, **kwargs + cls, exception_source, exception_type=EXCEPTION_UNKNOWN, *args, **kwargs ): """Get exception object from MyJDownloader exception type.""" return EXCEPTION_CLASSES.get(exception_type.upper(), MYJDUnknownException)( diff --git a/myjd/myjdapi.py b/myjd/myjdapi.py index b2965126da0..1da0fe4db1e 100644 --- a/myjd/myjdapi.py +++ b/myjd/myjdapi.py @@ -1,13 +1,13 @@ # -*- encoding: utf-8 -*- +from Crypto.Cipher import AES +from base64 import b64encode, b64decode from hashlib import sha256 from hmac import new from json import dumps, loads, JSONDecodeError -from time import time -from urllib.parse import quote -from base64 import b64encode, b64decode from requests import get, post from requests.exceptions import RequestException -from Crypto.Cipher import AES +from time import time +from urllib.parse import quote from .exception import ( MYJDException, @@ -812,10 +812,10 @@ def __refresh_direct_connections(self): "/device/getDirectConnectionInfos", "POST", None, self.__action_url() ) if ( - response is not None - and "data" in response - and "infos" in response["data"] - and len(response["data"]["infos"]) != 0 + response is not None + and "data" in response + and "infos" in response["data"] + and len(response["data"]["infos"]) != 0 ): self.__update_direct_connections(response["data"]["infos"]) @@ -849,17 +849,17 @@ def disable_direct_connection(self): def action(self, path, params=(), http_action="POST"): action_url = self.__action_url() if ( - self.__direct_connection_enabled - and self.__direct_connection_info is not None - and time() >= self.__direct_connection_cooldown + self.__direct_connection_enabled + and self.__direct_connection_info is not None + and time() >= self.__direct_connection_cooldown ): return self.__direct_connect(path, http_action, params, action_url) response = self.myjd.request_api(path, http_action, params, action_url) if response is None: raise (MYJDConnectionException("No connection established\n")) if ( - self.__direct_connection_enabled - and time() >= self.__direct_connection_cooldown + self.__direct_connection_enabled + and time() >= self.__direct_connection_cooldown ): self.__refresh_direct_connections() return response["data"] @@ -881,7 +881,7 @@ def __direct_connect(self, path, http_action, params, action_url): conn["cooldown"] = time() + 60 self.__direct_connection_consecutive_failures += 1 self.__direct_connection_cooldown = time() + ( - 60 * self.__direct_connection_consecutive_failures + 60 * self.__direct_connection_consecutive_failures ) response = self.myjd.request_api(path, http_action, params, action_url) if response is None: @@ -984,7 +984,7 @@ def __decrypt(self, secret_token, data): :param data: """ init_vector = secret_token[: len(secret_token) // 2] - key = secret_token[len(secret_token) // 2 :] + key = secret_token[len(secret_token) // 2:] decryptor = AES.new(key, AES.MODE_CBC, init_vector) return UNPAD(decryptor.decrypt(b64decode(data))) @@ -997,7 +997,7 @@ def __encrypt(self, secret_token, data): """ data = PAD(data.encode("utf-8")) init_vector = secret_token[: len(secret_token) // 2] - key = secret_token[len(secret_token) // 2 :] + key = secret_token[len(secret_token) // 2:] encryptor = AES.new(key, AES.MODE_CBC, init_vector) encrypted_data = b64encode(encryptor.encrypt(data)) return encrypted_data.decode("utf-8") @@ -1212,13 +1212,13 @@ def request_api(self, path, http_method="GET", params=None, action=None, api=Non "Failed to decode response: {}", encrypted_response.text ) from exc msg = ( - "\n\tSOURCE: " - + error_msg["src"] - + "\n\tTYPE: " - + error_msg["type"] - + "\n------\nREQUEST_URL: " - + api - + path + "\n\tSOURCE: " + + error_msg["src"] + + "\n\tTYPE: " + + error_msg["type"] + + "\n------\nREQUEST_URL: " + + api + + path ) if http_method == "GET": msg += query diff --git a/update.py b/update.py index 0852ed0188a..aaf69a0799e 100644 --- a/update.py +++ b/update.py @@ -1,3 +1,4 @@ +from dotenv import load_dotenv, dotenv_values from logging import ( FileHandler, StreamHandler, @@ -7,9 +8,8 @@ info as log_info, ) from os import path, environ, remove -from subprocess import run as srun -from dotenv import load_dotenv, dotenv_values from pymongo import MongoClient +from subprocess import run as srun if path.exists("log.txt"): with open("log.txt", "r+") as f: @@ -53,9 +53,9 @@ if old_config is not None: del old_config["_id"] if ( - old_config is not None - and old_config == dict(dotenv_values("config.env")) - or old_config is None + old_config is not None + and old_config == dict(dotenv_values("config.env")) + or old_config is None ) and config_dict is not None: environ["UPSTREAM_REPO"] = config_dict["UPSTREAM_REPO"] environ["UPSTREAM_BRANCH"] = config_dict["UPSTREAM_BRANCH"] diff --git a/web/nodes.py b/web/nodes.py index 1c00b637db4..7531af45dee 100644 --- a/web/nodes.py +++ b/web/nodes.py @@ -1,6 +1,6 @@ from anytree import NodeMixin -from re import findall as re_findall from os import environ +from re import findall as re_findall DOWNLOAD_DIR = environ.get('DOWNLOAD_DIR', '') if len(DOWNLOAD_DIR) == 0: @@ -10,7 +10,8 @@ class TorNode(NodeMixin): - def __init__(self, name, is_folder=False, is_file=False, parent=None, size=None, priority=None, file_id=None, progress=None): + def __init__(self, name, is_folder=False, is_file=False, parent=None, size=None, priority=None, file_id=None, + progress=None): super().__init__() self.name = name self.is_folder = is_folder @@ -31,10 +32,12 @@ def __init__(self, name, is_folder=False, is_file=False, parent=None, size=None, def qb_get_folders(path): return path.split("/") + def get_folders(path): fs = re_findall(f'{DOWNLOAD_DIR}[0-9]+/(.+)', path)[0] return fs.split('/') + def make_tree(res, aria2=False): parent = TorNode("Torrent") if not aria2: @@ -42,17 +45,17 @@ def make_tree(res, aria2=False): folders = qb_get_folders(i.name) if len(folders) > 1: previous_node = parent - for j in range(len(folders)-1): + for j in range(len(folders) - 1): current_node = next((k for k in previous_node.children if k.name == folders[j]), None) if current_node is None: previous_node = TorNode(folders[j], parent=previous_node, is_folder=True) else: previous_node = current_node TorNode(folders[-1], is_file=True, parent=previous_node, size=i.size, priority=i.priority, \ - file_id=i.id, progress=round(i.progress*100, 5)) + file_id=i.id, progress=round(i.progress * 100, 5)) else: TorNode(folders[-1], is_file=True, parent=parent, size=i.size, priority=i.priority, \ - file_id=i.id, progress=round(i.progress*100, 5)) + file_id=i.id, progress=round(i.progress * 100, 5)) else: for i in res: folders = get_folders(i['path']) @@ -61,19 +64,20 @@ def make_tree(res, aria2=False): priority = 0 if len(folders) > 1: previous_node = parent - for j in range(len(folders)-1): + for j in range(len(folders) - 1): current_node = next((k for k in previous_node.children if k.name == folders[j]), None) if current_node is None: previous_node = TorNode(folders[j], parent=previous_node, is_folder=True) else: previous_node = current_node TorNode(folders[-1], is_file=True, parent=previous_node, size=i['length'], priority=priority, \ - file_id=i['index'], progress=round((int(i['completedLength'])/int(i['length']))*100, 5)) + file_id=i['index'], progress=round((int(i['completedLength']) / int(i['length'])) * 100, 5)) else: TorNode(folders[-1], is_file=True, parent=parent, size=i['length'], priority=priority, \ - file_id=i['index'], progress=round((int(i['completedLength'])/int(i['length']))*100, 5)) + file_id=i['index'], progress=round((int(i['completedLength']) / int(i['length'])) * 100, 5)) return create_list(parent, ["", 0]) + """ def print_tree(parent): for pre, _, node in RenderTree(parent): @@ -81,6 +85,7 @@ def print_tree(parent): print(treestr.ljust(8), node.is_folder, node.is_file) """ + def create_list(par, msg): if par.name != ".unwanted": msg[0] += '
    ' @@ -95,9 +100,11 @@ def create_list(par, msg): else: msg[0] += '
  • ' if i.priority == 0: - msg[0] += f' / {i.progress}%' + msg[ + 0] += f' / {i.progress}%' else: - msg[0] += f' / {i.progress}%' + msg[ + 0] += f' / {i.progress}%' msg[0] += f'' msg[0] += "
  • " diff --git a/web/wserver.py b/web/wserver.py index 3560e1c1975..56a33592168 100644 --- a/web/wserver.py +++ b/web/wserver.py @@ -1,8 +1,8 @@ -from logging import getLogger, FileHandler, StreamHandler, INFO, basicConfig -from time import sleep -from qbittorrentapi import NotFound404Error, Client as qbClient from aria2p import API as ariaAPI, Client as ariaClient from flask import Flask, request +from logging import getLogger, FileHandler, StreamHandler, INFO, basicConfig +from qbittorrentapi import NotFound404Error, Client as qbClient +from time import sleep from web.nodes import make_tree @@ -11,8 +11,8 @@ aria2 = ariaAPI(ariaClient(host="http://localhost", port=6800, secret="")) basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - handlers=[FileHandler('log.txt'), StreamHandler()], - level=INFO) + handlers=[FileHandler('log.txt'), StreamHandler()], + level=INFO) LOGGER = getLogger(__name__) @@ -648,8 +648,8 @@ """ -def re_verfiy(paused, resumed, client, hash_id): +def re_verfiy(paused, resumed, client, hash_id): paused = paused.strip() resumed = resumed.strip() if paused: @@ -692,9 +692,9 @@ def re_verfiy(paused, resumed, client, hash_id): LOGGER.info(f"Verified! Hash: {hash_id}") return True + @app.route('/app/files/', methods=['GET']) def list_torrent_contents(id_): - if "pin_code" not in request.args.keys(): return code_page.replace("{form_url}", f"/app/files/{id_}") @@ -717,9 +717,9 @@ def list_torrent_contents(id_): cont = make_tree(res, True) return page.replace("{My_content}", cont[0]).replace("{form_url}", f"/app/files/{id_}?pin_code={pincode}") + @app.route('/app/files/', methods=['POST']) def set_priority(id_): - data = dict(request.form) resume = "" @@ -771,14 +771,16 @@ def set_priority(id_): LOGGER.info(f"Verification Failed! Report! Gid: {id_}") return list_torrent_contents(id_) + @app.route('/') def homepage(): return "

    See mirror-leech-telegram-bot @GitHub By Anas

    " + @app.errorhandler(Exception) def page_not_found(e): return f"

    404: Torrent not found! Mostly wrong input.

    Error: {e}

    ", 404 + if __name__ == "__main__": app.run() -