From 3136482b75610e325e277052f1bb25e3099d445b Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 20 Sep 2019 12:47:36 +0200 Subject: [PATCH] Suitable downloader for milestone #1 --- YouTubeMDBot/__init__.py | 23 ++++ YouTubeMDBot/__main__.py | 15 +++ YouTubeMDBot/bot.py | 37 ++++++ YouTubeMDBot/commands/StartHandler.py | 24 ++++ YouTubeMDBot/commands/__init__.py | 15 +++ YouTubeMDBot/constants/__init__.py | 17 +++ YouTubeMDBot/constants/app_constants.py | 21 ++++ YouTubeMDBot/decorators/__init__.py | 17 +++ YouTubeMDBot/decorators/decorators.py | 55 +++++++++ YouTubeMDBot/downloader/__init__.py | 16 +++ YouTubeMDBot/downloader/youtube_downloader.py | 39 ++++++ YouTubeMDBot/logging_utils/__init__.py | 17 +++ YouTubeMDBot/logging_utils/utils.py | 116 ++++++++++++++++++ YouTubeMDBot/metadata/MetadataIdentifier.py | 20 +++ YouTubeMDBot/metadata/__init__.py | 15 +++ YouTubeMDBot/requirements.txt | 3 + 16 files changed, 450 insertions(+) create mode 100644 YouTubeMDBot/__init__.py create mode 100644 YouTubeMDBot/__main__.py create mode 100644 YouTubeMDBot/bot.py create mode 100644 YouTubeMDBot/commands/StartHandler.py create mode 100644 YouTubeMDBot/commands/__init__.py create mode 100644 YouTubeMDBot/constants/__init__.py create mode 100644 YouTubeMDBot/constants/app_constants.py create mode 100644 YouTubeMDBot/decorators/__init__.py create mode 100644 YouTubeMDBot/decorators/decorators.py create mode 100644 YouTubeMDBot/downloader/__init__.py create mode 100644 YouTubeMDBot/downloader/youtube_downloader.py create mode 100644 YouTubeMDBot/logging_utils/__init__.py create mode 100644 YouTubeMDBot/logging_utils/utils.py create mode 100644 YouTubeMDBot/metadata/MetadataIdentifier.py create mode 100644 YouTubeMDBot/metadata/__init__.py create mode 100644 YouTubeMDBot/requirements.txt diff --git a/YouTubeMDBot/__init__.py b/YouTubeMDBot/__init__.py new file mode 100644 index 0000000..d0c79d3 --- /dev/null +++ b/YouTubeMDBot/__init__.py @@ -0,0 +1,23 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from .bot import PROGRAM_ARGS +from .bot import main + +from .logging_utils import LoggingHandler +from .logging_utils import setup_logging + +from .decorators import send_action +from .decorators import restricted diff --git a/YouTubeMDBot/__main__.py b/YouTubeMDBot/__main__.py new file mode 100644 index 0000000..8a858f1 --- /dev/null +++ b/YouTubeMDBot/__main__.py @@ -0,0 +1,15 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . diff --git a/YouTubeMDBot/bot.py b/YouTubeMDBot/bot.py new file mode 100644 index 0000000..10b68d9 --- /dev/null +++ b/YouTubeMDBot/bot.py @@ -0,0 +1,37 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from telegram.ext import Updater +from telegram.ext import CommandHandler + +PROGRAM_ARGS = None + + +def main(args: dict): + global PROGRAM_ARGS + PROGRAM_ARGS = args + updater = Updater(args["token"], workers=args["workers"]) + + dispatcher = updater.dispatcher + dispatcher.add_handler(CommandHandler("hello", main)) + + if args["use_webhook"]: + updater.start_webhook(listen=args["ip"], + port=args["port"], + url_path=args["token"], + webhook_url=args["public_url"] + '/' + args["token"]) + else: + updater.start_polling(args["poll_interval"]) + updater.idle() diff --git a/YouTubeMDBot/commands/StartHandler.py b/YouTubeMDBot/commands/StartHandler.py new file mode 100644 index 0000000..d209a1e --- /dev/null +++ b/YouTubeMDBot/commands/StartHandler.py @@ -0,0 +1,24 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from .. import LoggingHandler + + +class StartHandler(object): + def __init__(self): + self._user_data = {} + + def start(self, bot, update): + self._user_data[] diff --git a/YouTubeMDBot/commands/__init__.py b/YouTubeMDBot/commands/__init__.py new file mode 100644 index 0000000..8a858f1 --- /dev/null +++ b/YouTubeMDBot/commands/__init__.py @@ -0,0 +1,15 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . diff --git a/YouTubeMDBot/constants/__init__.py b/YouTubeMDBot/constants/__init__.py new file mode 100644 index 0000000..b8d3e20 --- /dev/null +++ b/YouTubeMDBot/constants/__init__.py @@ -0,0 +1,17 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from ..constants.app_constants import ydl_options +from ..constants.app_constants import STREAM_OFFSET diff --git a/YouTubeMDBot/constants/app_constants.py b/YouTubeMDBot/constants/app_constants.py new file mode 100644 index 0000000..f738ade --- /dev/null +++ b/YouTubeMDBot/constants/app_constants.py @@ -0,0 +1,21 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +ydl_options: dict = { + "format": "bestaudio[ext=m4a]", + "outtmpl": "-", + "logger": "" +} +STREAM_OFFSET: int = 0 diff --git a/YouTubeMDBot/decorators/__init__.py b/YouTubeMDBot/decorators/__init__.py new file mode 100644 index 0000000..9a87cd2 --- /dev/null +++ b/YouTubeMDBot/decorators/__init__.py @@ -0,0 +1,17 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from ..decorators.decorators import restricted +from ..decorators.decorators import send_action diff --git a/YouTubeMDBot/decorators/decorators.py b/YouTubeMDBot/decorators/decorators.py new file mode 100644 index 0000000..5c305b4 --- /dev/null +++ b/YouTubeMDBot/decorators/decorators.py @@ -0,0 +1,55 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from functools import wraps + +from .. import PROGRAM_ARGS +from .. import LoggingHandler + + +logging = LoggingHandler() + + +def send_action(action): + """ + Sends an action while processing a command. + :param action: the action to be performed. + :return: itself. + """ + + def decorator(func): + @wraps(func) + def command_func(update, context, *args, **kwargs): + context.bot.send_chat_action(chat_id=update.effective_message.chat_id, action=action) + return func(update, context, *args, **kwargs) + return command_func + + return decorator + + +def restricted(func): + """ + Restricts a specific function to be accessed from non-authorized users. + :param func: function to be wrapped. + :return: itself. + """ + @wraps(func) + def wrapped(update, context, *args, **kwargs): + user_id = update.effective_user.id + if user_id not in PROGRAM_ARGS["admin"]: + logging.warning("Unauthorized access denied for {}.".format(user_id)) + return + return func(update, context, *args, **kwargs) + return wrapped diff --git a/YouTubeMDBot/downloader/__init__.py b/YouTubeMDBot/downloader/__init__.py new file mode 100644 index 0000000..89c3cee --- /dev/null +++ b/YouTubeMDBot/downloader/__init__.py @@ -0,0 +1,16 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from ..downloader.youtube_downloader import YouTubeDownloader diff --git a/YouTubeMDBot/downloader/youtube_downloader.py b/YouTubeMDBot/downloader/youtube_downloader.py new file mode 100644 index 0000000..b956952 --- /dev/null +++ b/YouTubeMDBot/downloader/youtube_downloader.py @@ -0,0 +1,39 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import logging +import youtube_dl + +from contextlib import redirect_stdout as save_to +from io import BytesIO + +from ..constants.app_constants import ydl_options +from ..constants.app_constants import STREAM_OFFSET + + +class YouTubeDownloader(object): + def __init__(self, url: str, + logger: logging = logging.getLogger("empty-logger")): + self.__url: str = url + self.__options: dict = ydl_options + self.__options["logger"] = logger + + def download(self, io: BytesIO = BytesIO()) -> BytesIO: + with save_to(io): + with youtube_dl.YoutubeDL(self.__options) as yt_downloader: + yt_downloader.download([self.__url]) + + io.seek(STREAM_OFFSET) + return io diff --git a/YouTubeMDBot/logging_utils/__init__.py b/YouTubeMDBot/logging_utils/__init__.py new file mode 100644 index 0000000..45c2549 --- /dev/null +++ b/YouTubeMDBot/logging_utils/__init__.py @@ -0,0 +1,17 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from ..logging_utils.utils import LoggingHandler +from ..logging_utils.utils import setup_logging diff --git a/YouTubeMDBot/logging_utils/utils.py b/YouTubeMDBot/logging_utils/utils.py new file mode 100644 index 0000000..309a620 --- /dev/null +++ b/YouTubeMDBot/logging_utils/utils.py @@ -0,0 +1,116 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import logging + + +def cleanup_old_logs(log_file: str): + import tarfile + import os + + tar_log_filename = log_file + ".tar.gz" + + if os.path.exists(log_file): + if os.path.exists(tar_log_filename): + os.remove(tar_log_filename) + with tarfile.open(tar_log_filename, "w:gz") as tar: + tar.add(log_file, arcname=os.path.basename(log_file)) + tar.close() + os.remove(log_file) + + +def setup_logging(logger_name: str, log_file: str, level=logging.DEBUG, + formatter: str = "%(process)d - %(asctime)s | [%(levelname)s]: %(message)s"): + from os import path + from os import makedirs + + log_dir = path.dirname(path.abspath(log_file)) + if not path.exists(log_dir): + makedirs(log_dir) + + cleanup_old_logs(log_file) + new_logging = logging.getLogger(logger_name) + logging_formatter = logging.Formatter(formatter) + logging_file_handler = logging.FileHandler(log_file, mode="w") + + logging_file_handler.setFormatter(logging_formatter) + + new_logging.setLevel(level) + new_logging.addHandler(logging_file_handler) + + return logging_file_handler + + +class LoggingHandler(object): + class __LoggingHandler(object): + def __init__(self, logs: list): + self.__logs = logs + + def debug(self, msg): + for log in self.__logs: + log.debug(msg) + + def info(self, msg): + for log in self.__logs: + log.info(msg) + + def error(self, msg): + for log in self.__logs: + log.error(msg) + + def warning(self, msg): + for log in self.__logs: + log.warning(msg) + + def critical(self, msg): + for log in self.__logs: + log.critical(msg) + + def get_loggers(self) -> list: + return self.__logs + + __instance = None + + def __new__(cls, *args, **kwargs): + if not LoggingHandler.__instance: + logs = kwargs.get("logs") + if not logs or len(logs) == 0: + raise AttributeError("At least kwarg \"log\" (a list of the loggers) must be provided") + LoggingHandler.__instance = LoggingHandler.__LoggingHandler(logs) + return LoggingHandler.__instance + + def __getattr__(self, item): + return getattr(self.__instance, item) + + def __setattr__(self, key, value): + return setattr(self.__instance, key, value) + + def debug(self, msg): + self.__instance.debug(msg) + + def info(self, msg): + self.__instance.info(msg) + + def error(self, msg): + self.__instance.error(msg) + + def warning(self, msg): + self.__instance.warning(msg) + + def critical(self, msg): + self.__instance.critical(msg) + + def get_loggers(self) -> list: + return self.__instance.get_loggers() diff --git a/YouTubeMDBot/metadata/MetadataIdentifier.py b/YouTubeMDBot/metadata/MetadataIdentifier.py new file mode 100644 index 0000000..b473a23 --- /dev/null +++ b/YouTubeMDBot/metadata/MetadataIdentifier.py @@ -0,0 +1,20 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import acoustid + + +class MetadataIdentifier(object): + def __init__(self, filename: str = None, audio: str = None): diff --git a/YouTubeMDBot/metadata/__init__.py b/YouTubeMDBot/metadata/__init__.py new file mode 100644 index 0000000..8a858f1 --- /dev/null +++ b/YouTubeMDBot/metadata/__init__.py @@ -0,0 +1,15 @@ +# YouTubeMDBot +# Copyright (C) 2019 - Javinator9889 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . diff --git a/YouTubeMDBot/requirements.txt b/YouTubeMDBot/requirements.txt new file mode 100644 index 0000000..9c3d398 --- /dev/null +++ b/YouTubeMDBot/requirements.txt @@ -0,0 +1,3 @@ +youtube_dl +pyacoustid +python-telegram-bot