diff --git a/.env_sample b/.env_sample new file mode 100644 index 0000000..d962d4b --- /dev/null +++ b/.env_sample @@ -0,0 +1,4 @@ +TOKEN= +ALLOWED_USERS= +ADMIN= +MEGA=,, diff --git a/Pipfile b/Pipfile index 8ec64ff..641715e 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,7 @@ name = "pypi" [packages] pytelegrambotapi = "*" +"mega.py" = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 4c031b6..0182f1c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "77d6cd72469868b878cf3239d2e87a1255a5c38e7dca5cd457e6eb6128e6cac1" + "sha256": "2245d4f0288fcda4cc0f3fd3a9d9da82427e95aa9ff0e843735891e060f4511c" }, "pipfile-spec": 6, "requires": { @@ -40,6 +40,57 @@ "markers": "python_version >= '3.5'", "version": "==3.3" }, + "mega.py": { + "hashes": [ + "sha256:0632664abda8b7e4d0bbd68460da4b331d3d7d63db9afe7d3ce6fcb4f137c1a9", + "sha256:863b2dd59f8e639402fef3c67778fd63895fc1b678127e7006df1544f04e737c" + ], + "index": "pypi", + "version": "==1.0.8" + }, + "pathlib": { + "hashes": [ + "sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f", + "sha256:f35f95ab8b0f59e6d354090350b44a80a80635d22efdedfa84c7ad1cf0a74147" + ], + "version": "==1.0.1" + }, + "pycryptodome": { + "hashes": [ + "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79", + "sha256:0926f7cc3735033061ef3cf27ed16faad6544b14666410727b31fea85a5b16eb", + "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e", + "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88", + "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763", + "sha256:2ea63d46157386c5053cfebcdd9bd8e0c8b7b0ac4a0507a027f5174929403884", + "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13", + "sha256:2ffd8b31561455453ca9f62cb4c24e6b8d119d6d531087af5f14b64bee2c23e6", + "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2", + "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667", + "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a", + "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d", + "sha256:60b4faae330c3624cc5a546ba9cfd7b8273995a15de94ee4538130d74953ec2e", + "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b", + "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83", + "sha256:9135dddad504592bcc18b0d2d95ce86c3a5ea87ec6447ef25cfedea12d6018b8", + "sha256:9c772c485b27967514d0df1458b56875f4b6d025566bf27399d0c239ff1b369f", + "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f", + "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676", + "sha256:a8f06611e691c2ce45ca09bbf983e2ff2f8f4f87313609d80c125aff9fad6e7f", + "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8", + "sha256:b9cc96e274b253e47ad33ae1fccc36ea386f5251a823ccb50593a935db47fdd2", + "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f", + "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9", + "sha256:d2a39a66057ab191e5c27211a7daf8f0737f23acbf6b3562b25a62df65ffcb7b", + "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1", + "sha256:ecaaef2d21b365d9c5ca8427ffc10cebed9d9102749fd502218c23cb9a05feb5", + "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c", + "sha256:ff287bcba9fbeb4f1cccc1f2e90a08d691480735a611ee83c80a7d74ad72b9d9", + "sha256:ff7ae90e36c1715a54446e7872b76102baa5c63aa980917f4aa45e8c78d1a3ec" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==3.15.0" + }, "pytelegrambotapi": { "hashes": [ "sha256:b1aea4c3c867586b7efaa80d54db3b710f4b24aeb8095bfcef568ff27d3ca510" @@ -55,6 +106,21 @@ "markers": "python_version >= '3.7' and python_version < '4'", "version": "==2.28.1" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "tenacity": { + "hashes": [ + "sha256:3a916e734559f1baa2cab965ee00061540c41db71c3bf25375b81540a19758fc", + "sha256:e664bd94f088b17f46da33255ae33911ca6a0fe04b156d334b601a4ef66d3c5f" + ], + "version": "==5.1.5" + }, "urllib3": { "hashes": [ "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", diff --git a/Readme.md b/Readme.md index 8bd0bec..be916f3 100644 --- a/Readme.md +++ b/Readme.md @@ -13,12 +13,13 @@ Take Photo/Audio/Video from webcam by remotely controlling it using a Telegram b 1. `/photo` - Take photo 2. `/audio` - Take audio 3. `/video` - Take video - +1. A mega account is also needed to upload larger files and accordingly the mega account credentials need to be put in the .env file. **NOTE:** 1. If different devices are used for video and audio recording, then there may be some sync issue. 1. Current codebase uses a polling method for the bot to communicate with the telegram server, for a production level solution a webhook should be used. +1. A smaple `.env` file is also provided [env_sample](./.env_sample) diff --git a/telegramBot.py b/telegramBot.py index 98cfdad..f69bddf 100644 --- a/telegramBot.py +++ b/telegramBot.py @@ -2,11 +2,19 @@ from telebot import TeleBot from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton import logging, shutil +from mega import Mega + + + + + TOKEN = os.getenv('TOKEN') ALLOWED_USERS = [int(i) for i in os.getenv('ALLOWED_USERS').split()] ADMIN = os.getenv('ADMIN') + + bot = TeleBot(TOKEN, parse_mode='HTML') @@ -25,7 +33,7 @@ def remind(self, userid: int): def nudge(self): message = bot.send_message(self.userid, "Recording in progress. Don't forget to finish") - deleteMessage(message,10) # delete this notification after 10 seconds + deleteMessage(message,60) # delete this notification after 10 seconds def cancel(self): self.timer.cancel() @@ -73,7 +81,7 @@ def checkRequest(message): -@bot.message_handler(commands='start') +@bot.message_handler(commands=['start']) def send_welcome(message): if checkRequest(message): return @@ -81,7 +89,7 @@ def send_welcome(message): -@bot.message_handler(commands='photo') +@bot.message_handler(commands=['photo']) def send_photo(message): user = message.from_user.id if checkRequest(message): @@ -143,7 +151,7 @@ def keepPhoto(self,ranStr): photoK = PhotoKeeper() -@bot.message_handler(commands='audio') +@bot.message_handler(commands=['audio']) def send_audio(message): # start audio recording user = message.from_user.id @@ -159,7 +167,7 @@ def send_audio(message): -@bot.message_handler(commands='video') +@bot.message_handler(commands=['video']) def send_video(message): user = message.from_user.id if checkRequest(message): @@ -196,7 +204,7 @@ def callback_query(call): remind.cancel() # clear all reminder user = call.from_user.id - if not recorder.isRunning : + if not recorder.isRunning: bot.send_message(user, "No recording is currently in progress !!!") return @@ -205,27 +213,28 @@ def callback_query(call): size = os.path.getsize(file)/1e6 logger.info(f"Recording finished: {os.path.basename(file)} ({act:.2f} sec) ({size:.2f} MB)") - msg = bot.send_message(user, - "Recording saved successfully. Wait while the bot uploads the file." + - (" Due Telegram restrictions the file will be split." if size>48.0 else "") - ) - if size > 48.0: # Telegram file size restriction is 50 MB - files = splitFilesInChunks(file) - else: - files = [file] - - try: - for file in files: - print('-----------------', os.path.getsize(file)) - with open(file, 'rb') as f: - if file.endswith('mp4'): - bot.send_video(user, f) - else: - bot.send_audio(user, f) + msg = bot.send_message(user, "Recording saved successfully. Wait while the bot uploads the file.") + + uploaded = False + + try: # telegram server won't accept file larger than 50 mb + if size>49: + raise Exception('File too large to upload') + with open(file,'rb') as ff: + if file.endswith('mp4'): + bot.send_video(user, ff) + else: + bot.send_audio(user, ff) except: - bot.send_message(user, - f"Something went wrong while uploading the file file. You can find the file stored as {file}") - + mm = bot.send_message(user, f"Something went wrong while uploading the file to telegram server." + "The bot will upload the file to a remote server") + link = mClient.get_upload_link(mClient.upload(file, MEGA_FOLDER)) + deleteMessage(mm) + bot.send_message(user,link) + uploaded = True + finally: + if not uploaded: # upload it anyway for future storage + mClient.upload(file, MEGA_FOLDER) deleteMessage(msg) @@ -240,4 +249,7 @@ def callback_query(call): bot.send_message(ADMIN, "Starting bot") -bot.infinity_polling() \ No newline at end of file +mega = Mega() +user,pasw,MEGA_FOLDER = os.getenv('MEGA').split(',') +mClient = mega.login(user,pasw) +bot.infinity_polling() diff --git a/utils.py b/utils.py index 66e629b..c0d478a 100644 --- a/utils.py +++ b/utils.py @@ -59,7 +59,7 @@ class AVRecorder: def __init__(self): self.commonFlags = 'ffmpeg -hide_banner -f dshow -y -video_size 1280x720 -rtbufsize 2G'.split() - self.vidFlags = "-vcodec libx265 -crf 28 -r 21".split() + self.vidFlags = "-vcodec libx265 -crf 28 -r 17".split() # get list of devices with `ffmpeg -list_devices true -f dshow -i dummy` # self.audioInput = "audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" # self.videoInput = "video=HP HD Camera"