diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..cd1694374
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,68 @@
+name: MirrorX Release
+
+on:
+ push:
+ tags:
+ - "v*.*.*"
+
+jobs:
+ BuildWheel:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.8.12
+ - name: Get the version
+ id: get_version
+ run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
+ - name: Install deps fro Pypi Release
+ run: |
+ pip -q install setuptools wheel twine
+ pip -q install -r requirements.txt
+ - name: Publish to pypi
+ env:
+ TWINE_USERNAME: __token__
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
+ run: |
+ python setup.py sdist bdist_wheel
+ twine upload dist/* || exit 0
+ - name: Upload all the data files to github Release
+ uses: softprops/action-gh-release@v1
+ with:
+ name: MirrorX Release ${{ steps.get_version.outputs.VERSION }}
+ files: |
+ dist/*
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Sleep
+ run: sleep 60
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v1
+ with:
+ platforms: arm64
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v1
+ with:
+ registry: ghcr.io
+ username: token
+ password: ${{ secrets.GH_TOKEN }}
+ - name: Docker meta
+ id: metaraw
+ uses: docker/metadata-action@v3
+ with:
+ images: ghcr.io/iamliquidx/mirrorx
+ tags: |
+ type=semver,pattern={{version}}
+ - name: Build and push Docker images
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ file: ./Dockerfile
+ platforms: linux/amd64, linux/arm64/v8
+ push: true
+ tags: ${{ steps.metaraw.outputs.tags }}
+ labels: ${{ steps.metaraw.outputs.labels }}
diff --git a/.gitignore b/.gitignore
index 86facd3c1..ac258eaab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,20 @@
config.env
*auth_token.txt
-*.pyc
downloads/*
download/*
-data*
.vscode
.idea
*.json
*.pickle
authorized_chats.txt
log.txt
-accounts/*
\ No newline at end of file
+accounts/*
+*.pyc
+dht6.dat
+aria.conf
+.gitignore
+dht.dat
+build
+dist
+*.spec
+/venv/
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index ea40a2d28..000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "vendor/cmrudl.py"]
- path = vendor/cmrudl.py
- url = https://github.com/JrMasterModelBuilder/cmrudl.py.git
diff --git a/Dockerfile b/Dockerfile
index 9d3313774..bd340f79c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,38 +1,30 @@
-FROM ubuntu:18.04
+FROM python:3.9-slim
-WORKDIR /usr/src/app
-RUN chmod 777 /usr/src/app
+WORKDIR /
+# Deps
-RUN apt-get -qq update
-RUN apt-get -qq install -y python3 python3-pip rar unzip git aria2 g++ gcc autoconf automake \
- m4 libtool qt4-qmake make libqt4-dev libcurl4-openssl-dev \
- libcrypto++-dev libsqlite3-dev libc-ares-dev \
- libsodium-dev libnautilus-extension-dev \
- libssl-dev libfreeimage-dev swig curl pv jq ffmpeg locales python3-lxml
+SHELL [ "/usr/bin/bash" , "-cel" ]
-# Installing mega sdk python binding
-ENV MEGA_SDK_VERSION '3.6.4'
-RUN git clone https://github.com/meganz/sdk.git sdk
-WORKDIR sdk
-RUN git checkout v$MEGA_SDK_VERSION && ./autogen.sh && \
- ./configure --disable-silent-rules --enable-python --disable-examples && \
- make -j$(nproc --all) && cd bindings/python/ && \
- python3 setup.py bdist_wheel && cd dist/ && \
- pip3 install --no-cache-dir megasdk-$MEGA_SDK_VERSION-*.whl
+RUN \
+[[ ${valid_arch:-aarch64 amd64 x86_64} =~ ${HOST_CPU_ARCH:=$(uname -m)} ]] \
+ || echo 'unsupported cpu arch' && exit 1
+RUN \
+export HOST_CPU_ARCH=$(uname -m) \
+sed -i 's/main/main non-free/g' /etc/apt/sources.list && \
+apt-get -qq update && \
+apt-get -qq install -y tzdata curl aria2 p7zip-full p7zip-rar wget xz-utils libmagic-dev gcc libffi-dev nscd && \
+apt-get -y autoremove && rm -rf /var/lib/apt/lists/* && apt-get clean && \
+wget -q https://github.com/yzop/gg/raw/main/ffmpeg-git-${HOST_CPU_ARCH}-static.tar.xz && \
+tar -xf ff*.tar.xz && rm -rf *.tar.xz && \
+mv ff*/ff* /usr/local/bin/ && rm -rf ff* && \
+wget -q https://github.com/viswanathbalusu/megasdkrest/releases/latest/download/megasdkrest-${HOST_CPU_ARCH} -O /usr/local/bin/megasdkrest && \
+chmod a+x /usr/local/bin/megasdkrest && mkdir /app/ && chmod 777 /app/ && \
+pip3 install --no-cache-dir MirrorX && \
+apt-get purge -yqq gcc && apt-get -y autoremove && rm -rf /var/lib/apt/lists/* && apt-get clean
-COPY requirements.txt .
-COPY extract /usr/local/bin
-RUN chmod +x /usr/local/bin/extract
-RUN pip3 install --no-cache-dir -r requirements.txt
-RUN locale-gen en_US.UTF-8
-ENV LANG en_US.UTF-8
-ENV LANGUAGE en_US:en
-ENV LC_ALL en_US.UTF-8
-COPY . .
-COPY netrc /root/.netrc
-RUN chmod +x aria.sh
-
-CMD ["bash","start.sh"]
+WORKDIR /app
+CMD ["MirrorX"]
+###
diff --git a/README.md b/README.md
index a9e837d7c..7d7bc2555 100644
--- a/README.md
+++ b/README.md
@@ -1,151 +1,38 @@
-# What is this repo about?
-This is a telegram bot writen in python for mirroring files on the internet to our beloved Google Drive.
-
-# Inspiration
-This project is heavily inspired from @out386 's telegram bot which is written in JS.
-
-# Features supported:
-- Mirroring direct download links to google drive
-- Mirroring Mega.nz links to google drive (In development stage)
-- Mirror Telegram files to google drive
-- Mirror all youtube-dl supported links
-- Extract zip, rar, tar and many supported file types and uploads to google drive
-- Copy files from someone's drive to your drive (using Rclone)
-- Service account support in cloning and uploading
-- Download progress
-- Upload progress
-- Download/upload speeds and ETAs
-- Docker support
-- Uploading To Team Drives.
-- Index Link support
-
-# Bot commands to be set in botfather
-
-```
-mirror - Start Mirroring
-tarmirror - Upload tar (zipped) file
-unzipmirror - Extract files
-clone - copy folder to drive
-watch - mirror YT-DL support link
-tarwatch - mirror youtube playlist link as tar
-cancel - Cancel a task
-cancelall - Cancel all tasks
-list - [query] searches files in G-Drive
-status - Get Mirror Status message
-stats - Bot Usage Stats
-help - Get Detailed Help
-log - Bot Log [owner only]
-```
-
-# How to deploy?
-Deploying is pretty much straight forward and is divided into several steps as follows:
-## Installing requirements
-
-- Clone this repo:
-```
-git clone https://github.com/magneto261290/magneto-python-aria mirror-bot/
-cd mirror-bot
-```
-
-- Install requirements
-For Debian based distros
-```
-sudo apt install python3
-sudo snap install docker
-```
-- For Arch and it's derivatives:
-```
-sudo pacman -S docker python
-```
-
-## Setting up config file
-```
-cp config_sample.env config.env
-```
-- Remove the first line saying:
-```
-_____REMOVE_THIS_LINE_____=True
-```
-Fill up rest of the fields. Meaning of each fields are discussed below:
-- **BOT_TOKEN** : The telegram bot token that you get from @BotFather
-- **GDRIVE_FOLDER_ID** : This is the folder ID of the Google Drive Folder to which you want to upload all the mirrors.
-- **DOWNLOAD_DIR** : The path to the local folder where the downloads should be downloaded to
-- **DOWNLOAD_STATUS_UPDATE_INTERVAL** : A short interval of time in seconds after which the Mirror progress message is updated. (I recommend to keep it 5 seconds at least)
-- **OWNER_ID** : The Telegram user ID (not username) of the owner of the bot
-- **AUTO_DELETE_MESSAGE_DURATION** : Interval of time (in seconds), after which the bot deletes it's message (and command message) which is expected to be viewed instantly. Note: Set to -1 to never automatically delete messages
-- **IS_TEAM_DRIVE** : (Optional field) Set to "True" if GDRIVE_FOLDER_ID is from a Team Drive else False or Leave it empty.
-- **USE_SERVICE_ACCOUNTS**: (Optional field) (Leave empty if unsure) Whether to use service accounts or not. For this to work see "Using service accounts" section below.
-- **INDEX_URL** : (Optional field) Refer to https://github.com/maple3142/GDIndex/ The URL should not have any trailing '/'
-- **API_KEY** : This is to authenticate to your telegram account for downloading Telegram files. You can get this from https://my.telegram.org DO NOT put this in quotes.
-- **API_HASH** : This is to authenticate to your telegram account for downloading Telegram files. You can get this from https://my.telegram.org
-- **USER_SESSION_STRING** : Session string generated by running:
-- **MEGA_API_KEY**: Mega.nz api key to mirror mega.nz links. Get it from [Mega SDK Page](https://mega.nz/sdk)
-```
-python3 generate_string_session.py
-```
-Note: You can limit maximum concurrent downloads by changing the value of MAX_CONCURRENT_DOWNLOADS in aria.sh. By default, it's set to 2
-
-## Getting Google OAuth API credential file
-
-- Visit the [Google Cloud Console](https://console.developers.google.com/apis/credentials)
-- Go to the OAuth Consent tab, fill it, and save.
-- Go to the Credentials tab and click Create Credentials -> OAuth Client ID
-- Choose Other and Create.
-- Use the download button to download your credentials.
-- Move that file to the root of mirror-bot, and rename it to credentials.json
-- Visit [Google API page](https://console.developers.google.com/apis/library)
-- Search for Drive and enable it if it is disabled
-- Finally, run the script to generate token file (token.pickle) for Google Drive:
-```
-pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
-python3 generate_drive_token.py
-```
-## Deploying
-
-- Start docker daemon (skip if already running):
-```
-sudo dockerd
-```
-- Build Docker image:
-```
-sudo docker build . -t mirror-bot
-```
-- Run the image:
-```
-sudo docker run mirror-bot
-```
-
-# 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
-Many thanks to [AutoRClone](https://github.com/xyou365/AutoRclone) for the scripts
-## Generating service accounts
-Step 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 autorclone and we do **NOT** recommend that you make a lot of projects, just one project and 100 sa allow you plenty of use, its also possible that overabuse might get your projects banned by google.
-
-```
-Note: 1 service account can copy around 750gb a day, 1 project makes 100 service accounts so thats 75tb a day, for most users this should easily suffice.
-```
-
-`python3 gen_sa_accounts.py --quick-setup 1 --new-only`
-
-A folder named accounts will be created which will contain keys for the service accounts created
-
-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 project_id
-```
-
-### Add all the service accounts to the Team Drive or folder
-- Run:
-```
-python3 add_to_team_drive.py -d SharedTeamDriveSrcID
-```
-
-# Youtube-dl authentication using .netrc file
-For using your premium accounts in youtube-dl, edit the netrc file (in the root directory of this repository) according to following format:
-```
-machine host login username password my_youtube_password
-```
-where host is the name of extractor (eg. youtube, twitch). Multiple accounts of different hosts can be added each separated by a new line
\ No newline at end of file
+
+
+
+
+
+
+
+# This Is A Telegram Bot Written In Python For Mirroring Files On The Internet To Our Beloved Google Drive.
+
+
+Here Are Some Things To Get You Started.👇
+
+
+## 👉[All The Feature Of This Bot Or What This Bot Can Do For You.](https://github.com/iamLiquidX/MirrorX/wiki/Feature-Or-What-This-Bot-Can-Do)
+
+## 👉[How To Deploy](https://github.com/iamLiquidX/MirrorX/wiki/How-To-Deploy)
+
+## 👉[Commands To Use The Bot](https://github.com/iamLiquidX/MirrorX/wiki/Commands-To-Use-This-Bot)
+
+## 👉[Modification Guide](https://github.com/iamLiquidX/MirrorX/wiki/Modification)
+
+
+For The Most Recent Changes, Please Check The Changelog.👇
+
+## 👉[Changelog](https://github.com/iamLiquidX/MirrorX/wiki/Changelog)
+
+
+
+# Credits 👇
+
+1. [Shivam Jha aka lzzy12](https://github.com/lzzy12) & [JaskaranSM aka Zero Cool](https://github.com/jaskaranSM) - They Built This Bot From Scratch.
+2. [Sreeraj V R](https://github.com/SVR666)- Added Inline Button, Added Support For Deleting File/Folders From GDrive, Search Results On Telegra.ph.
+3. [Archie](https://github.com/archie9211) - Added Support For Extraction Of Archives, Fixed SSL Handshake Error, Update Trackers Dynamically.
+4. [Magneto](https://github.com/magneto261290) - Added Alot Of Customization, Support For Custom File Names, Support For Password Protected Archives, Quality Selection Option In YTDL And Much More.
+5. [KenHV](https://github.com/KenHV) - Many Fixes And Imporovements.
+6. [Anos](https://github.com/destiny6520) - Modification/Customization Guide.
+7. [Viswanath](https://github.com/nenokkadine) - Fixes & Improvements, Dockerfile Clean Up, DHT Support In Aria.
+8. [breakdowns](https://github.com/breakdowns) - Source Code For Count,Zip/Unzip GDrive Links & Fembed.
diff --git a/aria.bat b/aria.bat
deleted file mode 100644
index 388080057..000000000
--- a/aria.bat
+++ /dev/null
@@ -1 +0,0 @@
-aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port 6800 --max-connection-per-server=10 --rpc-max-request-size=1024M --seed-time=0.01 --min-split-size=10M --follow-torrent=mem --split=10 --daemon=true --allow-overwrite=true
diff --git a/aria.sh b/aria.sh
deleted file mode 100755
index efd9ab0d7..000000000
--- a/aria.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-export MAX_DOWNLOAD_SPEED=0
-export MAX_CONCURRENT_DOWNLOADS=3
-aria2c --enable-rpc --rpc-listen-all=false --rpc-listen-port 6800 \
- --max-connection-per-server=10 --rpc-max-request-size=1024M \
- --seed-time=0.01 --min-split-size=10M --follow-torrent=mem --split=10 \
- --daemon=true --allow-overwrite=true --max-overall-download-limit=$MAX_DOWNLOAD_SPEED \
- --max-overall-upload-limit=1K --max-concurrent-downloads=$MAX_CONCURRENT_DOWNLOADS
diff --git a/bin/MirrorX b/bin/MirrorX
new file mode 100644
index 000000000..7c40066fb
--- /dev/null
+++ b/bin/MirrorX
@@ -0,0 +1,3 @@
+#!/bin/bash
+pip3 install -U MirrorX
+MirrorXBot
\ No newline at end of file
diff --git a/bin/extract b/bin/extract
new file mode 100755
index 000000000..bd05693c6
--- /dev/null
+++ b/bin/extract
@@ -0,0 +1,194 @@
+#!/bin/bash
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $(basename $0) FILES"
+ exit 1
+fi
+
+extract() {
+ arg="$1"
+ cd "$(dirname "$arg")" || exit
+ case "$arg" in
+ *.tar.bz2)
+ tar xjf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.tar.gz)
+ tar xzf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.bz2)
+ bunzip2 "$arg"
+ local code=$?
+ ;;
+ *.gz)
+ gunzip "$arg"
+ local code=$?
+ ;;
+ *.tar)
+ tar xf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.tbz2)
+ (tar xjf "$arg" --one-top-level)
+ local code=$?
+ ;;
+ *.tgz)
+ tar xzf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.zip)
+ a_dir=$(expr "$arg" : '\(.*\).zip')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.7z)
+ a_dir=$(expr "$arg" : '\(.*\).7z')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.Z)
+ uncompress "$arg"
+ local code=$?
+ ;;
+ *.rar)
+ a_dir=$(expr "$arg" : '\(.*\).rar')
+ mkdir "$a_dir"
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.iso)
+ a_dir=$(expr "$arg" : '\(.*\).iso')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.wim)
+ a_dir=$(expr "$arg" : '\(.*\).wim')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.cab)
+ a_dir=$(expr "$arg" : '\(.*\).cab')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.apm)
+ a_dir=$(expr "$arg" : '\(.*\).apm')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.arj)
+ a_dir=$(expr "$arg" : '\(.*\).arj')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.chm)
+ a_dir=$(expr "$arg" : '\(.*\).chm')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.cpio)
+ a_dir=$(expr "$arg" : '\(.*\).cpio')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.cramfs)
+ a_dir=$(expr "$arg" : '\(.*\).cramfs')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.deb)
+ a_dir=$(expr "$arg" : '\(.*\).deb')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.dmg)
+ a_dir=$(expr "$arg" : '\(.*\).dmg')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.fat)
+ a_dir=$(expr "$arg" : '\(.*\).fat')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.hfs)
+ a_dir=$(expr "$arg" : '\(.*\).hfs')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.lzh)
+ a_dir=$(expr "$arg" : '\(.*\).lzh')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.lzma)
+ a_dir=$(expr "$arg" : '\(.*\).lzma')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.lzma2)
+ a_dir=$(expr "$arg" : '\(.*\).lzma2')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.mbr)
+ a_dir=$(expr "$arg" : '\(.*\).mbr')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.msi)
+ a_dir=$(expr "$arg" : '\(.*\).msi')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.mslz)
+ a_dir=$(expr "$arg" : '\(.*\).mslz')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.nsis)
+ a_dir=$(expr "$arg" : '\(.*\).nsis')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.ntfs)
+ a_dir=$(expr "$arg" : '\(.*\).ntfs')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.rpm)
+ a_dir=$(expr "$arg" : '\(.*\).rpm')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.squashfs)
+ a_dir=$(expr "$arg" : '\(.*\).squashfs')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.udf)
+ a_dir=$(expr "$arg" : '\(.*\).udf')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.vhd)
+ a_dir=$(expr "$arg" : '\(.*\).vhd')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *.xar)
+ a_dir=$(expr "$arg" : '\(.*\).xar')
+ 7z x "$arg" -o"$a_dir"
+ local code=$?
+ ;;
+ *)
+ echo "'$arg' cannot be extracted via extract()" 1>&2
+ exit 1
+ ;;
+ esac
+ cd - || exit $?
+ exit $code
+}
+
+extract "$1"
diff --git a/bin/pextract b/bin/pextract
new file mode 100644
index 000000000..297a0eafc
--- /dev/null
+++ b/bin/pextract
@@ -0,0 +1,195 @@
+#!/bin/bash
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $(basename $0) FILES"
+ exit 1
+fi
+
+extract() {
+ arg="$1"
+ pswd="$2"
+ cd "$(dirname "$arg")" || exit
+ case "$arg" in
+ *.tar.bz2)
+ tar xjf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.tar.gz)
+ tar xzf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.bz2)
+ bunzip2 "$arg"
+ local code=$?
+ ;;
+ *.gz)
+ gunzip "$arg"
+ local code=$?
+ ;;
+ *.tar)
+ tar xf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.tbz2)
+ (tar xjf "$arg" --one-top-level)
+ local code=$?
+ ;;
+ *.tgz)
+ tar xzf "$arg" --one-top-level
+ local code=$?
+ ;;
+ *.zip)
+ a_dir=$(expr "$arg" : '\(.*\).zip')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.7z)
+ a_dir=$(expr "$arg" : '\(.*\).7z')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.Z)
+ uncompress "$arg"
+ local code=$?
+ ;;
+ *.rar)
+ a_dir=$(expr "$arg" : '\(.*\).rar')
+ mkdir "$a_dir"
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.iso)
+ a_dir=$(expr "$arg" : '\(.*\).iso')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.wim)
+ a_dir=$(expr "$arg" : '\(.*\).wim')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.cab)
+ a_dir=$(expr "$arg" : '\(.*\).cab')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.apm)
+ a_dir=$(expr "$arg" : '\(.*\).apm')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.arj)
+ a_dir=$(expr "$arg" : '\(.*\).arj')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.chm)
+ a_dir=$(expr "$arg" : '\(.*\).chm')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.cpio)
+ a_dir=$(expr "$arg" : '\(.*\).cpio')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.cramfs)
+ a_dir=$(expr "$arg" : '\(.*\).cramfs')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.deb)
+ a_dir=$(expr "$arg" : '\(.*\).deb')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.dmg)
+ a_dir=$(expr "$arg" : '\(.*\).dmg')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.fat)
+ a_dir=$(expr "$arg" : '\(.*\).fat')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.hfs)
+ a_dir=$(expr "$arg" : '\(.*\).hfs')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.lzh)
+ a_dir=$(expr "$arg" : '\(.*\).lzh')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.lzma)
+ a_dir=$(expr "$arg" : '\(.*\).lzma')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.lzma2)
+ a_dir=$(expr "$arg" : '\(.*\).lzma2')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.mbr)
+ a_dir=$(expr "$arg" : '\(.*\).mbr')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.msi)
+ a_dir=$(expr "$arg" : '\(.*\).msi')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.mslz)
+ a_dir=$(expr "$arg" : '\(.*\).mslz')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.nsis)
+ a_dir=$(expr "$arg" : '\(.*\).nsis')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.ntfs)
+ a_dir=$(expr "$arg" : '\(.*\).ntfs')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.rpm)
+ a_dir=$(expr "$arg" : '\(.*\).rpm')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.squashfs)
+ a_dir=$(expr "$arg" : '\(.*\).squashfs')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.udf)
+ a_dir=$(expr "$arg" : '\(.*\).udf')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.vhd)
+ a_dir=$(expr "$arg" : '\(.*\).vhd')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *.xar)
+ a_dir=$(expr "$arg" : '\(.*\).xar')
+ 7z x "$arg" -o"$a_dir" -p"$pswd"
+ local code=$?
+ ;;
+ *)
+ echo "'$arg' cannot be extracted via extract()" 1>&2
+ exit 1
+ ;;
+ esac
+ cd - || exit $?
+ exit $code
+}
+
+extract "$1" "$2"
\ No newline at end of file
diff --git a/bot/__init__.py b/bot/__init__.py
index c08dee660..756cf6675 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -2,11 +2,24 @@
import os
import threading
import time
+import random
+import string
+import subprocess
+import pkgutil
+import pathlib
+import sys
import aria2p
+import requests
import telegram.ext as tg
from dotenv import load_dotenv
+from pyrogram import Client
+from telegraph import Telegraph
+from megasdkrestclient import MegaSdkRestClient, errors as mega_err
+
import socket
+import faulthandler
+faulthandler.enable()
socket.setdefaulttimeout(600)
@@ -36,6 +49,35 @@ def getConfig(name: str):
exit()
except KeyError:
pass
+CWD = os.getcwd()
+ariaconfig = pkgutil.get_data("bot", "data/aria.conf").decode()
+dhtfile = pkgutil.get_data("bot", "data/dht.dat")
+dht6file = pkgutil.get_data("bot", "data/dht6.dat")
+with open("dht.dat", "wb+") as dht:
+ dht.write(dhtfile)
+with open("dht6.dat", "wb+") as dht6:
+ dht6.write(dhtfile)
+ariaconfig = ariaconfig.replace("/currentwd", str(CWD))
+try:
+ max_dl = getConfig("MAX_CONCURRENT_DOWNLOADS")
+except KeyError:
+ max_dl = "4"
+tracker_list = requests.get("https://raw.githubusercontent.com/XIU2/TrackersListCollection/master/all_aria2.txt").text
+ariaconfig += f"\nmax-concurrent-downloads={max_dl}\nbt-tracker={tracker_list}"
+
+with open("aria.conf", "w+") as ariaconf:
+ ariaconf.write(ariaconfig)
+
+ARIA_CHILD_PROC = None
+try:
+ ARIA_CHILD_PROC = subprocess.Popen(["aria2c", f"--conf-path={CWD}/aria.conf"])
+except FileNotFoundError:
+ LOGGER.error("Please install Aria2c, Exiting..")
+ sys.exit(0)
+except OSError:
+ LOGGER.error("Aria2c Binary might have got damaged, Please Check and reinstall..")
+ sys.exit(0)
+time.sleep(1)
aria2 = aria2p.API(
aria2p.Client(
@@ -64,33 +106,124 @@ def getConfig(name: str):
for line in lines:
# LOGGER.info(line.split())
AUTHORIZED_CHATS.add(int(line.split()[0]))
+try:
+ achats = getConfig('AUTHORIZED_CHATS')
+ achats = achats.split(" ")
+ for chats in achats:
+ AUTHORIZED_CHATS.add(int(chats))
+except:
+ pass
+
try:
BOT_TOKEN = getConfig('BOT_TOKEN')
parent_id = getConfig('GDRIVE_FOLDER_ID')
DOWNLOAD_DIR = getConfig('DOWNLOAD_DIR')
- if DOWNLOAD_DIR[-1] != '/' or DOWNLOAD_DIR[-1] != '\\':
+ if not DOWNLOAD_DIR.endswith("/"):
DOWNLOAD_DIR = DOWNLOAD_DIR + '/'
+ if not os.path.exists(DOWNLOAD_DIR):
+ os.makedirs(DOWNLOAD_DIR, 0o777)
DOWNLOAD_STATUS_UPDATE_INTERVAL = int(getConfig('DOWNLOAD_STATUS_UPDATE_INTERVAL'))
OWNER_ID = int(getConfig('OWNER_ID'))
AUTO_DELETE_MESSAGE_DURATION = int(getConfig('AUTO_DELETE_MESSAGE_DURATION'))
- USER_SESSION_STRING = getConfig('USER_SESSION_STRING')
TELEGRAM_API = getConfig('TELEGRAM_API')
TELEGRAM_HASH = getConfig('TELEGRAM_HASH')
except KeyError as e:
LOGGER.error("One or more env variables missing! Exiting now")
- exit(1)
+ sys.exit()
+ # exit()
+
+LOGGER.info("Generating USER_SESSION_STRING")
+app = Client(':memory:', api_id=int(TELEGRAM_API), api_hash=TELEGRAM_HASH, bot_token=BOT_TOKEN)
+
+#Generate Telegraph Token
+sname = ''.join(random.SystemRandom().choices(string.ascii_letters, k=8))
+LOGGER.info("Generating Telegraph Token using '" + sname + "' name")
+telegraph = Telegraph()
+telegraph.create_account(short_name=sname)
+telegraph_token = telegraph.get_access_token()
+LOGGER.info("Telegraph Token Generated: '" + telegraph_token + "'")
try:
- MEGA_API_KEY = getConfig('MEGA_API_KEY')
+ UPTOBOX_TOKEN = getConfig('UPTOBOX_TOKEN')
except KeyError:
- logging.warning('MEGA Api key not provided!')
- MEGA_API_KEY = None
+ logging.warning('UPTOBOX_TOKEN not provided!')
+ UPTOBOX_TOKEN = None
+
+try:
+ MEGA_KEY = getConfig('MEGA_KEY')
+except KeyError:
+ MEGA_KEY = None
+ LOGGER.info('MEGA API KEY NOT AVAILABLE')
+MEGA_CHILD_PROC = None
+if MEGA_KEY is not None:
+ try:
+ MEGA_CHILD_PROC = subprocess.Popen(["megasdkrest", "--apikey", MEGA_KEY])
+ except FileNotFoundError:
+ LOGGER.error("Please install Megasdkrest Binary, Exiting..")
+ sys.exit(0)
+ except OSError:
+ LOGGER.error("Megasdkrest Binary might have got damaged, Please Check ..")
+ sys.exit(0)
+ time.sleep(3)
+ mega_client = MegaSdkRestClient('http://localhost:6090')
+ try:
+ MEGA_USERNAME = getConfig('MEGA_USERNAME')
+ MEGA_PASSWORD = getConfig('MEGA_PASSWORD')
+ if len(MEGA_USERNAME) > 0 and len(MEGA_PASSWORD) > 0:
+ try:
+ mega_client.login(MEGA_USERNAME, MEGA_PASSWORD)
+ except mega_err.MegaSdkRestClientException as e:
+ logging.error(e.message['message'])
+ exit(0)
+ else:
+ LOGGER.info("Mega API KEY provided but credentials not provided. Starting mega in anonymous mode!")
+ MEGA_USERNAME = None
+ MEGA_PASSWORD = None
+ except KeyError:
+ LOGGER.info("Mega API KEY provided but credentials not provided. Starting mega in anonymous mode!")
+ MEGA_USERNAME = None
+ MEGA_PASSWORD = None
+else:
+ MEGA_USERNAME = None
+ MEGA_PASSWORD = None
try:
INDEX_URL = getConfig('INDEX_URL')
if len(INDEX_URL) == 0:
INDEX_URL = None
except KeyError:
INDEX_URL = None
+try:
+ BUTTON_THREE_NAME = getConfig('BUTTON_THREE_NAME')
+ BUTTON_THREE_URL = getConfig('BUTTON_THREE_URL')
+ if len(BUTTON_THREE_NAME) == 0 or len(BUTTON_THREE_URL) == 0:
+ raise KeyError
+except KeyError:
+ BUTTON_THREE_NAME = None
+ BUTTON_THREE_URL = None
+try:
+ BUTTON_FOUR_NAME = getConfig('BUTTON_FOUR_NAME')
+ BUTTON_FOUR_URL = getConfig('BUTTON_FOUR_URL')
+ if len(BUTTON_FOUR_NAME) == 0 or len(BUTTON_FOUR_URL) == 0:
+ raise KeyError
+except KeyError:
+ BUTTON_FOUR_NAME = None
+ BUTTON_FOUR_URL = None
+try:
+ BUTTON_FIVE_NAME = getConfig('BUTTON_FIVE_NAME')
+ BUTTON_FIVE_URL = getConfig('BUTTON_FIVE_URL')
+ if len(BUTTON_FIVE_NAME) == 0 or len(BUTTON_FIVE_URL) == 0:
+ raise KeyError
+except KeyError:
+ BUTTON_FIVE_NAME = None
+ BUTTON_FIVE_URL = None
+try:
+ STOP_DUPLICATE_MIRROR = getConfig('STOP_DUPLICATE_MIRROR')
+ if STOP_DUPLICATE_MIRROR.lower() == 'true':
+ STOP_DUPLICATE_MIRROR = True
+ else:
+ STOP_DUPLICATE_MIRROR = False
+except KeyError:
+ STOP_DUPLICATE_MIRROR = False
try:
IS_TEAM_DRIVE = getConfig('IS_TEAM_DRIVE')
if IS_TEAM_DRIVE.lower() == 'true':
@@ -109,6 +242,24 @@ def getConfig(name: str):
except KeyError:
USE_SERVICE_ACCOUNTS = False
-updater = tg.Updater(token=BOT_TOKEN,use_context=True)
+try:
+ BLOCK_MEGA_LINKS = getConfig('BLOCK_MEGA_LINKS')
+ if BLOCK_MEGA_LINKS.lower() == 'true':
+ BLOCK_MEGA_LINKS = True
+ else:
+ BLOCK_MEGA_LINKS = False
+except KeyError:
+ BLOCK_MEGA_LINKS = False
+
+try:
+ SHORTENER = getConfig('SHORTENER')
+ SHORTENER_API = getConfig('SHORTENER_API')
+ if len(SHORTENER) == 0 or len(SHORTENER_API) == 0:
+ raise KeyError
+except KeyError:
+ SHORTENER = None
+ SHORTENER_API = None
+
+updater = tg.Updater(token=BOT_TOKEN)
bot = updater.bot
dispatcher = updater.dispatcher
diff --git a/bot/__main__.py b/bot/__main__.py
index 34df995b5..5242d529d 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -1,35 +1,46 @@
-import shutil
+import os
+import shutil, psutil
import signal
-import pickle
-from os import execl, path, remove
from sys import executable
+import time
-from telegram.ext import CommandHandler, run_async
-from bot import dispatcher, updater, botStartTime
+from telegram.ext import CommandHandler
+from bot import bot, dispatcher, updater, botStartTime
from bot.helper.ext_utils import fs_utils
from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.telegram_helper.message_utils import *
from .helper.ext_utils.bot_utils import get_readable_file_size, get_readable_time
from .helper.telegram_helper.filters import CustomFilters
-from .modules import authorize, list, cancel_mirror, mirror_status, mirror, clone, watch
+from .modules import authorize, list, cancel_mirror, mirror_status, mirror, clone, watch, delete, speedtest, count
+
+from pyrogram import idle
+from bot import app
-@run_async
def stats(update, context):
- currentTime = get_readable_time((time.time() - botStartTime))
+ currentTime = get_readable_time(time.time() - botStartTime)
total, used, free = shutil.disk_usage('.')
total = get_readable_file_size(total)
used = get_readable_file_size(used)
free = get_readable_file_size(free)
- stats = f'Bot Uptime: {currentTime}\n' \
- f'Total disk space: {total}\n' \
- f'Used: {used}\n' \
- f'Free: {free}'
+ sent = get_readable_file_size(psutil.net_io_counters().bytes_sent)
+ recv = get_readable_file_size(psutil.net_io_counters().bytes_recv)
+ cpuUsage = psutil.cpu_percent(interval=0.5)
+ memory = psutil.virtual_memory().percent
+ disk = psutil.disk_usage('/').percent
+ stats = f'Bot Uptime:- {currentTime}\n' \
+ f'Total Disk Space:- {total}\n' \
+ f'Used:- {used} ' \
+ f'Free:- {free}\n\n' \
+ f'Data Usage\nUp:- {sent}\n' \
+ f'Down:- {recv}\n\n' \
+ f'CPU: {cpuUsage}% ' \
+ f'RAM: {memory}% ' \
+ f'Disk: {disk}%'
sendMessage(stats, context.bot, update)
-@run_async
def start(update, context):
start_string = f'''
This is a bot which can mirror all your links to Google drive!
@@ -38,17 +49,16 @@ def start(update, context):
sendMessage(start_string, context.bot, update)
-@run_async
def restart(update, context):
restart_message = sendMessage("Restarting, Please wait!", context.bot, update)
- # Save restart message object in order to reply to it after restarting
+ # Save restart message ID and chat ID in order to edit it after restarting
+ with open(".restartmsg", "w") as f:
+ f.truncate(0)
+ f.write(f"{restart_message.chat.id}\n{restart_message.message_id}\n")
fs_utils.clean_all()
- with open('restart.pickle', 'wb') as status:
- pickle.dump(restart_message, status)
- execl(executable, executable, "-m", "bot")
+ os.execl(executable, executable, "-m", "bot")
-@run_async
def ping(update, context):
start_time = int(round(time.time() * 1000))
reply = sendMessage("Starting Ping", context.bot, update)
@@ -56,23 +66,23 @@ def ping(update, context):
editMessage(f'{end_time - start_time} ms', reply)
-@run_async
def log(update, context):
sendLogFile(context.bot, update)
-@run_async
def bot_help(update, context):
help_string = f'''
/{BotCommands.HelpCommand}: To get this message
-/{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to google drive
+/{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to google drive.\n
/{BotCommands.UnzipMirrorCommand} [download_url][magnet_link] : starts mirroring and if downloaded file is any archive , extracts it to google drive
+/{BotCommands.CountCommand}: Count files/folders of G-Drive Links
+
/{BotCommands.TarMirrorCommand} [download_url][magnet_link]: start mirroring and upload the archived (.tar) version of the download
-/{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl
+/{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl. Click /{BotCommands.WatchCommand} for more help.
/{BotCommands.TarWatchCommand} [youtube-dl supported link]: Mirror through youtube-dl and tar before uploading
@@ -88,6 +98,8 @@ def bot_help(update, context):
/{BotCommands.LogCommand}: Get a log file of the bot. Handy for getting crash reports
+/{BotCommands.SpeedCommand} : Check Internet Speed Of The Host
+
'''
sendMessage(help_string, context.bot, update)
@@ -95,23 +107,23 @@ def bot_help(update, context):
def main():
fs_utils.start_cleanup()
# Check if the bot is restarting
- if path.exists('restart.pickle'):
- with open('restart.pickle', 'rb') as status:
- restart_message = pickle.load(status)
- restart_message.edit_text("Restarted Successfully!")
- remove('restart.pickle')
+ if os.path.isfile(".restartmsg"):
+ with open(".restartmsg") as f:
+ chat_id, msg_id = map(int, f)
+ bot.edit_message_text("Restarted successfully!", chat_id, msg_id)
+ os.remove(".restartmsg")
start_handler = CommandHandler(BotCommands.StartCommand, start,
- filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
+ filters=CustomFilters.authorized_chat | CustomFilters.authorized_user, run_async=True)
ping_handler = CommandHandler(BotCommands.PingCommand, ping,
- filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
+ filters=CustomFilters.authorized_chat | CustomFilters.authorized_user, run_async=True)
restart_handler = CommandHandler(BotCommands.RestartCommand, restart,
- filters=CustomFilters.owner_filter)
+ filters=CustomFilters.owner_filter| CustomFilters.authorized_user, run_async=True)
help_handler = CommandHandler(BotCommands.HelpCommand,
- bot_help, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
+ bot_help, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user, run_async=True)
stats_handler = CommandHandler(BotCommands.StatsCommand,
- stats, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user)
- log_handler = CommandHandler(BotCommands.LogCommand, log, filters=CustomFilters.owner_filter)
+ stats, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user, run_async=True)
+ log_handler = CommandHandler(BotCommands.LogCommand, log, filters=CustomFilters.owner_filter, run_async=True)
dispatcher.add_handler(start_handler)
dispatcher.add_handler(ping_handler)
dispatcher.add_handler(restart_handler)
@@ -122,5 +134,6 @@ def main():
LOGGER.info("Bot Started!")
signal.signal(signal.SIGINT, fs_utils.exit_clean_up)
-
+app.start()
main()
+idle()
diff --git a/bot/data/aria.conf b/bot/data/aria.conf
new file mode 100644
index 000000000..b3a6a2ce5
--- /dev/null
+++ b/bot/data/aria.conf
@@ -0,0 +1,43 @@
+# RPC
+enable-rpc=true
+rpc-listen-all=true
+rpc-listen-port=6800
+rpc-max-request-size=1024M
+
+# Connection
+max-connection-per-server=14
+check-certificate=false
+min-split-size=10M
+max-overall-download-limit=0
+disable-ipv6=true
+split=10
+
+# Aria
+# daemon=true
+quiet=true
+allow-overwrite=true
+file-allocation=prealloc
+
+#BT
+listen-port=51413
+bt-max-peers=0
+bt-request-peer-speed-limit=0
+max-overall-upload-limit=0
+seed-time=0.01
+bt-tracker-connect-timeout=600
+follow-torrent=mem
+bt-force-encryption=true
+bt-stop-timeout=600
+user-agent=qBittorrent/4.3.5
+peer-agent=qBittorrent/4.3.5
+peer-id-prefix=-qB4350-
+
+#DHT
+dht-listen-port=51513
+enable-dht=true
+enable-dht6=false
+dht-file-path=/currentwd/dht.dat
+dht-file-path6=/currentwd/dht6.dat
+dht-entry-point=dht.transmissionbt.com:6881
+dht-entry-point6=dht.transmissionbt.com:6881
+
diff --git a/bot/data/dht.dat b/bot/data/dht.dat
new file mode 100644
index 000000000..a834b7771
Binary files /dev/null and b/bot/data/dht.dat differ
diff --git a/bot/data/dht6.dat b/bot/data/dht6.dat
new file mode 100644
index 000000000..36d34dbd8
Binary files /dev/null and b/bot/data/dht6.dat differ
diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py
index a015fb79f..2de4b3ca8 100644
--- a/bot/helper/ext_utils/bot_utils.py
+++ b/bot/helper/ext_utils/bot_utils.py
@@ -3,6 +3,7 @@
import threading
import time
+from bot.helper.telegram_helper.bot_commands import BotCommands
from bot import download_dict, download_dict_lock
LOGGER = logging.getLogger(__name__)
@@ -16,14 +17,14 @@ class MirrorStatus:
STATUS_UPLOADING = "Uploading"
STATUS_DOWNLOADING = "Downloading"
STATUS_WAITING = "Queued"
- STATUS_FAILED = "Failed. Cleaning download"
- STATUS_CANCELLED = "Cancelled"
+ STATUS_FAILED = "Failed.Cleaning download"
+ STATUS_CANCELLED = "Cancelled "
STATUS_ARCHIVING = "Archiving"
STATUS_EXTRACTING = "Extracting"
PROGRESS_MAX_SIZE = 100 // 8
-PROGRESS_INCOMPLETE = ['▏', '▎', '▍', '▌', '▋', '▊', '▉']
+PROGRESS_INCOMPLETE = ['█', '█', '█', '█', '█', '█', '█']
SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
@@ -62,7 +63,9 @@ def get_readable_file_size(size_in_bytes) -> str:
def getDownloadByGid(gid):
with download_dict_lock:
for dl in download_dict.values():
- if dl.status() != MirrorStatus.STATUS_UPLOADING and dl.status() != MirrorStatus.STATUS_ARCHIVING:
+ status = dl.status()
+ if status != MirrorStatus.STATUS_UPLOADING and status != MirrorStatus.STATUS_ARCHIVING \
+ and status != MirrorStatus.STATUS_EXTRACTING:
if dl.gid() == gid:
return dl
return None
@@ -81,7 +84,7 @@ def get_progress_bar_string(status):
p_str = '█' * cFull
if cPart >= 0:
p_str += PROGRESS_INCOMPLETE[cPart]
- p_str += ' ' * (PROGRESS_MAX_SIZE - cFull)
+ p_str += '░' * (PROGRESS_MAX_SIZE - cFull)
p_str = f"[{p_str}]"
return p_str
@@ -90,17 +93,23 @@ def get_readable_message():
with download_dict_lock:
msg = ""
for download in list(download_dict.values()):
- msg += f"{download.name()} - "
- msg += download.status()
+ msg += f"Name:- {download.name()}"
+ msg += f"\nStatus:- {download.status()}"
if download.status() != MirrorStatus.STATUS_ARCHIVING and download.status() != MirrorStatus.STATUS_EXTRACTING:
- msg += f"\n{get_progress_bar_string(download)} {download.progress()} of " \
- f"{download.size()}" \
- f" at {download.speed()}, ETA: {download.eta()} "
+ msg += f"\n{get_progress_bar_string(download)} {download.progress()}"
+ if download.status() == MirrorStatus.STATUS_DOWNLOADING:
+ msg += f"\nDownloaded:- {get_readable_file_size(download.processed_bytes())} of {download.size()}"
+ else:
+ msg += f"\nUploaded:- {get_readable_file_size(download.processed_bytes())} of {download.size()}"
+ msg += f"\nSpeed:- {download.speed()}, \nETA:- {download.eta()} "
+ # if hasattr(download, 'is_torrent'):
+ try:
+ msg += f"\nInfo: Seeders:- {download.aria_download().num_seeders}" \
+ f" & Peers:- {download.aria_download().connections}"
+ except:
+ pass
if download.status() == MirrorStatus.STATUS_DOWNLOADING:
- if hasattr(download, 'is_torrent'):
- msg += f"| P: {download.aria_download().connections} " \
- f"| S: {download.aria_download().num_seeders}"
- msg += f"\nGID: {download.gid()}"
+ msg += f"\nTo Stop:- /{BotCommands.CancelMirror} {download.gid()}"
msg += "\n\n"
return msg
@@ -137,15 +146,30 @@ def is_magnet(url: str):
return True
return False
+def is_gdrive_link(url: str):
+ return "drive.google.com" in url
+
def is_mega_link(url: str):
return "mega.nz" in url
+def get_mega_link_type(url: str):
+ if "folder" in url:
+ return "folder"
+ elif "file" in url:
+ return "file"
+ elif "/#F!" in url:
+ return "folder"
+ return "file"
+
+
def new_thread(fn):
"""To use as decorator to make a function call threaded.
Needs import
from threading import Thread"""
+
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs)
thread.start()
return thread
+
return wrapper
diff --git a/bot/helper/ext_utils/exceptions.py b/bot/helper/ext_utils/exceptions.py
index 25ff87fa6..a2f600c27 100644
--- a/bot/helper/ext_utils/exceptions.py
+++ b/bot/helper/ext_utils/exceptions.py
@@ -1,2 +1,8 @@
class DirectDownloadLinkException(Exception):
+ """Not method found for extracting direct download link from the http link"""
+ pass
+
+
+class NotSupportedExtractionArchive(Exception):
+ """The archive format use is trying to extract is not supported"""
pass
diff --git a/bot/helper/ext_utils/fs_utils.py b/bot/helper/ext_utils/fs_utils.py
index 90951d60a..d1bc9bd22 100644
--- a/bot/helper/ext_utils/fs_utils.py
+++ b/bot/helper/ext_utils/fs_utils.py
@@ -1,10 +1,11 @@
import sys
-from bot import aria2, LOGGER, DOWNLOAD_DIR
+from bot import aria2, LOGGER, DOWNLOAD_DIR, ARIA_CHILD_PROC, MEGA_CHILD_PROC
import shutil
import os
import pathlib
import magic
import tarfile
+from .exceptions import NotSupportedExtractionArchive
def clean_download(path: str):
@@ -22,16 +23,23 @@ def start_cleanup():
def clean_all():
aria2.remove_all(True)
- shutil.rmtree(DOWNLOAD_DIR)
+ try:
+ shutil.rmtree(DOWNLOAD_DIR)
+ except FileNotFoundError:
+ pass
def exit_clean_up(signal, frame):
try:
LOGGER.info("Please wait, while we clean up the downloads and stop running downloads")
clean_all()
+ ARIA_CHILD_PROC.kill()
+ MEGA_CHILD_PROC.kill()
sys.exit(0)
except KeyboardInterrupt:
LOGGER.warning("Force Exiting before the cleanup finishes!")
+ ARIA_CHILD_PROC.kill()
+ MEGA_CHILD_PROC.kill()
sys.exit(1)
@@ -60,25 +68,77 @@ def get_base_name(orig_path: str):
if orig_path.endswith(".tar.bz2"):
return orig_path.replace(".tar.bz2", "")
elif orig_path.endswith(".tar.gz"):
- return orig_path.replace(".tar.gz","")
+ return orig_path.replace(".tar.gz", "")
elif orig_path.endswith(".bz2"):
- return orig_path.replace(".bz2","")
+ return orig_path.replace(".bz2", "")
elif orig_path.endswith(".gz"):
- return orig_path.replace(".gz","")
+ return orig_path.replace(".gz", "")
elif orig_path.endswith(".tar"):
- return orig_path.replace(".tar","")
+ return orig_path.replace(".tar", "")
elif orig_path.endswith(".tbz2"):
- return orig_path.replace("tbz2","")
+ return orig_path.replace("tbz2", "")
elif orig_path.endswith(".tgz"):
- return orig_path.replace(".tgz","")
+ return orig_path.replace(".tgz", "")
elif orig_path.endswith(".zip"):
- return orig_path.replace(".zip","")
+ return orig_path.replace(".zip", "")
+ elif orig_path.endswith(".7z"):
+ return orig_path.replace(".7z", "")
elif orig_path.endswith(".Z"):
- return orig_path.replace(".Z","")
+ return orig_path.replace(".Z", "")
elif orig_path.endswith(".rar"):
- return orig_path.replace(".rar","")
+ return orig_path.replace(".rar", "")
+ elif orig_path.endswith(".iso"):
+ return orig_path.replace(".iso", "")
+ elif orig_path.endswith(".wim"):
+ return orig_path.replace(".wim", "")
+ elif orig_path.endswith(".cab"):
+ return orig_path.replace(".cab", "")
+ elif orig_path.endswith(".apm"):
+ return orig_path.replace(".apm", "")
+ elif orig_path.endswith(".arj"):
+ return orig_path.replace(".arj", "")
+ elif orig_path.endswith(".chm"):
+ return orig_path.replace(".chm", "")
+ elif orig_path.endswith(".cpio"):
+ return orig_path.replace(".cpio", "")
+ elif orig_path.endswith(".cramfs"):
+ return orig_path.replace(".cramfs", "")
+ elif orig_path.endswith(".deb"):
+ return orig_path.replace(".deb", "")
+ elif orig_path.endswith(".dmg"):
+ return orig_path.replace(".dmg", "")
+ elif orig_path.endswith(".fat"):
+ return orig_path.replace(".fat", "")
+ elif orig_path.endswith(".hfs"):
+ return orig_path.replace(".hfs", "")
+ elif orig_path.endswith(".lzh"):
+ return orig_path.replace(".lzh", "")
+ elif orig_path.endswith(".lzma"):
+ return orig_path.replace(".lzma", "")
+ elif orig_path.endswith(".lzma2"):
+ return orig_path.replace(".lzma2", "")
+ elif orig_path.endswith(".mbr"):
+ return orig_path.replace(".mbr", "")
+ elif orig_path.endswith(".msi"):
+ return orig_path.replace(".msi", "")
+ elif orig_path.endswith(".mslz"):
+ return orig_path.replace(".mslz", "")
+ elif orig_path.endswith(".nsis"):
+ return orig_path.replace(".nsis", "")
+ elif orig_path.endswith(".ntfs"):
+ return orig_path.replace(".ntfs", "")
+ elif orig_path.endswith(".rpm"):
+ return orig_path.replace(".rpm", "")
+ elif orig_path.endswith(".squashfs"):
+ return orig_path.replace(".squashfs", "")
+ elif orig_path.endswith(".udf"):
+ return orig_path.replace(".udf", "")
+ elif orig_path.endswith(".vhd"):
+ return orig_path.replace(".vhd", "")
+ elif orig_path.endswith(".xar"):
+ return orig_path.replace(".xar", "")
else:
- return "unsupported"
+ raise NotSupportedExtractionArchive('File format not supported for extraction')
def get_mime_type(file_path):
diff --git a/bot/helper/mirror_utils/download_utils/aria2_download.py b/bot/helper/mirror_utils/download_utils/aria2_download.py
index e30a0a9d9..defdca6c4 100644
--- a/bot/helper/mirror_utils/download_utils/aria2_download.py
+++ b/bot/helper/mirror_utils/download_utils/aria2_download.py
@@ -1,4 +1,5 @@
-from bot import aria2, download_dict_lock
+from bot import aria2, download_dict_lock, STOP_DUPLICATE_MIRROR
+from bot.helper.mirror_utils.upload_utils.gdriveTools import GoogleDriveHelper
from bot.helper.ext_utils.bot_utils import *
from .download_helper import DownloadHelper
from bot.helper.mirror_utils.status_utils.aria_download_status import AriaDownloadStatus
@@ -15,18 +16,36 @@ def __init__(self):
@new_thread
def __onDownloadStarted(self, api, gid):
+ sleep(1)
LOGGER.info(f"onDownloadStart: {gid}")
+ dl = getDownloadByGid(gid)
+ download = api.get_download(gid)
+ self.name = download.name
+ sname = download.name
+ if STOP_DUPLICATE_MIRROR:
+ if dl.getListener().isTar == True:
+ sname = sname + ".tar"
+ if dl.getListener().extract == True:
+ smsg = None
+ else:
+ gdrive = GoogleDriveHelper(None)
+ smsg, button = gdrive.drive_list(sname)
+ if smsg:
+ dl.getListener().onDownloadError(f'File is already available in drive.This download has been stopped.\n\n')
+ sendMarkup("Here are the search results:", dl.getListener().bot, dl.getListener().update, button)
+ aria2.remove([download])
+ return
update_all_messages()
-
def __onDownloadComplete(self, api: API, gid):
LOGGER.info(f"onDownloadComplete: {gid}")
dl = getDownloadByGid(gid)
download = api.get_download(gid)
if download.followed_by_ids:
new_gid = download.followed_by_ids[0]
+ new_download = api.get_download(new_gid)
with download_dict_lock:
- download_dict[dl.uid()] = AriaDownloadStatus(new_gid,dl.getListener())
- if download.is_torrent:
+ download_dict[dl.uid()] = AriaDownloadStatus(new_gid, dl.getListener())
+ if new_download.is_torrent:
download_dict[dl.uid()].is_torrent = True
update_all_messages()
LOGGER.info(f'Changed gid from {gid} to {new_gid}')
@@ -43,7 +62,7 @@ def __onDownloadPause(self, api, gid):
def __onDownloadStopped(self, api, gid):
LOGGER.info(f"onDownloadStop: {gid}")
dl = getDownloadByGid(gid)
- if dl: dl.getListener().onDownloadError('Download stopped by user!')
+ if dl: dl.getListener().onDownloadError('Your torrent has no seeds.Download stopped automatically.')
@new_thread
def __onDownloadError(self, api, gid):
@@ -63,11 +82,11 @@ def start_listener(self):
on_download_complete=self.__onDownloadComplete)
- def add_download(self, link: str, path,listener):
+ def add_download(self, link: str, path, listener, filename):
if is_magnet(link):
- download = aria2.add_magnet(link, {'dir': path})
+ download = aria2.add_magnet(link, {'dir': path, 'out': filename})
else:
- download = aria2.add_uris([link], {'dir': path})
+ download = aria2.add_uris([link], {'dir': path, 'out': filename})
if download.error_message: #no need to proceed further at this point
listener.onDownloadError(download.error_message)
return
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 84ea43a5b..b00728517 100644
--- a/bot/helper/mirror_utils/download_utils/direct_link_generator.py
+++ b/bot/helper/mirror_utils/download_utils/direct_link_generator.py
@@ -10,12 +10,20 @@
import json
import re
+import math
import urllib.parse
from os import popen
from random import choice
+from urllib.parse import urlparse
+import lk21
import requests
+import logging
+from bot import UPTOBOX_TOKEN
from bs4 import BeautifulSoup
+from lk21.extractors.bypasser import Bypass
+from base64 import standard_b64encode
+from js2py import EvalJs
from bot.helper.ext_utils.exceptions import DirectDownloadLinkException
@@ -32,38 +40,45 @@ def direct_link_generator(link: str):
return cm_ru(link)
elif 'mediafire.com' in link:
return mediafire(link)
+ elif 'uptobox.com' in link:
+ return uptobox(link)
elif 'osdn.net' in link:
return osdn(link)
elif 'github.com' in link:
return github(link)
+ elif 'fembed.com' in link:
+ return fembed(link)
+ elif 'femax20.com' in link:
+ return fembed(link)
+ elif 'feurl.com' in link:
+ return fembed(link)
else:
raise DirectDownloadLinkException(f'No Direct link function found for {link}')
def zippy_share(url: str) -> str:
- """ ZippyShare direct links generator
- Based on https://github.com/LameLemon/ziggy"""
- dl_url = ''
+ link = re.findall("https:/.(.*?).zippyshare", url)[0]
+ response_content = (requests.get(url)).content
+ bs_obj = BeautifulSoup(response_content, "lxml")
+
try:
- link = re.findall(r'\bhttps?://.*zippyshare\.com\S+', url)[0]
- except IndexError:
- raise DirectDownloadLinkException("`No ZippyShare links found`\n")
- session = requests.Session()
- base_url = re.search('http.+.com', link).group()
- response = session.get(link)
- page_soup = BeautifulSoup(response.content, "lxml")
- scripts = page_soup.find_all("script", {"type": "text/javascript"})
- for script in scripts:
- if "getElementById('dlbutton')" in script.text:
- url_raw = re.search(r'= (?P\".+\" \+ (?P