more validaitons and optimizations

This commit is contained in:
thezero 2020-11-28 12:52:18 +01:00
parent 1d0d83b1df
commit 8fbe1a2bf4
4 changed files with 47 additions and 21 deletions

View File

@ -1,4 +1,4 @@
# telegram-bot-youtube-downloader # telegram-apk-downloader
Set in your environment the following variables: Set in your environment the following variables:
- `BOT_TOKEN` telegram token for your bot - `BOT_TOKEN` telegram token for your bot

View File

@ -8,3 +8,4 @@ services:
- ./conf:/bot/conf - ./conf:/bot/conf
environment: environment:
- CONF_FOLDER=/bot/conf/ - CONF_FOLDER=/bot/conf/
user: 1000:1000

View File

@ -1,6 +1,10 @@
import os import os
import re
from glob import glob, escape from glob import glob, escape
from contextlib import contextmanager from contextlib import contextmanager
from subprocess import check_call
from urllib.parse import urlparse, parse_qs
from gplaycli.gplaycli import GPlaycli from gplaycli.gplaycli import GPlaycli
@ -13,16 +17,32 @@ class dotdict(dict):
__setattr__ = dict.__setitem__ __setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__ __delattr__ = dict.__delitem__
def validate_package_name(package_name):
# https://developer.android.com/studio/build/application-id
"""
- It must have at least two segments (one or more dots).
- Each segment must start with a letter.
- All characters must be alphanumeric or an underscore [a-zA-Z0-9_].
"""
reg = r"^(?:[a-zA-Z]+(?:\d*[a-zA-Z_]*)*)(?:\.[a-zA-Z]+(?:\d*[a-zA-Z_]*)*)+$"
return re.match(reg, package_name) is not None
class APK: class APK:
def __init__(self, apk, conf={}, conf_file=None): def __init__(self, apk, conf={}, conf_file=None):
self.conf = conf self.conf = conf
self.conf_file = conf_file self.conf_file = conf_file
if 'play.google.com/store/apps/details?id=' in apk: self.package_name = ''
self.package_name = apk.split('play.google.com/store/apps/details?id=')[1] if 'play.google.com/store/apps/details' in apk:
url = urlparse(apk)
if url.netloc == 'play.google.com':
self.package_name = parse_qs(url.query)['id'][0]
else: else:
self.package_name = apk self.package_name = apk
def download(self): def download(self):
if not validate_package_name(self.package_name):
raise BadPackageNameException(f'error downloading {self.package_name}')
cli = GPlaycli(args=dotdict(self.conf), config_file=self.conf_file) cli = GPlaycli(args=dotdict(self.conf), config_file=self.conf_file)
cli.download_folder = 'out' cli.download_folder = 'out'
d = cli.download([self.package_name]) # returns the number of downloaded packages d = cli.download([self.package_name]) # returns the number of downloaded packages
@ -35,7 +55,7 @@ class APK:
def check_dimension(self): def check_dimension(self):
if os.path.getsize(self.file_name) > 50 * 1024 * 1023: if os.path.getsize(self.file_name) > 50 * 1024 * 1023:
os.system('split -b 49M "{0}" "{1}"'.format(self.file_name, self.file_name)) check_call(['split', '-b', '49M', self.file_name, self.file_name])
os.remove(self.file_name) os.remove(self.file_name)
return glob(escape(self.file_name) + '*') return glob(escape(self.file_name) + '*')

View File

@ -1,5 +1,6 @@
import logging import logging
import os import os
from subprocess import CalledProcessError
from telegram.ext import Updater, MessageHandler, Filters from telegram.ext import Updater, MessageHandler, Filters
@ -8,37 +9,32 @@ from download_utils import APK, BadPackageNameException
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def error_callback(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
def get_format(update, context): def get_package(update, context):
logger.info("from {}: {}".format(update.message.chat_id, update.message.text)) # "history" logger.info("from {}: {}".format(update.message.chat_id, update.message.text)) # "history"
if update.message.text == '/start': if update.message.text == '/start':
update.message.reply_text("To start downloading APK file send me a PlayStore link ok a package name. :)") update.message.reply_text("To start downloading APK file send me a PlayStore link ok a package name. :)")
return return
conf = { apk = APK(update.message.text, conf=CONF, conf_file=CONF_FILE)
'yes': True,
'verbose': False,
'tokencachefile': os.path.join(os.environ['CONF_FOLDER'], 'token.cache'),
} msg = context.bot.send_message(text=f"Downloading {apk.package_name}...",
apk = APK(update.message.text, conf=conf, conf_file=os.path.join(os.environ['CONF_FOLDER'], 'gplaycli.conf'))
msg = context.bot.send_message(text="Downloading...",
chat_id=update.message.chat_id) chat_id=update.message.chat_id)
try: try:
apk.download() apk.download()
except BadPackageNameException as e:
# instead of editing the text message we delete and resend one so a new notification will trigger
context.bot.delete_message(chat_id=update.message.chat_id,
message_id=msg.message_id)
context.bot.send_message(text="Bad package name: {}".format(e),
chat_id=update.message.chat_id)
return
with apk.send() as files: with apk.send() as files:
for f in files: for f in files:
context.bot.send_document(chat_id=update.message.chat_id, document=open(f, 'rb')) context.bot.send_document(chat_id=update.message.chat_id, document=open(f, 'rb'))
except BadPackageNameException as e:
# instead of editing the text message we delete and resend one so a new notification will trigger
context.bot.send_message(text="Bad package name: {}".format(e),
chat_id=update.message.chat_id)
except CalledProcessError:
context.bot.send_message(text="Failed to send APK file",
chat_id=update.message.chat_id)
context.bot.delete_message(chat_id=update.message.chat_id, context.bot.delete_message(chat_id=update.message.chat_id,
message_id=msg.message_id) message_id=msg.message_id)
@ -50,9 +46,18 @@ if os.environ.get('CONF_FOLDER') is None:
TOKEN = None TOKEN = None
with open(os.path.join(os.environ['CONF_FOLDER'], 'bot.token')) as f: with open(os.path.join(os.environ['CONF_FOLDER'], 'bot.token')) as f:
TOKEN = f.read().strip() TOKEN = f.read().strip()
CONF = {
'yes': True,
'verbose': False,
'tokencachefile': os.path.join(os.environ['CONF_FOLDER'], 'token.cache'),
}
CONF_FILE = os.path.join(os.environ['CONF_FOLDER'], 'gplaycli.conf')
updater = Updater(token=TOKEN) updater = Updater(token=TOKEN)
updater.dispatcher.add_handler(MessageHandler(Filters.text, get_format)) updater.dispatcher.add_handler(MessageHandler(Filters.text, get_package))
updater.dispatcher.add_error_handler(error_callback)
updater.start_polling() updater.start_polling()
updater.idle() updater.idle()