more validaitons and optimizations
This commit is contained in:
parent
1d0d83b1df
commit
8fbe1a2bf4
@ -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
|
||||||
|
@ -8,3 +8,4 @@ services:
|
|||||||
- ./conf:/bot/conf
|
- ./conf:/bot/conf
|
||||||
environment:
|
environment:
|
||||||
- CONF_FOLDER=/bot/conf/
|
- CONF_FOLDER=/bot/conf/
|
||||||
|
user: 1000:1000
|
||||||
|
@ -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) + '*')
|
||||||
|
|
||||||
|
39
src/main.py
39
src/main.py
@ -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()
|
||||||
|
with apk.send() as files:
|
||||||
|
for f in files:
|
||||||
|
context.bot.send_document(chat_id=update.message.chat_id, document=open(f, 'rb'))
|
||||||
except BadPackageNameException as e:
|
except BadPackageNameException as e:
|
||||||
# instead of editing the text message we delete and resend one so a new notification will trigger
|
# 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),
|
context.bot.send_message(text="Bad package name: {}".format(e),
|
||||||
chat_id=update.message.chat_id)
|
chat_id=update.message.chat_id)
|
||||||
return
|
except CalledProcessError:
|
||||||
|
context.bot.send_message(text="Failed to send APK file",
|
||||||
with apk.send() as files:
|
chat_id=update.message.chat_id)
|
||||||
for f in files:
|
|
||||||
context.bot.send_document(chat_id=update.message.chat_id, document=open(f, 'rb'))
|
|
||||||
|
|
||||||
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()
|
||||||
|
Loading…
Reference in New Issue
Block a user