├── 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 | [](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 |
--------------------------------------------------------------------------------