diff --git a/.gitignore b/.gitignore index bf0d076..680e343 100644 --- a/.gitignore +++ b/.gitignore @@ -1,156 +1,157 @@ -# Created by .ignore support plugin (hsz.mobi) -### Python template -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - - -# ignore .pem file -*.pem - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# IPython Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# dotenv -.env - -# virtualenv -venv/ -ENV/ - -# Spyder project settings -.spyderproject - -# Rope project settings -.ropeproject -### VirtualEnv template -# Virtualenv -# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ -.Python -[Bb]in -[Ii]nclude -[Ll]ib -[Ll]ib64 -[Ll]ocal -[Ss]cripts -pyvenv.cfg -.venv -pip-selfcheck.json -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea/workspace.xml -.idea/tasks.xml -.idea/dictionaries -.idea/vcs.xml -.idea/jsLibraryMappings.xml - -# Sensitive or high-churn files: -.idea/dataSources.ids -.idea/dataSources.xml -.idea/dataSources.local.xml -.idea/sqlDataSources.xml -.idea/dynamic.xml -.idea/uiDesigner.xml - -# Gradle: -.idea/gradle.xml -.idea/libraries - -# Mongo Explorer plugin: -.idea/mongoSettings.xml - -.idea/ - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - +# Created by .ignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +.telegramToken + +# ignore .pem file +*.pem + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject +### VirtualEnv template +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +.Python +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +.venv +pip-selfcheck.json +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +.idea/ + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + diff --git a/.telegramToken b/.telegramToken new file mode 100644 index 0000000..fbb87da --- /dev/null +++ b/.telegramToken @@ -0,0 +1 @@ +5796704439:AAHeEfJXgEwYcZbv38JbuIP97mlodDVryFc \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ac0a3bb..e64a775 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ -FROM python:3.8.12-slim-buster - -# YOUR COMMANDS HERE -# .... -# .... - +FROM python:3.8.12-slim-buster +WORKDIR /app + +COPY . . + +RUN pip install -r requirements.txt + CMD ["python3", "app.py"] \ No newline at end of file diff --git a/app.py b/app.py index 45e12d7..f937433 100644 --- a/app.py +++ b/app.py @@ -1,74 +1,76 @@ -import telebot -from utils import search_download_youtube_video -from loguru import logger - - -class Bot: - - def __init__(self, token): - self.bot = telebot.TeleBot(token, threaded=False) - self.bot.set_update_listener(self._bot_internal_handler) - - self.current_msg = None - - def _bot_internal_handler(self, messages): - """Bot internal messages handler""" - for message in messages: - self.current_msg = message - self.handle_message(message) - - def start(self): - """Start polling msgs from users, this function never returns""" - logger.info(f'{self.__class__.__name__} is up and listening to new messages....') - logger.info('Telegram Bot information') - logger.info(self.bot.get_me()) - - self.bot.infinity_polling() - - def send_text(self, text): - self.bot.send_message(self.current_msg.chat.id, text) - - def send_text_with_quote(self, text, message_id): - self.bot.send_message(self.current_msg.chat.id, text, reply_to_message_id=message_id) - - def is_current_msg_photo(self): - return self.current_msg.content_type == 'photo' - - def download_user_photo(self, quality=0): - """ - Downloads photos sent to the Bot to `photos` directory (should be existed) - :param quality: integer representing the file quality. Allowed values are [0, 1, 2, 3] - :return: - """ - if self.current_msg.content_type != 'photo': - raise RuntimeError(f'Message content of type \'photo\' expected, but got {self.current_msg["content_type"]}') - - file_info = self.bot.get_file(self.current_msg.photo[quality].file_id) - data = self.bot.download_file(file_info.file_path) - - # TODO save `data` as a photo in `file_info.file_path` path - - def handle_message(self, message): - """Bot Main message handler""" - logger.info(f'Incoming message: {message}') - self.send_text(f'Your original message: {message.text}') - - -class QuoteBot(Bot): - def handle_message(self, message): - if message.text != 'Don\'t quote me please': - self.send_text_with_quote(message.text, message_id=message.message_id) - - -class YoutubeBot(Bot): - pass - - -if __name__ == '__main__': - with open('.telegramToken') as f: - _token = f.read() - - my_bot = Bot(_token) - my_bot.start() - - +import telebot +from utils import search_download_youtube_video +from loguru import logger + +class Bot: + def __init__(self, token): + self.bot = telebot.TeleBot(token, threaded=False) + self.bot.set_update_listener(self._bot_internal_handler) + + self.current_msg = None + + def _bot_internal_handler(self, messages): + """Bot internal messages handler""" + for message in messages: + self.current_msg = message + self.handle_message(message) + + def start(self): + """Start polling msgs from users, this function never returns""" + logger.info(f'{self.__class__.__name__} is up and listening to new messages....') + logger.info('Telegram Bot information') + logger.info(self.bot.get_me()) + + self.bot.infinity_polling() + + def send_text(self, text): + self.bot.send_message(self.current_msg.chat.id, text) + + def send_text_with_quote(self, text, message_id): + self.bot.send_message(self.current_msg.chat.id, text, reply_to_message_id=message_id) + + def is_current_msg_photo(self): + return self.current_msg.content_type == 'photo' + + def download_user_photo(self, quality=0): + """ + Downloads photos sent to the Bot to `photos` directory (should be existed) + :param quality: integer representing the file quality. Allowed values are [0, 1, 2, 3] + :return: + """ + if self.current_msg.content_type != 'photo': + raise RuntimeError(f'Message content of type \'photo\' expected, but got {self.current_msg["content_type"]}') + + file_info = self.bot.get_file(self.current_msg.photo[quality].file_id) + data = self.bot.download_file(file_info.file_path) + + # TODO save `data` as a photo in `file_info.file_path` path + + def handle_message(self, message): + """Bot Main message handler""" + logger.info(f'Incoming message: {message}') + self.send_text(f'Your original message: {message.text}') + + +class QuoteBot(Bot): + def handle_message(self, message): + if message.text != 'Don\'t quote me please': + self.send_text_with_quote(message.text, message_id=message.message_id) + + +class Bot(Bot): + def handle_message(self, message): + if self.is_current_msg_photo(): + self.download_user_photo(quality=3) + return + + video = search_download_youtube_video(message.text) + self.send_text(video[0].get("url")) + + +if __name__ == '__main__': + with open('.telegramToken') as f: + _token = f.read() + + my_bot = Bot(_token) + my_bot.start() \ No newline at end of file diff --git a/data/readme.txt b/data/readme.txt new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt index 1e50522..4337829 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -pyTelegramBotAPI -yt-dlp>=2022.6.29 +pyTelegramBotAPI +yt-dlp>=2022.6.29 loguru \ No newline at end of file diff --git a/utils.py b/utils.py index e5426e0..c32c8a6 100644 --- a/utils.py +++ b/utils.py @@ -1,24 +1,24 @@ -import time -from yt_dlp import YoutubeDL - - -def search_download_youtube_video(video_name, num_results=1): - """ - This function downloads the first num_results search results from Youtube - :param video_name: string of the video name - :param num_results: integer representing how many videos to download - :return: list of paths to your downloaded video files - """ - results = [] - with YoutubeDL() as ydl: - videos = ydl.extract_info(f"ytsearch{num_results}:{video_name}", download=True)['entries'] - - for video in videos: - results.append({ - 'filename': ydl.prepare_filename(video), - 'video_id': video['id'], - 'title': video['title'], - 'url': video['webpage_url'] - }) - - return results +import time +from yt_dlp import YoutubeDL + + +def search_download_youtube_video(video_name, num_results=1): + """ + This function downloads the first num_results search results from Youtube + :param video_name: string of the video name + :param num_results: integer representing how many videos to download + :return: list of paths to your downloaded video files + """ + results = [] + with YoutubeDL() as ydl: + videos = ydl.extract_info(f"ytsearch{num_results}:{video_name}", download=False)['entries'] + + for video in videos: + results.append({ + 'filename': ydl.prepare_filename(video), + 'video_id': video['id'], + 'title': video['title'], + 'url': video['webpage_url'] + }) + + return results