├── root ├── etc │ ├── services.d │ │ ├── bot │ │ │ └── run │ │ └── qbittorrent │ │ │ └── run │ └── cont-init.d │ │ └── 30-config └── defaults │ ├── qBittorrent.conf │ └── bot.py ├── README.md └── Dockerfile /root/etc/services.d/bot/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | exec \ 4 | s6-setuidgid root python3 /config/bot.py 5 | -------------------------------------------------------------------------------- /root/etc/services.d/qbittorrent/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | UMASK_SET=${UMASK_SET:-022} 4 | WEBUI_PORT=${WEBUI_PORT:-8080} 5 | 6 | umask "$UMASK_SET" 7 | 8 | exec \ 9 | s6-setuidgid abc /usr/bin/qbittorrent-nox --webui-port="${WEBUI_PORT}" 10 | -------------------------------------------------------------------------------- /root/defaults/qBittorrent.conf: -------------------------------------------------------------------------------- 1 | [AutoRun] 2 | enabled=false 3 | program=qbittorrent-nox 4 | 5 | [LegalNotice] 6 | Accepted=true 7 | 8 | [Preferences] 9 | Connection\UPnP=false 10 | Connection\PortRangeMin=6881 11 | Downloads\SavePath=/downloads/ 12 | Downloads\ScanDirsV2=@Variant(\0\0\0\x1c\0\0\0\0) 13 | Downloads\TempPath=/downloads/incomplete/ 14 | WebUI\Address=* 15 | WebUI\ServerDomains=* 16 | -------------------------------------------------------------------------------- /root/etc/cont-init.d/30-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | # make our folders 4 | mkdir -p \ 5 | /config/qBittorrent \ 6 | /config/data \ 7 | /config/normales \ 8 | /config/zip 9 | 10 | # copy config 11 | [[ ! -e /config/qBittorrent/qBittorrent.conf ]] && \ 12 | cp /defaults/qBittorrent.conf /config/qBittorrent/qBittorrent.conf && cp /defaults/bot.py /config/ 13 | # chown download directory if currently set to root 14 | if [[ "$(stat -c '%U' /downloads)" != "abc" ]]; then 15 | chown -R abc:abc /downloads 16 | fi 17 | 18 | # permissions 19 | chown -R abc:abc \ 20 | /config 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qbittrclonebot 🚀 2 | 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/rclone/rclone)](https://hub.docker.com/r/guzmi/qbittrclonebot) 4 | 5 | Este contenedor de docker contiene el cliente qBittorrent, herramienta Rclone y un BOT extra en Python para telegram al cuál enviar los torrents y automáticamente se añadan al cliente qbittorrent, con la finalidad de automatizar la subida de nuestras descargas a los principales servidores cloud como gdrive etc. 6 | 7 | ### Pre-requisitos 📋 8 | Únicamente necesitaremos tener docker instalado en nuestro sistema operativo. 9 | 10 | ## Despliegue 📦 11 | La forma más recomendades para lanzar este contenedor es la siguiente: 12 | 13 | ``` 14 | docker run \ 15 | --name=qbittorrent \ 16 | -e PUID=1000 \ 17 | -e PGID=1000 \ 18 | -e TZ=Europe/London \ 19 | -e UMASK_SET=022 \ 20 | -e WEBUI_PORT=8085 \ 21 | -p 6881:6881 \ 22 | -p 6881:6881/udp \ 23 | -p 8085:8085 \ 24 | -v /tupath/config:/config \ 25 | -v /tupath/downloads:/downloads \ 26 | --restart unless-stopped \ 27 | -it guzmi/qbittrclonebot /bin/bash 28 | ``` 29 | ## +info 📖 30 | La versión que contiene del cliente qBittorrent es la v4.2.1 31 | Para que el bot telgram pueda trabajar y debemos editar el archivo bot.py que se encuentra en la carpeta /config y añadir en lugar indicado el TOKEN ID de nuestro bot telegram, posteriormente a qBittorrent en configuración debemos configurarle como carpeta monitorizada /config/normales/ 32 | 33 | Es necesario que las carpetas a las cuáles apuntan los volúmenes tengan permisos de escritura y lectura de lo contrario rclone no podrá leer y escribir su fichero de configuración. 34 | 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lsiobase/ubuntu:bionic 2 | 3 | # set version label 4 | ARG BUILD_DATE 5 | ARG VERSION 6 | ARG QBITTORRENT_VERSION 7 | LABEL maintainer="guzmi" 8 | 9 | # environment settings 10 | ARG DEBIAN_FRONTEND="noninteractive" 11 | ENV HOME="/config" \ 12 | XDG_CONFIG_HOME="/config" \ 13 | XDG_DATA_HOME="/config" 14 | 15 | # add repo and install qbitorrent 16 | RUN \ 17 | echo "***** add qbitorrent repositories ****" && \ 18 | apt-get update && \ 19 | apt-get install -y \ 20 | gnupg \ 21 | python3 \ 22 | python3-pip && \ 23 | python3 -m pip install telegram python-telegram-bot --upgrade && \ 24 | curl -s https://bintray.com/user/downloadSubjectPublicKey?username=fedarovich | apt-key add - && \ 25 | apt-key adv --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 7CA69FC4 && \ 26 | echo "deb http://ppa.launchpad.net/qbittorrent-team/qbittorrent-stable/ubuntu bionic main" >> /etc/apt/sources.list.d/qbitorrent.list && \ 27 | echo "deb-src http://ppa.launchpad.net/qbittorrent-team/qbittorrent-stable/ubuntu bionic main" >> /etc/apt/sources.list.d/qbitorrent.list && \ 28 | echo "deb https://dl.bintray.com/fedarovich/qbittorrent-cli-debian bionic main" >> /etc/apt/sources.list.d/qbitorrent.list && \ 29 | echo "**** install packages ****" && \ 30 | if [ -z ${QBITTORRENT_VERSION+x} ]; then \ 31 | QBITTORRENT_VERSION=$(curl -sX GET http://ppa.launchpad.net/qbittorrent-team/qbittorrent-stable/ubuntu/dists/bionic/main/binary-amd64/Packages.gz | gunzip -c \ 32 | |grep -A 7 -m 1 "Package: qbittorrent-nox" | awk -F ": " '/Version/{print $2;exit}');\ 33 | fi && \ 34 | apt-get update && \ 35 | apt-get install -y \ 36 | p7zip-full \ 37 | qbittorrent-cli \ 38 | qbittorrent-nox=${QBITTORRENT_VERSION} \ 39 | unrar \ 40 | geoip-bin \ 41 | unzip && \ 42 | curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip && \ 43 | unzip rclone-current-linux-amd64.zip && \ 44 | cd rclone-*-linux-amd64 && \ 45 | cp rclone /usr/bin/ && \ 46 | chown root:root /usr/bin/rclone && \ 47 | chmod 755 /usr/bin/rclone && \ 48 | echo "**** cleanup ****" && \ 49 | apt-get clean && \ 50 | rm -rf \ 51 | /tmp/* \ 52 | /var/lib/apt/lists/* \ 53 | /var/tmp/* 54 | 55 | # add local files 56 | COPY root/ / 57 | 58 | # ports and volumes 59 | EXPOSE 6881 6881/udp 8085 60 | VOLUME /config /downloads 61 | -------------------------------------------------------------------------------- /root/defaults/bot.py: -------------------------------------------------------------------------------- 1 | ################################################# 2 | #### Programado por cRytoFono #### 3 | ################################################# 4 | #------------------------------------------------ 5 | # Librerías necesarias # 6 | #------------------------------------------------ 7 | # python3 -m pip install telegram --upgrade 8 | # python3 -m pip install python-telegram-bot --upgrade 9 | #------------------------------------------------ 10 | 11 | try: 12 | 13 | from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler, ConversationHandler, InlineQueryHandler, CallbackQueryHandler) 14 | from telegram import (InlineQueryResultArticle, ParseMode, InputTextMessageContent, MessageEntity, InlineKeyboardButton, InlineKeyboardMarkup) 15 | import telegram 16 | import logging 17 | from os import remove 18 | import os 19 | from os import scandir, getcwd, rename 20 | import zipfile 21 | 22 | # Enable logging 23 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) 24 | logger = logging.getLogger(__name__) 25 | 26 | 27 | 28 | #---------------------------------------------- 29 | # Función para descargarse un archivo de 30 | # internet 31 | #---------------------------------------------- 32 | def DownloadFile(url, ruta, filename): 33 | try: 34 | # local_filename = url.split('/')[-1] 35 | import urllib.request 36 | opener = urllib.request.build_opener() 37 | opener.addheaders = [('User-agent', 'Mozilla/5.0')] 38 | urllib.request.install_opener(opener) 39 | urllib.request.urlretrieve(url, ruta+filename) 40 | except Exception as e: 41 | print (e) 42 | 43 | #---------------------------------------------- 44 | # Función para leer los archivos de un 45 | # directorio 46 | #---------------------------------------------- 47 | def ls(ruta = getcwd()): 48 | return [arch.name for arch in scandir(ruta) if arch.is_file()] 49 | 50 | #---------------------------------------------- 51 | # Función para quitar los ' ' del nombre de 52 | # los archivos 53 | #---------------------------------------------- 54 | 55 | def rename_files(ruta): 56 | for archivos in ls(ruta): 57 | if archivos.startswith("'") and archivos.endswith("'"): 58 | rename(archivos, archivos[1:-1]) 59 | 60 | #---------------------------------------------- 61 | # Función para descargar .torrent y enviarlos 62 | # a una carpeta 63 | #---------------------------------------------- 64 | 65 | def descargar_archivos(bot, update): 66 | 67 | try: 68 | m=update.message 69 | #La variable ruta será donde guarde los torrents, es decir será la carpeta que al cliente hay que ponerle para que la monitorice 70 | ruta='/config/normales/' 71 | tmp='/config/zip/' 72 | 73 | filename=m.document.file_name 74 | texto=m.text 75 | archivo = bot.getFile(m.document.file_id) 76 | 77 | if filename.endswith('.zip'): 78 | DownloadFile(archivo.file_path, tmp, filename) 79 | zf = zipfile.ZipFile(tmp+filename, "r") 80 | for torrents in zf.namelist(): 81 | if os.path.dirname(torrents)=='' and torrents.endswith('.torrent'): 82 | zf.extract(torrents, ruta) 83 | zf.close() 84 | #rename_files() 85 | remove(tmp+filename) 86 | bot.send_message(chat_id=m.chat.id, text="Se han guardado los archivos de "+filename+" en la carpeta", parse_mode="HTML") 87 | 88 | if filename.endswith('.torrent'): 89 | DownloadFile(archivo.file_path, ruta, filename) 90 | bot.send_message(chat_id=m.chat.id, text="El archivo "+filename+" se ha añadido guardado en la carpeta", parse_mode="HTML") 91 | if "magnet" in texto: 92 | bot.send_message(chat_id=m.chat.id, text="Esto es un magnet tronco", parse_mode="HTML") 93 | except Exception as e: 94 | print (e) 95 | 96 | #---------------------------------------------- 97 | # Función para descargar los magnet 98 | # a una carpeta 99 | #---------------------------------------------- 100 | def descargar_texto(bot, update): 101 | 102 | try: 103 | m=update.message 104 | 105 | ruta='/config/normales/descarga.magnet' 106 | 107 | texto=m.text 108 | 109 | if "magnet" in texto or ".torrent" in texto: 110 | f = open (ruta,'w') 111 | f.write(texto) 112 | f.close() 113 | bot.send_message(chat_id=m.chat.id, text="Torrent añadidor por URL o Magnet Correctamente", parse_mode="HTML") 114 | 115 | except Exception as e: 116 | print (e) 117 | 118 | def error(bot, update, error): 119 | logger.warn('Update "%s" caused error "%s"' % (update, error)) 120 | 121 | 122 | def main(): 123 | # Create the EventHandler and pass it your bot's token. 124 | 125 | updater = Updater("TU TOKEN BOT") 126 | dp = updater.dispatcher 127 | 128 | dp.add_handler(MessageHandler(Filters.document, descargar_archivos)) 129 | # Get the dispatcher to register handlers 130 | dp.add_handler(MessageHandler(Filters.text, descargar_texto)) 131 | 132 | 133 | 134 | # log all errors 135 | dp.add_error_handler(error) 136 | 137 | # Start the Bot 138 | updater.start_polling(clean=True) 139 | 140 | # Run the bot until you press Ctrl-C or the process receives SIGINT, 141 | # SIGTERM or SIGABRT. This should be used most of the time, since 142 | # start_polling() is non-blocking and will stop the bot gracefully. 143 | updater.idle() 144 | 145 | 146 | if __name__ == '__main__': 147 | main() 148 | except Exception as e: 149 | print (e) 150 | --------------------------------------------------------------------------------