telegram-download-daemon/telegram-download-daemon.py

174 lines
5.4 KiB
Python
Raw Normal View History

2020-04-23 02:35:13 +08:00
#!/usr/bin/env python3
# Telegram Download Daemon
# Author: Alfonso E.M. <alfonso@el-magnifico.org>
# You need to install telethon (and cryptg to speed up downloads)
from os import getenv, rename
import subprocess
import math
2020-04-23 02:35:13 +08:00
from sessionManager import getSession, saveSession
2020-04-23 02:35:13 +08:00
from telethon import TelegramClient, events
2020-11-07 23:04:50 +08:00
from telethon.tl.types import PeerChannel, DocumentAttributeFilename, DocumentAttributeVideo
2020-04-23 02:35:13 +08:00
import logging
2020-05-24 23:32:29 +08:00
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s]%(name)s:%(message)s',
level=logging.WARNING)
2020-04-23 02:35:13 +08:00
import multiprocessing
2020-04-24 00:32:42 +08:00
import argparse
import asyncio
2020-04-24 00:32:42 +08:00
2020-05-10 12:43:13 +08:00
TELEGRAM_DAEMON_API_ID = getenv("TELEGRAM_DAEMON_API_ID")
TELEGRAM_DAEMON_API_HASH = getenv("TELEGRAM_DAEMON_API_HASH")
TELEGRAM_DAEMON_CHANNEL = getenv("TELEGRAM_DAEMON_CHANNEL")
2020-04-24 00:32:42 +08:00
2020-05-10 12:43:13 +08:00
TELEGRAM_DAEMON_SESSION_PATH = getenv("TELEGRAM_DAEMON_SESSION_PATH")
2020-04-24 00:32:42 +08:00
2020-05-24 23:32:29 +08:00
parser = argparse.ArgumentParser(
description="Script to download files from Telegram Channel.")
parser.add_argument(
"--api-id",
required=TELEGRAM_DAEMON_API_ID == None,
type=int,
default=TELEGRAM_DAEMON_API_ID,
help=
'api_id from https://core.telegram.org/api/obtaining_api_id (default is TELEGRAM_DAEMON_API_ID env var)'
)
parser.add_argument(
"--api-hash",
required=TELEGRAM_DAEMON_API_HASH == None,
type=str,
default=TELEGRAM_DAEMON_API_HASH,
help=
'api_hash from https://core.telegram.org/api/obtaining_api_id (default is TELEGRAM_DAEMON_API_HASH env var)'
)
parser.add_argument(
"--dest",
type=str,
default=getenv("TELEGRAM_DAEMON_DEST", "/telegram-downloads"),
help=
'Destenation path for downloading files (default is /telegram-downloads).')
parser.add_argument(
"--channel",
required=TELEGRAM_DAEMON_CHANNEL == None,
type=int,
default=TELEGRAM_DAEMON_CHANNEL,
help=
'Channel id to download from it (default is TELEGRAM_DAEMON_CHANNEL env var'
)
2020-04-24 00:32:42 +08:00
args = parser.parse_args()
api_id = args.api_id
api_hash = args.api_hash
channel_id = args.channel
downloadFolder = args.dest
worker_count = multiprocessing.cpu_count()
2020-04-24 00:32:42 +08:00
2020-04-23 02:35:13 +08:00
# Edit these lines:
2020-04-24 00:32:42 +08:00
proxy = None
2020-04-23 02:35:13 +08:00
2020-05-24 23:32:29 +08:00
# End of interesting parameters
async def sendHelloMessage(client, peerChannel):
entity = await client.get_entity(peerChannel)
2020-05-26 03:06:10 +08:00
print("Hi! Ready for your files!")
2020-05-25 00:25:39 +08:00
await client.send_message(entity, "Hi! Ready for your files!")
2020-05-24 23:32:29 +08:00
async def log_reply(event : events.ChatAction.Event, reply):
print(reply)
await event.reply(reply)
def getFilename(event: events.NewMessage.Event):
2020-11-07 23:04:50 +08:00
for attribute in event.media.document.attributes:
if isinstance(attribute, DocumentAttributeFilename): return attribute.file_name
if isinstance(attribute, DocumentAttributeVideo): return "DocumentAttributeVideo"
2020-04-23 02:35:13 +08:00
in_progress={}
def set_progress(filename, received, total):
if received >= total:
try: in_progress.pop(filename)
except: pass
return
percentage = math.trunc(received / total * 10000) / 100;
in_progress[filename] = f"{percentage} % ({received} / {total})"
2020-05-24 23:32:29 +08:00
with TelegramClient(getSession(), api_id, api_hash,
proxy=proxy).start() as client:
2020-04-23 02:35:13 +08:00
saveSession(client.session)
2020-04-23 02:35:13 +08:00
queue = asyncio.Queue()
peerChannel = PeerChannel(channel_id)
2020-04-23 02:35:13 +08:00
@client.on(events.NewMessage())
async def handler(event):
2020-04-23 02:35:13 +08:00
if event.to_id != peerChannel:
return
2020-05-24 23:32:29 +08:00
print(event)
2020-05-24 23:32:29 +08:00
if not event.media and event.message:
command = event.message.message
command = command.lower()
output = "Unknown command"
if command == "list":
output = subprocess.run(["ls", "-l", downloadFolder], capture_output=True).stdout
output = output.decode('utf-8')
if command == "status":
try:
output = "".join([ f"{key}: {value}\n" for (key, value) in in_progress.items()])
if output: output = "Active downloads:\n\n" + output
else: output = "No active downloads"
except:
output = "Some error occured while checking the status. Retry."
await log_reply(event, output)
if event.media:
filename=getFilename(event)
await log_reply(event, f"{filename} added to queue")
queue.put_nowait(event)
async def worker():
while True:
event = await queue.get()
filename=getFilename(event)
2020-05-24 23:40:48 +08:00
await log_reply(
2020-05-24 23:32:29 +08:00
event,
f"Downloading file {filename} ({event.media.document.size} bytes)"
)
2020-04-23 02:35:13 +08:00
download_callback = lambda received, total: set_progress(filename, received, total)
await client.download_media(event.message, f"{downloadFolder}/{filename}.partial", progress_callback = download_callback)
set_progress(filename, 1, 1)
rename(f"{downloadFolder}/{filename}.partial", f"{downloadFolder}/{filename}")
await log_reply(event, f"{filename} ready")
queue.task_done()
async def start():
tasks = []
2020-11-07 22:12:17 +08:00
loop = asyncio.get_event_loop()
for i in range(worker_count):
2020-11-07 22:12:17 +08:00
task = loop.create_task(worker())
tasks.append(task)
await sendHelloMessage(client, peerChannel)
await client.run_until_disconnected()
for task in tasks:
task.cancel()
await asyncio.gather(*tasks, return_exceptions=True)
2020-05-24 23:32:29 +08:00
client.loop.run_until_complete(start())