From 551e69c5ebd7a227478105ac1cc91876f1c2f601 Mon Sep 17 00:00:00 2001 From: Tolmachev Igor Date: Sun, 15 Sep 2024 01:20:00 +0300 Subject: Add story publisher module --- .vscode/settings.json | 2 +- video2story/__main__.py | 73 ++++++++++++++++++++-------- video2story/uploader.py | 125 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 176 insertions(+), 24 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a205f43..d6063cb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,5 @@ "**/__pycache__": true, "**/.venv": true }, - "cSpell.words": ["screenshotting"] + "cSpell.words": ["screenshotting", "tdlib"] } diff --git a/video2story/__main__.py b/video2story/__main__.py index 8e08cac..43c94b8 100644 --- a/video2story/__main__.py +++ b/video2story/__main__.py @@ -40,8 +40,7 @@ video_parser.add_argument( default=60, help=( "Specifies each story duration.\n" - "When set to 0 each story will be an image.\n" - "Max value is 60 and min value is 0.\n" + "Max value is 60 and min value is 1.\n" "Default is 60." ), ) @@ -67,7 +66,6 @@ video_parser.add_argument( help="Specifies the second of the video from which processing will end.", ) - story_parser = subparsers.add_parser( "story", help="Story publishing module", @@ -75,27 +73,31 @@ story_parser = subparsers.add_parser( ) story_parser.add_argument( - "action", + "phone", type=str, - metavar="ACTION", - choices=["publish-all", "publish-one"], - help=( - "Specifies the type of publishing action.\n" - "Accept values: `publish-all` and `publish-one`.\n" - ), + metavar="PHONE", + help="Your phone number.", +) +story_parser.add_argument( + "input", + type=str, + metavar="PATH", + help="Input folder with processed videos", ) story_parser.add_argument( - "privacy", + "-p", + "--privacy", type=str, metavar="PRIVACY-MODE", - choices=["everyone", "contacts", "selected-users", "close-friends"], + choices=["everyone", "contacts", "selected", "friends"], + default="everyone", help=( "Specifies who can see you story.\n" - "Accept values: `everyone`, `contacts`, `selected-users` and `close-friends`.\n" + "Accept values: `everyone`, `contacts`, `selected` and `friends`.\n" "\n" "If set to `everyone` or `contacts`, the --user flag excludes the user who can see your story.\n" - "If set to `selected-users`, the --user flag specifies the user who can see your story.\n" - "If set to `close-friends`, the --user flag will have no effect.\n" + "If set to `selected`, the --user flag specifies the user who can see your story.\n" + "If set to `friends`, the --user flag will have no effect.\n" ), ) story_parser.add_argument( @@ -104,7 +106,10 @@ story_parser.add_argument( type=str, metavar="USERS", nargs="+", - help="Behavior depends on privacy mode. See `privacy` description.", + help=( + "Behavior depends on privacy mode. See `privacy` description.\n" + "You can specify a username or user id." + ), ) story_parser.add_argument( "-a", @@ -119,14 +124,25 @@ story_parser.add_argument( "Default is 24h." ), ) +story_parser.add_argument( + "--save-to-profile", + action="store_true", + help="Keep the story accessible after expiration.", +) story_parser.add_argument( "--protected-content", action="store_true", help="Protect story from forwarding and screenshotting.", ) story_parser.add_argument( - "-f", - "--from", + "--tdlib", + type=str, + metavar="PATH", + help="Path to tdlib library file.", +) +story_parser.add_argument( + "-s", + "--start", type=int, metavar="VIDEO-ID", default=0, @@ -137,8 +153,8 @@ story_parser.add_argument( ), ) story_parser.add_argument( - "-t", - "--to", + "-e", + "--end", type=int, metavar="VIDEO-ID", default=None, @@ -151,6 +167,10 @@ story_parser.add_argument( args = parser.parse_args() if args.module == "video": + if not (1 <= args.duration <= 60): + print("Duration must be between 1 and 60") + exit(1) + cut( normpath(args.filename), normpath(args.output), @@ -160,4 +180,15 @@ if args.module == "video": args.end, ) elif args.module == "story": - pass + upload( + args.phone, + normpath(args.input), + args.privacy, + args.users, + args.active_period, + args.save_to_profile, + args.protected_content, + args.tdlib, + args.start, + args.end, + ) diff --git a/video2story/uploader.py b/video2story/uploader.py index dde8c98..d61ca43 100644 --- a/video2story/uploader.py +++ b/video2story/uploader.py @@ -1,2 +1,123 @@ -def upload() -> None: - pass \ No newline at end of file +from os import listdir +from os.path import isdir, join +from threading import Event +from time import sleep + +from telegram.client import Telegram + + +def upload( + phone: str, + input_dir: str, + privacy: str, + users: list[str] | None, + active_period: str, + save_to_profile: bool, + protected_content: bool, + tdlib: str | None, + start: int, + end: int | None, +) -> None: + telegram = Telegram( + api_id=2092395, + api_hash="38e26914cf0fda6356fda8f9d28f3bb9", + database_encryption_key="just a secret", + tdlib_verbosity=0, + library_path=tdlib, + phone=phone, + ) + telegram.login() + me = int(telegram.call_method("getMe", block=True).update["id"]) + + if users is not None: + user_ids = [] + for u in users: + if u.isdigit(): + user_ids.append(int(u)) + continue + + try: + user_ids.append( + telegram.call_method( + "searchPublicChat", + {"username": u.strip().removeprefix("@")}, + block=True, + ).update["id"] + ) + except Exception: + print(f"An error occurred while getting user id ({u}).") + else: + user_ids = None + + if not isdir(input_dir): + print("Input folder does not exists") + exit(1) + + queue = set() + done = Event() + + for i in range(start, (end + 1) if end is not None else len(listdir(input_dir))): + print(f"Adding to the uploading queue. (VIDEO-ID: {i})") + + queue.add( + telegram.call_method( + "sendStory", + { + "chat_id": me, + "content": { + "@type": "inputStoryContentVideo", + "video": { + "@type": "inputFileLocal", + "path": join(input_dir, f"{i}.mp4"), + }, + }, + "areas": None, + "caption": None, + "privacy_settings": { + "everyone": { + "@type": "storyPrivacySettingsEveryone", + "except_user_ids": user_ids, + }, + "contacts": { + "@type": "storyPrivacySettingsContacts", + "except_user_ids": user_ids, + }, + "selected": { + "@type": "storyPrivacySettingsSelectedUsers", + "user_ids": user_ids, + }, + "friends": { + "@type": "storyPrivacySettingsCloseFriends", + }, + }[privacy], + "active_period": { + "6h": 21600, + "12h": 43200, + "24h": 86400, + "48h": 172800, + }[active_period], + "is_posted_to_chat_page": save_to_profile, + "protect_content": protected_content, + }, + block=True, + ).update["content"]["video"]["video"]["id"] + ) + sleep(0.5) + + print(f"Uploading. {len(queue)} left") + + def update(file: dict[str, object]) -> None: + if ( + file["file"]["id"] in queue + and not file["file"]["remote"]["is_uploading_active"] + ): + queue.remove(file["file"]["id"]) + + if len(queue) == 0: + print("Done") + done.set() + else: + print(f"Uploading. {len(queue)} left") + + telegram.add_update_handler("updateFile", update) + done.wait() -- cgit v1.2.3