From 8ad3ab03734a4cdbac793ff13e824ffbe481a22f Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 1 Jun 2022 19:43:09 -0400 Subject: [PATCH 01/23] added twt handle --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index fd7a139..870ad7e 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,7 @@ from video_creation.final_video import make_final_video # base code by elebumm print_markdown( - "### Thanks for using this tool! 😊 Feel free to contribute to this project on GitHub! (JasonLovesDoggo/RedditVideoMakerBot). If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue.") + "### Thanks for using this tool! 😊 Feel free to contribute to this project on GitHub! (JasonLovesDoggo/RedditVideoMakerBot). If you have any questions, feel free to reach out to me on Twitter @JasonLovesDoggo or submit a GitHub issue.") time.sleep(2) From 96d0bcfdd83a0862f3f87e3f3c6119317c4dc8de Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 1 Jun 2022 22:26:41 -0400 Subject: [PATCH 02/23] fp issue nightly backup --- reddit/subreddit.py | 2 -- video_creation/data/videos.json | 10 +++++++++- video_creation/voices.py | 27 ++++++++++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 9a19c55..5bf475f 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -12,8 +12,6 @@ TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234 def textify(text): return ''.join(filter(TEXT_WHITELIST.__contains__, text)) - - def get_subreddit_threads(): """ Returns a list of threads from the AskReddit subreddit. diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index fe51488..2a417ad 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -1 +1,9 @@ -[] +[ + { + "id": "v2kd2q", + "time": "1654128204", + "background_credit": "bbswitzer", + "reddit_title": "What movie do you absolutely love yet acknowledge is not a super wellmade movie", + "filename": "What movie do you absolutely l....mp4" + } +] \ No newline at end of file diff --git a/video_creation/voices.py b/video_creation/voices.py index ccb4a9d..5f6797b 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -1,3 +1,5 @@ +from os import remove + import sox from pathlib import Path @@ -8,6 +10,8 @@ from rich.progress import track from video_creation.TTSwrapper import TTTTSWrapper +VIDEO_LENGTH: int = 40 # secs + def save_text_to_mp3(reddit_obj): """Saves Text to MP3 files. @@ -27,18 +31,27 @@ def save_text_to_mp3(reddit_obj): length += MP3(f"assets/temp/mp3/title.mp3").info.length except HeaderNotFoundError: length = sox.file_info.duration(f"assets/temp/mp3/title.mp3") - - for idx, comment in track(enumerate(reddit_obj["comments"]), "Saving..."): + com = 0 + for comment in track((reddit_obj["comments"]), "Saving..."): # ! Stop creating mp3 files if the length is greater than 50 seconds. This can be longer, but this is just a good_voices starting point - if length > 50: + if length > VIDEO_LENGTH: break - ttttsw.tts(comment["comment_body"], filename=f"assets/temp/mp3/{idx}.mp3", random_speaker=False) + ttttsw.tts(comment["comment_body"], filename=f"assets/temp/mp3/{com}.mp3", random_speaker=False) try: - length += MP3(f"assets/temp/mp3/{idx}.mp3").info.length + length += MP3(f"assets/temp/mp3/{com}.mp3").info.length + com += 1 except (HeaderNotFoundError, MutagenError, Exception): - length = sox.file_info.duration(f"assets/temp/mp3/{idx}.mp3") + try: + length += sox.file_info.duration(f"assets/temp/mp3/{com}.mp3") + com += 1 + except (OSError, IOError): + print('would have removed' + f"assets/temp/mp3/{com}.mp3" + f"assets/temp/png/comment_{com}.png") + #remove(f"assets/temp/mp3/{com}.mp3") + #remove(f"assets/temp/png/comment_{com}.png")# todo might cause odd un-syncing print_substep("Saved Text to MP3 files Successfully.", style="bold green") # ! Return the index so we know how many screenshots of comments we need to make. - return length, idx + return length, com From 43e29af04a07c44ca7ed796d579602d84b57d793 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Jun 2022 17:39:08 -0400 Subject: [PATCH 03/23] added TFA --- .env.template | 3 +++ README.md | 11 +++++------ reddit/subreddit.py | 40 +++++++++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.env.template b/.env.template index 3cd9dd4..01028a5 100644 --- a/.env.template +++ b/.env.template @@ -2,7 +2,10 @@ REDDIT_CLIENT_ID="" REDDIT_CLIENT_SECRET="" REDDIT_USERNAME="" REDDIT_PASSWORD="" +# Valid options are "yes" and "no" for the variable below +REDDIT_2FA="" SUBREDDIT="AskReddit" ALLOW_NSFW="False" +# Example of a PostID is ult7el POST_ID="" THEME="LIGHT" diff --git a/README.md b/README.md index d0e59df..82b0004 100644 --- a/README.md +++ b/README.md @@ -31,18 +31,17 @@ These videos on TikTok, YouTube and Instagram get MILLIONS of views across all p ## Installation 👩‍💻 1. Clone this repository -2. Rename `.env.template` to `.env` and replace all values with the appropriate fields. To get Reddit keys (**required**), visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps) TL;DR set up an app that is a "script". Copy your keys into the `.env` files. +2. Rename `.env.template` to `.env` and replace all values with the appropriate fields. To get Reddit keys (**required**), visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps) TL;DR set up an app that is a "script". Copy your keys into the `.env` file, along with whether your account uses two-factor authentication. 3. Run `pip3 install -r requirements.txt` 4. install [SoX](https://sourceforge.net/projects/sox/files/sox/) -5. Run `python3 main.py` -6. Enjoy 😎 -## Usage - * an example of a reddit ID is ult7el +5. Run `playwright install` and `playwright install-deps`. +6. Run `python3 main.py` +7. Enjoy 😎 ## Contributing & Ways to improve 📈 In its current state, this bot does exactly what it needs to do. However, lots of improvements can be made. -I have tried to simplify the code so anyone can read it and start contibuting at any skill level. Don't be shy :) contribute! +I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute! - [ ] Creating better documentation and adding a command line interface. - [x] Allowing users to choose a reddit thread instead of being randomized. diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 5bf475f..cd6bd25 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -7,45 +7,55 @@ from dotenv import load_dotenv from os import getenv, environ from utils.videos import check_done + TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890') + def textify(text): return ''.join(filter(TEXT_WHITELIST.__contains__, text)) + def get_subreddit_threads(): """ Returns a list of threads from the AskReddit subreddit. """ print_step("Getting subreddit threads...") - content = {} load_dotenv() + if getenv("REDDIT_2FA").casefold() == "yes": + print("\nEnter your two-factor authentication code from your authenticator app.\n") + code = input("> ") + print() + pw = getenv("REDDIT_PASSWORD") + passkey = f"{pw}:{code}" + else: + passkey = getenv("REDDIT_PASSWORD") reddit = praw.Reddit(client_id=getenv("REDDIT_CLIENT_ID"), client_secret=getenv("REDDIT_CLIENT_SECRET"), user_agent="Accessing AskReddit threads", username=getenv("REDDIT_USERNAME"), - password=getenv("REDDIT_PASSWORD"), ) + passkey=passkey, ) """ Ask user for subreddit input """ - if not getenv("SUBREDDIT"): - subreddit = reddit.subreddit( - input("What subreddit would you like to pull from? ")) # if the env isnt set, ask user - else: - print_substep(f"Using subreddit: r/{getenv('SUBREDDIT')} from environment variable config") - subreddit = reddit.subreddit( - getenv("SUBREDDIT")) # Allows you to specify in .env. Done for automation purposes. if getenv('POST_ID'): submission = reddit.submission(id=getenv('POST_ID')) else: + if getenv("SUBREDDIT"): # Allows you to specify in .env. Done for automation purposes. + subreddit = reddit.subreddit(getenv("SUBREDDIT")) + else: + # Prompt the user to enter a subreddit + try: + subreddit = reddit.subreddit(input("What subreddit would you like to pull from? ")) + except ValueError: + subreddit = reddit.subreddit("askreddit") + print_substep("Subreddit not defined. Using AskReddit.") threads = subreddit.hot(limit=25) submission = list(threads)[random.randrange(0, 25)] submission = check_done(submission) + print_substep(f"Video will be: {submission.title} :thumbsup:") - print_substep( - f'subreddit thread is: {submission.title}\n(if you dont like this, you can change it by exiting and rerunning the program)') - - environ["VIDEO_TITLE"] = str(textify(submission.title)) + environ["VIDEO_TITLE"] = str(textify(submission.title)) # todo use global instend of env vars environ["VIDEO_ID"] = str(textify(submission.id)) try: @@ -56,9 +66,9 @@ def get_subreddit_threads(): for top_level_comment in submission.comments: content["comments"].append( {"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink, - "comment_id": top_level_comment.id, }) + "comment_id": top_level_comment.id, }) except AttributeError as e: pass - print_substep("Received subreddit threads Successfully.", style="bold green") + print_substep("Received subreddit thread Successfully.", style="bold green") return content From 3ecfd14edb0e7c8343498694ec3f442fb60e6867 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Jun 2022 18:32:11 -0400 Subject: [PATCH 04/23] fixed postID message timing --- utils/videos.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/videos.py b/utils/videos.py index 66b9a75..4f69b5d 100644 --- a/utils/videos.py +++ b/utils/videos.py @@ -8,14 +8,14 @@ from utils.console import print_step def check_done(redditobj): # don't set this to be run anyplace that isn't subreddit.py bc of inspect stack """params: reddit_object: The Reddit Object you received in askreddit.py""" - if getenv('POST_ID'): - print_step( - 'You already have done this video but since it was declared specifically in the .env file the program will continue') - return redditobj with open('./video_creation/data/videos.json', 'r') as done_vids_raw: done_videos = json.load(done_vids_raw) for video in done_videos: if video['id'] == str(redditobj): + if getenv('POST_ID'): + print_step( + 'You already have done this video but since it was declared specifically in the .env file the program will continue') + return redditobj print_step('Getting new post as the current one has already been done') from reddit.subreddit import get_subreddit_threads return get_subreddit_threads() # recursive func From 2c2a5974434bb50a74bdd80d97dcb2cb56b18f24 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Jun 2022 18:33:38 -0400 Subject: [PATCH 05/23] updated requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5744dee..0578bfb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ praw~=7.6.0 moviepy~=1.0.3 rich~=12.4.4 mutagen~=1.45.1 -pytube~=12.1.0 playwright~=1.22.0 python-dotenv==0.20.0 typed-ast~=1.5.4 requests~=2.27.1 +yt-dlp From 519e5247e95b27b956300e973bb114b3408fbc18 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Jun 2022 18:34:02 -0400 Subject: [PATCH 06/23] updated the environment file template --- .env.template | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.template b/.env.template index 01028a5..b9b8875 100644 --- a/.env.template +++ b/.env.template @@ -5,7 +5,11 @@ REDDIT_PASSWORD="" # Valid options are "yes" and "no" for the variable below REDDIT_2FA="" SUBREDDIT="AskReddit" +# True or False ALLOW_NSFW="False" # Example of a PostID is ult7el POST_ID="" +#set to either LIGHT or DARK THEME="LIGHT" +# set to an int e.g. 1 or 29 and leave blank for once +TIMES_TO_RUN="" From 3c9bc3d0caf63f27fa64cfae56dc3f455a7693bb Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Jun 2022 18:34:19 -0400 Subject: [PATCH 07/23] removed unnecessary askreddit.py --- reddit/askreddit.py | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 reddit/askreddit.py diff --git a/reddit/askreddit.py b/reddit/askreddit.py deleted file mode 100644 index c11791c..0000000 --- a/reddit/askreddit.py +++ /dev/null @@ -1,45 +0,0 @@ -from utils.console import print_step, print_substep -import praw -import random -from dotenv import load_dotenv -import os - - -def get_askreddit_threads(): - """ - Returns a list of threads from the AskReddit subreddit. - """ - - print_step("Getting AskReddit threads...") - - content = {} - load_dotenv() - reddit = praw.Reddit( - client_id=os.getenv("REDDIT_CLIENT_ID"), - client_secret=os.getenv("REDDIT_CLIENT_SECRET"), - user_agent="Accessing AskReddit threads", - username=os.getenv("REDDIT_USERNAME"), - password=os.getenv("REDDIT_PASSWORD"), - ) - askreddit = reddit.subreddit("askreddit") - threads = askreddit.hot(limit=25) - submission = list(threads)[random.randrange(0, 25)] - try: - - content["thread_url"] = submission.url - content["thread_title"] = submission.title - content["comments"] = [] - - for top_level_comment in submission.comments: - content["comments"].append( - { - "comment_body": top_level_comment.body, - "comment_url": top_level_comment.permalink, - "comment_id": top_level_comment.id, - } - ) - - except AttributeError as e: - pass - print_substep("Received AskReddit threads Successfully.", style="bold green") - return content From f491479fb7c5efed1c2c9c77689f0800467566d5 Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 4 Jun 2022 12:48:35 -0400 Subject: [PATCH 08/23] backup --- README.md | 14 ++++++--- main.py | 23 ++++++++++---- reddit/subreddit.py | 11 +++---- utils/cleanup.py | 1 - utils/videos.py | 1 - video_creation/TTSwrapper.py | 5 ++-- video_creation/background.py | 40 ++++++++++++++----------- video_creation/data/videos.json | 16 +++++----- video_creation/screenshot_downloader.py | 11 +++---- video_creation/voices.py | 16 +++++----- 10 files changed, 78 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 82b0004..0f7c5a8 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,16 @@ Created by Lewis Menelaws & [TMRRW](https://tmrrwinc.ca) ## Motivation 🤔 -These videos on TikTok, YouTube and Instagram get MILLIONS of views across all platforms and require very little effort. The only original thing being done is the editing and gathering of all materials... +These videos on TikTok, YouTube and Instagram get MILLIONS of views across all platforms and require very little effort. +The only original thing being done is the editing and gathering of all materials... ... but what if we can automate that process? 🤔 ## Disclaimers 🚨 - This is purely for fun purposes. -- **At the moment**, this repository won't attempt to upload this content through this bot. It will give you a file that you will then have to upload manually. This is for the sake of avoiding any sort of community guideline issues. +- **At the moment**, this repository won't attempt to upload this content through this bot. It will give you a file that + you will then have to upload manually. This is for the sake of avoiding any sort of community guideline issues. ## Requirements @@ -31,17 +33,21 @@ These videos on TikTok, YouTube and Instagram get MILLIONS of views across all p ## Installation 👩‍💻 1. Clone this repository -2. Rename `.env.template` to `.env` and replace all values with the appropriate fields. To get Reddit keys (**required**), visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps) TL;DR set up an app that is a "script". Copy your keys into the `.env` file, along with whether your account uses two-factor authentication. +2. Rename `.env.template` to `.env` and replace all values with the appropriate fields. To get Reddit keys (** + required**), visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps) TL;DR set up an app that is a "script". + Copy your keys into the `.env` file, along with whether your account uses two-factor authentication. 3. Run `pip3 install -r requirements.txt` 4. install [SoX](https://sourceforge.net/projects/sox/files/sox/) 5. Run `playwright install` and `playwright install-deps`. 6. Run `python3 main.py` 7. Enjoy 😎 + ## Contributing & Ways to improve 📈 In its current state, this bot does exactly what it needs to do. However, lots of improvements can be made. -I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) contribute! +I have tried to simplify the code so anyone can read it and start contributing at any skill level. Don't be shy :) +contribute! - [ ] Creating better documentation and adding a command line interface. - [x] Allowing users to choose a reddit thread instead of being randomized. diff --git a/main.py b/main.py index 870ad7e..04e1143 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,17 @@ +import os +import time + +from dotenv import load_dotenv + +from reddit.subreddit import get_subreddit_threads from utils.cleanup import cleanup from utils.console import print_markdown -import time -from reddit.subreddit import get_subreddit_threads from video_creation.background import download_background, chop_background_video -from video_creation.voices import save_text_to_mp3 -from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.final_video import make_final_video +from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts +from video_creation.voices import save_text_to_mp3 +load_dotenv() # base code by elebumm print_markdown( "### Thanks for using this tool! 😊 Feel free to contribute to this project on GitHub! (JasonLovesDoggo/RedditVideoMakerBot). If you have any questions, feel free to reach out to me on Twitter @JasonLovesDoggo or submit a GitHub issue.") @@ -34,9 +39,17 @@ def main(): final_video = make_final_video(number_of_comments) +def run_many(times): + for x in range(times): + main() + + if __name__ == '__main__': try: - main() + if os.getenv('TIMES_TO_RUN'): + run_many(int(os.getenv('TIMES_TO_RUN'))) + else: + main() except KeyboardInterrupt: print_markdown("## Clearing temp files") cleanup() diff --git a/reddit/subreddit.py b/reddit/subreddit.py index cd6bd25..5fc79da 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -1,11 +1,9 @@ -import re - -from utils.console import print_step, print_substep -import praw import random -from dotenv import load_dotenv from os import getenv, environ +import praw + +from utils.console import print_step, print_substep from utils.videos import check_done TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890') @@ -22,7 +20,6 @@ def get_subreddit_threads(): print_step("Getting subreddit threads...") content = {} - load_dotenv() if getenv("REDDIT_2FA").casefold() == "yes": print("\nEnter your two-factor authentication code from your authenticator app.\n") code = input("> ") @@ -66,7 +63,7 @@ def get_subreddit_threads(): for top_level_comment in submission.comments: content["comments"].append( {"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink, - "comment_id": top_level_comment.id, }) + "comment_id": top_level_comment.id, }) except AttributeError as e: pass diff --git a/utils/cleanup.py b/utils/cleanup.py index ee3453b..5c31e05 100644 --- a/utils/cleanup.py +++ b/utils/cleanup.py @@ -20,4 +20,3 @@ def cleanup() -> int: os.remove('./assets/temp/mp3/' + file) return count return 0 - diff --git a/utils/videos.py b/utils/videos.py index 4f69b5d..c163076 100644 --- a/utils/videos.py +++ b/utils/videos.py @@ -1,4 +1,3 @@ -import inspect import json from os import getenv diff --git a/video_creation/TTSwrapper.py b/video_creation/TTSwrapper.py index e239e81..4498184 100644 --- a/video_creation/TTSwrapper.py +++ b/video_creation/TTSwrapper.py @@ -1,4 +1,6 @@ -import requests, base64, random, os +import base64 +import random +import requests # https://twitter.com/scanlime/status/1512598559769702406 voices = [ # DISNEY VOICES @@ -74,4 +76,3 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper if ok_or_good == 1: # 1/10 chance of ok voice return random.choice(good_voices['ok']) return random.choice(good_voices['good']) # 9/10 chance of good voice - diff --git a/video_creation/background.py b/video_creation/background.py index f146ade..0a3e1ce 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -1,11 +1,11 @@ import random -from os import listdir, environ +from os import listdir, environ, remove from pathlib import Path from random import randrange -from pytube import YouTube -from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip + from moviepy.editor import VideoFileClip -from rich.progress import Progress +from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip +from yt_dlp import YoutubeDL from utils.console import print_step, print_substep @@ -30,27 +30,31 @@ def download_background(): background_options): # if there are any background videos not installed print_step("We need to download the backgnrounds videos. they are fairly large but it's only done once. 😎") print_substep("Downloading the backgrounds videos... please be patient 🙏 ") - with Progress() as progress: - download_task = progress.add_task("[green]Downloading...", total=2) - - for uri, filename, credit in background_options: - print_substep(f"Downloading {filename} from {uri}") - YouTube(uri).streams.filter(res="720p").first().download("assets/backgrounds", - filename=f"{credit}-{filename}") - progress.update(download_task, advance=1) + for uri, filename, credit in background_options: + filename = f"{credit}-{filename}" + ydl_opts = {'outtmpl': f'assets/backgrounds/_raw_{filename}', 'merge_output_format': 'mp4', } + with YoutubeDL(ydl_opts) as ydl: + ydl.download(uri) + videoclip = VideoFileClip(f"assets/backgrounds/{filename}") + new_clip = videoclip.without_audio() + new_clip.write_videofile(f"assets/backgrounds/{filename}") + remove(f'assets/backgrounds/_raw_{filename}') print_substep("Background videos downloaded successfully! 🎉", style="bold green") def chop_background_video(video_length): - print_step("Finding a spot in the backgrounds video to chop...✂️") + print_step("Finding a spot in the background video to chop...") choice = random.choice(listdir('assets/backgrounds')) environ["background_credit"] = choice.split('-')[0] - background = VideoFileClip(f"assets/backgrounds/{choice}") - start_time, end_time = get_start_and_end_times(video_length, background.duration) - ffmpeg_extract_subclip(f'assets/backgrounds/{choice}', start_time, end_time, - targetname="assets/temp/backgrounds.mp4", ) - print_substep("Background video chopped successfully! 🎉", style="bold green") + print_substep(choice) + ffmpeg_extract_subclip( + f"assets/backgrounds/{choice}", + start_time, + end_time, + targetname="assets/temp/background.mp4", + ) + print_substep("Background video chopped successfully!", style="bold green") diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index 2a417ad..0fdcbda 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -1,9 +1,9 @@ [ - { - "id": "v2kd2q", - "time": "1654128204", - "background_credit": "bbswitzer", - "reddit_title": "What movie do you absolutely love yet acknowledge is not a super wellmade movie", - "filename": "What movie do you absolutely l....mp4" - } -] \ No newline at end of file + { + "id": "v2kd2q", + "time": "1654128204", + "background_credit": "bbswitzer", + "reddit_title": "What movie do you absolutely love yet acknowledge is not a super wellmade movie", + "filename": "What movie do you absolutely l....mp4" + } +] diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 12ea28d..bcc3bb0 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -1,12 +1,13 @@ import json from os import getenv - -from playwright.sync_api import sync_playwright from pathlib import Path + +from playwright.sync_api import sync_playwright, ViewportSize from rich.progress import track from utils.console import print_step, print_substep + def download_screenshots_of_reddit_posts(reddit_object, screenshot_num): """Downloads screenshots of reddit posts as they are seen on the web. @@ -31,15 +32,15 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num): context.add_cookies(cookies) # Get the thread screenshot page = context.new_page() + page.set_viewport_size(ViewportSize(width=1920, height=1080)) page.goto(reddit_object["thread_url"]) if page.locator('[data-testid="content-gate"]').is_visible(): # This means the post is NSFW and requires to click the proceed button. if getenv("ALLOW_NSFW").casefold() == "false": print_substep("NSFW Post Detected. Skipping...") - from subprocess import call - call(["python", "main.py"]) - exit(1) + from main import main + main() print_substep("Post is NSFW. You are spicy... :fire:") page.locator('[data-testid="content-gate"] button').click() diff --git a/video_creation/voices.py b/video_creation/voices.py index 5f6797b..3815722 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -1,13 +1,11 @@ -from os import remove - -import sox from pathlib import Path +import sox from mutagen import MutagenError from mutagen.mp3 import MP3, HeaderNotFoundError -from utils.console import print_step, print_substep from rich.progress import track +from utils.console import print_step, print_substep from video_creation.TTSwrapper import TTTTSWrapper VIDEO_LENGTH: int = 40 # secs @@ -29,11 +27,11 @@ def save_text_to_mp3(reddit_obj): ttttsw.tts(reddit_obj["thread_title"], filename=f"assets/temp/mp3/title.mp3", random_speaker=True) try: length += MP3(f"assets/temp/mp3/title.mp3").info.length - except HeaderNotFoundError: - length = sox.file_info.duration(f"assets/temp/mp3/title.mp3") + except HeaderNotFoundError: # note to self AudioFileClip + length += sox.file_info.duration(f"assets/temp/mp3/title.mp3") com = 0 for comment in track((reddit_obj["comments"]), "Saving..."): - # ! Stop creating mp3 files if the length is greater than 50 seconds. This can be longer, but this is just a good_voices starting point + # ! Stop creating mp3 files if the length is greater than VIDEO_LENGTH seconds. This can be longer, but this is just a good_voices starting point if length > VIDEO_LENGTH: break @@ -49,8 +47,8 @@ def save_text_to_mp3(reddit_obj): print('would have removed' f"assets/temp/mp3/{com}.mp3" f"assets/temp/png/comment_{com}.png") - #remove(f"assets/temp/mp3/{com}.mp3") - #remove(f"assets/temp/png/comment_{com}.png")# todo might cause odd un-syncing + # remove(f"assets/temp/mp3/{com}.mp3") + # remove(f"assets/temp/png/comment_{com}.png")# todo might cause odd un-syncing print_substep("Saved Text to MP3 files Successfully.", style="bold green") # ! Return the index so we know how many screenshots of comments we need to make. From 293b34666a2d0f664c915498ebfa61e52ea7b17f Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 17:30:34 -0400 Subject: [PATCH 09/23] feat: added TFA auth chore: overhauled the video download system. feat: added progress bar and speed for video download fix: fixed the evil file not found error! feat: added a variable that allows you to make MULTIPLE videos not just one feat: added a standardized viewport size for the screenshot downloader notes: removed askreddit.py as it was not needed after subreddit.py redesign. closes #26 fixes #38 fixes #32 fixes #31 fixes #30 fixes #22 fixes #21 fixes #17 fixes #14 --- .env.template | 1 + reddit/subreddit.py | 17 ++++++++--------- video_creation/background.py | 14 ++++---------- video_creation/data/videos.json | 10 +--------- video_creation/final_video.py | 13 +++++++------ 5 files changed, 21 insertions(+), 34 deletions(-) diff --git a/.env.template b/.env.template index b9b8875..280b7c3 100644 --- a/.env.template +++ b/.env.template @@ -13,3 +13,4 @@ POST_ID="" THEME="LIGHT" # set to an int e.g. 1 or 29 and leave blank for once TIMES_TO_RUN="" +MAX_COMMENT_LENGTH="500" diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 21b2123..b6947d8 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -1,24 +1,23 @@ -import re - -from utils.console import print_step, print_substep -import praw import random -from dotenv import load_dotenv from os import getenv, environ +import praw + +from utils.console import print_step, print_substep from utils.videos import check_done + TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890') + def textify(text): return ''.join(filter(TEXT_WHITELIST.__contains__, text)) - def get_subreddit_threads(): """ Returns a list of threads from the AskReddit subreddit. """ - + global submission print_step("Getting subreddit threads...") content = {} @@ -50,8 +49,8 @@ def get_subreddit_threads(): threads = subreddit.hot(limit=25) submission = list(threads)[random.randrange(0, 25)] submission = check_done(submission) - if submission == None: - return get_subreddit_threads() # todo check + if submission is None: + return get_subreddit_threads() # submission already done. rerun print_substep(f"Video will be: {submission.title} :thumbsup:") print_substep( diff --git a/video_creation/background.py b/video_creation/background.py index 268c592..04c7446 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,7 +5,6 @@ from random import randrange from pytube import YouTube from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.editor import VideoFileClip -from rich.progress import Progress from utils.console import print_step, print_substep @@ -30,15 +29,10 @@ def download_background(): background_options): # if there are any background videos not installed print_step("We need to download the backgnrounds videos. they are fairly large but it's only done once. 😎") print_substep("Downloading the backgrounds videos... please be patient 🙏 ") - with Progress() as progress: - - download_task = progress.add_task("[green]Downloading...", total=2) - - for uri, filename, credit in background_options: - print_substep(f"Downloading {filename} from {uri}") - YouTube(uri).streams.filter(res="1080p").first().download("assets/backgrounds", - filename=f"{credit}-{filename}") - progress.update(download_task, advance=1) # todo remove + for uri, filename, credit in background_options: + print_substep(f"Downloading {filename} from {uri}") + YouTube(uri).streams.filter(res="1080p").first().download("assets/backgrounds", + filename=f"{credit}-{filename}") print_substep("Background videos downloaded successfully! 🎉", style="bold green") diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json index 0fdcbda..fe51488 100644 --- a/video_creation/data/videos.json +++ b/video_creation/data/videos.json @@ -1,9 +1 @@ -[ - { - "id": "v2kd2q", - "time": "1654128204", - "background_credit": "bbswitzer", - "reddit_title": "What movie do you absolutely love yet acknowledge is not a super wellmade movie", - "filename": "What movie do you absolutely l....mp4" - } -] +[] diff --git a/video_creation/final_video.py b/video_creation/final_video.py index 157b94b..e94dd9e 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -4,8 +4,9 @@ import time from os.path import exists from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips, CompositeAudioClip, CompositeVideoClip -from moviepy.video import io +from moviepy.video.io import ffmpeg_tools +from reddit import subreddit from utils.cleanup import cleanup from utils.console import print_step, print_substep @@ -18,7 +19,7 @@ def make_final_video(number_of_clips, length): VideoFileClip.reH = lambda clip: clip.resize(width=H) background_clip = ( - VideoFileClip("assets/temp/backgrounds.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6, + VideoFileClip("assets/temp/background.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6, y2=1920)) # Gather all audio clips audio_clips = [] @@ -52,7 +53,7 @@ def make_final_video(number_of_clips, length): def save_data(): with open('./video_creation/data/videos.json', 'r+') as raw_vids: done_vids = json.load(raw_vids) - if str(os.getenv("VIDEO_ID")) in [video['id'] for video in done_vids]: + if str(subreddit.submission.id) in [video['id'] for video in done_vids]: return # video already done but was specified to continue anyway in the .env file payload = {"id": str(os.getenv("VIDEO_ID")), 'time': str(int(time.time())), "background_credit": str(os.getenv('background_credit')), @@ -66,9 +67,9 @@ def make_final_video(number_of_clips, length): print_substep('the results folder didn\'t exist so I made it') os.mkdir("./results") - final.write_videofile("temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k") - io.ffmpeg_tools.ffmpeg_extract_subclip("temp.mp4", 0, length, targetname=f"results/{filename}") - os.remove("temp.mp4") + final.write_videofile("assets/temp/temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k") + ffmpeg_tools.ffmpeg_extract_subclip("assets/temp/temp.mp4", 0, length, targetname=f"results/{filename}") + #os.remove("assets/temp/temp.mp4") print_step("Removing temporary files 🗑") cleanups = cleanup() From 917b20603ee351680a77c9fe5ffb52ff3cb1d7ed Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 17:31:02 -0400 Subject: [PATCH 10/23] removed useless line --- video_creation/background.py | 1 - 1 file changed, 1 deletion(-) diff --git a/video_creation/background.py b/video_creation/background.py index 04c7446..1fb17a0 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -5,7 +5,6 @@ from random import randrange from pytube import YouTube from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.editor import VideoFileClip - from utils.console import print_step, print_substep From b32e39f17da441569777689ce5a7bbf38c18d19e Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 17:33:00 -0400 Subject: [PATCH 11/23] last commit also fixed fixes #52 fixes #27 --- video_creation/background.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/video_creation/background.py b/video_creation/background.py index 1fb17a0..2d33c2e 100644 --- a/video_creation/background.py +++ b/video_creation/background.py @@ -16,8 +16,6 @@ def get_start_and_end_times(video_length, length_of_clip): def download_background(): """Downloads the backgrounds/s video from youtube. - Shoutout to: bbswitzer (https://www.youtube.com/watch?v=n_Dv4JMiwK8) - Shoutout to: Orbital Gameplay (https://www.youtube.com/watch?v=2X9QGY__0II) """ Path("./assets/backgrounds/").mkdir(parents=True, exist_ok=True) background_options = [ # uri , filename , credit From c6df98abeb9e402ec6ec604863e80da85ef924fc Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 17:48:43 -0400 Subject: [PATCH 12/23] added image transparency closes #39 --- .env.template | 2 ++ video_creation/final_video.py | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.env.template b/.env.template index 280b7c3..ae59b09 100644 --- a/.env.template +++ b/.env.template @@ -14,3 +14,5 @@ THEME="LIGHT" # set to an int e.g. 1 or 29 and leave blank for once TIMES_TO_RUN="" MAX_COMMENT_LENGTH="500" +# Range is 0 -> 1 recommended around 0.8-1 +OPACITY="" diff --git a/video_creation/final_video.py b/video_creation/final_video.py index e94dd9e..a41c862 100755 --- a/video_creation/final_video.py +++ b/video_creation/final_video.py @@ -3,7 +3,8 @@ import os import time from os.path import exists -from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips, CompositeAudioClip, CompositeVideoClip +from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips, \ + CompositeAudioClip, CompositeVideoClip from moviepy.video.io import ffmpeg_tools from reddit import subreddit @@ -17,10 +18,10 @@ def make_final_video(number_of_clips, length): print_step("Creating the final video 🎥") VideoFileClip.reW = lambda clip: clip.resize(width=W) VideoFileClip.reH = lambda clip: clip.resize(width=H) - + opacity = os.getenv('OPACITY') background_clip = ( VideoFileClip("assets/temp/background.mp4").without_audio().resize(height=H).crop(x1=1166.6, y1=0, x2=2246.6, - y2=1920)) + y2=1920)) # Gather all audio clips audio_clips = [] for i in range(0, number_of_clips): @@ -34,9 +35,10 @@ def make_final_video(number_of_clips, length): for i in range(0, number_of_clips): image_clips.append( ImageClip(f"assets/temp/png/comment_{i}.png").set_duration(audio_clips[i + 1].duration).set_position( - "center").resize(width=W - 100), ) + "center").resize(width=W - 100).set_opacity(float(opacity)), ) image_clips.insert(0, ImageClip(f"assets/temp/png/title.png").set_duration(audio_clips[0].duration).set_position( - "center").resize(width=W - 100), ) + "center").resize(width=W - 100).set_opacity(float(opacity)), + ) image_concat = concatenate_videoclips(image_clips).set_position(("center", "center")) image_concat.audio = audio_composite final = CompositeVideoClip([background_clip, image_concat]) @@ -69,7 +71,7 @@ def make_final_video(number_of_clips, length): final.write_videofile("assets/temp/temp.mp4", fps=30, audio_codec="aac", audio_bitrate="192k") ffmpeg_tools.ffmpeg_extract_subclip("assets/temp/temp.mp4", 0, length, targetname=f"results/{filename}") - #os.remove("assets/temp/temp.mp4") + # os.remove("assets/temp/temp.mp4") print_step("Removing temporary files 🗑") cleanups = cleanup() From e678d3e5ca5a98f593845fc2dada93ba69166ecd Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 18:03:54 -0400 Subject: [PATCH 13/23] adds voice config closes #28 --- .env.template | 4 +++ video_creation/TTSwrapper.py | 49 ++++++++++++++++++++---------------- video_creation/voices.py | 2 +- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/.env.template b/.env.template index ae59b09..6b82028 100644 --- a/.env.template +++ b/.env.template @@ -16,3 +16,7 @@ TIMES_TO_RUN="" MAX_COMMENT_LENGTH="500" # Range is 0 -> 1 recommended around 0.8-1 OPACITY="" + +# see TTSwrapper.py for all valid options +VOICE="en_us_001" # e.g. en_us_002 + diff --git a/video_creation/TTSwrapper.py b/video_creation/TTSwrapper.py index 6fa9d97..b2e4447 100644 --- a/video_creation/TTSwrapper.py +++ b/video_creation/TTSwrapper.py @@ -1,9 +1,13 @@ -import requests, base64, random, os import re + +import base64 +import os +import random +import requests from moviepy.editor import AudioFileClip, concatenate_audioclips, CompositeAudioClip # https://twitter.com/scanlime/status/1512598559769702406 -voices = [ # DISNEY VOICES +nonhuman = [ # DISNEY VOICES 'en_us_ghostface', # Ghost Face 'en_us_chewbacca', # Chewbacca 'en_us_c3po', # C3PO @@ -12,18 +16,20 @@ voices = [ # DISNEY VOICES 'en_us_rocket', # Rocket # ENGLISH VOICES - 'en_au_001', # English AU - Female - 'en_au_002', # English AU - Male - 'en_uk_001', # English UK - Male 1 - 'en_uk_003', # English UK - Male 2 - 'en_us_001', # English US - Female (Int. 1) - 'en_us_002', # English US - Female (Int. 2) - 'en_us_006', # English US - Male 1 - 'en_us_007', # English US - Male 2 - 'en_us_009', # English US - Male 3 - 'en_us_010', # English US - Male 4 +] +human = ['en_au_001', # English AU - Female + 'en_au_002', # English AU - Male + 'en_uk_001', # English UK - Male 1 + 'en_uk_003', # English UK - Male 2 + 'en_us_001', # English US - Female (Int. 1) + 'en_us_002', # English US - Female (Int. 2) + 'en_us_006', # English US - Male 1 + 'en_us_007', # English US - Male 2 + 'en_us_009', # English US - Male 3 + 'en_us_010'] +voices = nonhuman + human - # EUROPE VOICES +noneng = [ 'fr_001', # French - Male 1 'fr_002', # French - Male 2 'de_001', # German - Female @@ -47,8 +53,10 @@ voices = [ # DISNEY VOICES 'kr_003', # Korean - Female 'kr_004', # Korean - Male 2 ] -good_voices = {'good': ['en_us_002', 'en_us_006'], - 'ok': ['en_au_002', 'en_uk_001']} # less en_us_stormtrooper more less en_us_rocket en_us_ghostface + + +# good_voices = {'good': ['en_us_002', 'en_us_006'], +# 'ok': ['en_au_002', 'en_uk_001']} # less en_us_stormtrooper more less en_us_rocket en_us_ghostface class TTTTSWrapper: # TikTok Text-to-Speech Wrapper @@ -58,9 +66,9 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper def tts(self, req_text: str = "TikTok Text To Speech", filename: str = 'title.mp3', random_speaker: bool = False): req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and") - voice = self.randomvoice() if random_speaker else 'en_us_002' + voice = self.randomvoice() if random_speaker else (os.getenv('VOICE') or random.choice(human)) - chunks = [m.group().strip() for m in re.finditer(r' *((.{0,200})(\.|.$))',req_text)] + chunks = [m.group().strip() for m in re.finditer(r' *((.{0,200})(\.|.$))', req_text)] audio_clips = [] @@ -75,7 +83,7 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper audio_clips.append(AudioFileClip(f"{filename}-{chunkId}")) - chunkId = chunkId+1; + chunkId = chunkId + 1 audio_concat = concatenate_audioclips(audio_clips) audio_composite = CompositeAudioClip([audio_concat]) @@ -85,6 +93,5 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper def randomvoice(): ok_or_good = random.randrange(1, 10) if ok_or_good == 1: # 1/10 chance of ok voice - return random.choice(good_voices['ok']) - return random.choice(good_voices['good']) # 9/10 chance of good voice - + return random.choice(voices) + return random.choice(human) # 9/10 chance of good voice diff --git a/video_creation/voices.py b/video_creation/voices.py index 3815722..2fa2f88 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -24,7 +24,7 @@ def save_text_to_mp3(reddit_obj): Path("assets/temp/mp3").mkdir(parents=True, exist_ok=True) ttttsw = TTTTSWrapper() # tiktok text to speech wrapper - ttttsw.tts(reddit_obj["thread_title"], filename=f"assets/temp/mp3/title.mp3", random_speaker=True) + ttttsw.tts(reddit_obj["thread_title"], filename=f"assets/temp/mp3/title.mp3", random_speaker=False) try: length += MP3(f"assets/temp/mp3/title.mp3").info.length except HeaderNotFoundError: # note to self AudioFileClip From 45531df82316e186933f1eaad43952fe4260c8f8 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 18:09:21 -0400 Subject: [PATCH 14/23] sanitize text. closes #59 --- utils/voice.py | 16 ++++++++++++++++ video_creation/voices.py | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 utils/voice.py diff --git a/utils/voice.py b/utils/voice.py new file mode 100644 index 0000000..7661981 --- /dev/null +++ b/utils/voice.py @@ -0,0 +1,16 @@ +import re + + +def sanitize_text(text): + """ + Sanitizes the text for tts. + What gets removed: + - following characters`^_~@!&;#:-%“”‘"%*/{}[]()\|<>?=+` + """ + + # note: not removing apostrophes + regex_expr = r"\s['|’]|['|’]\s|[\^_~@!&;#:\-%“”‘\"%\*/{}\[\]\(\)\\|<>=+]" + result = re.sub(regex_expr, " ", text) + + # remove extra whitespace + return " ".join(result.split()) diff --git a/video_creation/voices.py b/video_creation/voices.py index 2fa2f88..a7822dc 100644 --- a/video_creation/voices.py +++ b/video_creation/voices.py @@ -6,6 +6,7 @@ from mutagen.mp3 import MP3, HeaderNotFoundError from rich.progress import track from utils.console import print_step, print_substep +from utils.voice import sanitize_text from video_creation.TTSwrapper import TTTTSWrapper VIDEO_LENGTH: int = 40 # secs @@ -24,7 +25,7 @@ def save_text_to_mp3(reddit_obj): Path("assets/temp/mp3").mkdir(parents=True, exist_ok=True) ttttsw = TTTTSWrapper() # tiktok text to speech wrapper - ttttsw.tts(reddit_obj["thread_title"], filename=f"assets/temp/mp3/title.mp3", random_speaker=False) + ttttsw.tts(sanitize_text(reddit_obj["thread_title"]), filename=f"assets/temp/mp3/title.mp3", random_speaker=False) try: length += MP3(f"assets/temp/mp3/title.mp3").info.length except HeaderNotFoundError: # note to self AudioFileClip @@ -35,7 +36,7 @@ def save_text_to_mp3(reddit_obj): if length > VIDEO_LENGTH: break - ttttsw.tts(comment["comment_body"], filename=f"assets/temp/mp3/{com}.mp3", random_speaker=False) + ttttsw.tts(sanitize_text(comment["comment_body"]), filename=f"assets/temp/mp3/{com}.mp3", random_speaker=False) try: length += MP3(f"assets/temp/mp3/{com}.mp3").info.length com += 1 From cb3f825014b50a2c5e1f9e41b7d2ae8f3da2f388 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 18:11:52 -0400 Subject: [PATCH 15/23] updated voice.py with uri removal too --- utils/voice.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/voice.py b/utils/voice.py index 7661981..e6f3989 100644 --- a/utils/voice.py +++ b/utils/voice.py @@ -4,13 +4,18 @@ import re def sanitize_text(text): """ Sanitizes the text for tts. - What gets removed: + What gets removed: - following characters`^_~@!&;#:-%“”‘"%*/{}[]()\|<>?=+` + - any http or https links """ + # remove any urls from the text + regex_urls = r"((http|https)://[^\s]+)" + result = re.sub(regex_urls, " ", text) + # note: not removing apostrophes regex_expr = r"\s['|’]|['|’]\s|[\^_~@!&;#:\-%“”‘\"%\*/{}\[\]\(\)\\|<>=+]" - result = re.sub(regex_expr, " ", text) + result = re.sub(regex_expr, " ", result) # remove extra whitespace return " ".join(result.split()) From b555b9ce4e55368dbfe4f8fea71a6fc33d040ad0 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 18:16:39 -0400 Subject: [PATCH 16/23] improved voice.py uri remover --- utils/voice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/voice.py b/utils/voice.py index e6f3989..13633da 100644 --- a/utils/voice.py +++ b/utils/voice.py @@ -10,7 +10,8 @@ def sanitize_text(text): """ # remove any urls from the text - regex_urls = r"((http|https)://[^\s]+)" + regex_urls = r'((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:@\-_=#])*' + result = re.sub(regex_urls, " ", text) # note: not removing apostrophes From 4d4cfdcd9826a31625a434fdfc5cd17a2f61d328 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 6 Jun 2022 18:19:55 -0400 Subject: [PATCH 17/23] stickied comments will never be used again see https://github.com/elebumm/RedditVideoMakerBot/pull/290 --- reddit/subreddit.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/reddit/subreddit.py b/reddit/subreddit.py index b6947d8..30ff8bd 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -65,10 +65,11 @@ def get_subreddit_threads(): content["comments"] = [] for top_level_comment in submission.comments: - if len(top_level_comment.body) <= int(environ["MAX_COMMENT_LENGTH"]): - content["comments"].append( - {"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink, - "comment_id": top_level_comment.id, }) + if not top_level_comment.stickied: + if len(top_level_comment.body) <= int(environ["MAX_COMMENT_LENGTH"]): + content["comments"].append( + {"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink, + "comment_id": top_level_comment.id, }) except AttributeError as e: pass print_substep("Received subreddit threads Successfully.", style="bold green") From 45956c409ae397199498896a38b93bd15c52c4bc Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 7 Jun 2022 09:45:26 -0400 Subject: [PATCH 18/23] tried to implement smth --- video_creation/TTSwrapper.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/video_creation/TTSwrapper.py b/video_creation/TTSwrapper.py index b2e4447..f5ae5e5 100644 --- a/video_creation/TTSwrapper.py +++ b/video_creation/TTSwrapper.py @@ -5,7 +5,9 @@ import os import random import requests from moviepy.editor import AudioFileClip, concatenate_audioclips, CompositeAudioClip - +#from profanity_filter import ProfanityFilter +#pf = ProfanityFilter() +# Code by @JasonLovesDoggo # https://twitter.com/scanlime/status/1512598559769702406 nonhuman = [ # DISNEY VOICES 'en_us_ghostface', # Ghost Face @@ -63,9 +65,11 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper def __init__(self): self.URI_BASE = 'https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker=' - def tts(self, req_text: str = "TikTok Text To Speech", filename: str = 'title.mp3', random_speaker: bool = False): + def tts(self, req_text: str = "TikTok Text To Speech", filename: str = 'title.mp3', random_speaker: bool = False, censer=False): req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and") - + if censer: + #req_text = pf.censor(req_text) + pass voice = self.randomvoice() if random_speaker else (os.getenv('VOICE') or random.choice(human)) chunks = [m.group().strip() for m in re.finditer(r' *((.{0,200})(\.|.$))', req_text)] From ec4729bd0673f8521d0ab119c038607fef8d13a8 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 7 Jun 2022 10:06:25 -0400 Subject: [PATCH 19/23] removed videos.json from git updatin --- main.py | 5 ++++- video_creation/data/.gitignore | 1 + video_creation/data/videos.json | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 video_creation/data/.gitignore delete mode 100644 video_creation/data/videos.json diff --git a/main.py b/main.py index 0b35c06..2ebb907 100755 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from dotenv import load_dotenv from reddit.subreddit import get_subreddit_threads from utils.cleanup import cleanup -from utils.console import print_markdown +from utils.console import print_markdown, print_step from video_creation.background import download_background, chop_background_video from video_creation.final_video import make_final_video from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts @@ -36,6 +36,9 @@ def main(): def run_many(times): for x in range(times): + print_step( + f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration') # correct 1st 2nd 3rd 4th 5th.... + os.system('cls' if os.name == 'nt' else 'clear') # clear terminal main() diff --git a/video_creation/data/.gitignore b/video_creation/data/.gitignore new file mode 100644 index 0000000..f96efd4 --- /dev/null +++ b/video_creation/data/.gitignore @@ -0,0 +1 @@ +videos.json diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json deleted file mode 100644 index fe51488..0000000 --- a/video_creation/data/videos.json +++ /dev/null @@ -1 +0,0 @@ -[] From 2b1f7183d40e8fd6779a85bdb234229bdc8d774f Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 7 Jun 2022 10:28:40 -0400 Subject: [PATCH 20/23] closes #61 fix: perm removed praw async error --- .env.template | 2 +- main.py | 13 ++++++------- reddit/subreddit.py | 2 +- video_creation/data/.gitignore | 1 + 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.env.template b/.env.template index 6b82028..a99bcc9 100644 --- a/.env.template +++ b/.env.template @@ -14,7 +14,7 @@ THEME="LIGHT" # set to an int e.g. 1 or 29 and leave blank for once TIMES_TO_RUN="" MAX_COMMENT_LENGTH="500" -# Range is 0 -> 1 recommended around 0.8-1 +# Range is 0 -> 1 recommended around 0.8-0.9 OPACITY="" # see TTSwrapper.py for all valid options diff --git a/main.py b/main.py index 2ebb907..8fc880c 100755 --- a/main.py +++ b/main.py @@ -1,8 +1,6 @@ -import os import time - from dotenv import load_dotenv - +from os import system, getenv, name from reddit.subreddit import get_subreddit_threads from utils.cleanup import cleanup from utils.console import print_markdown, print_step @@ -36,16 +34,17 @@ def main(): def run_many(times): for x in range(times): + x = x + 1 print_step( - f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration') # correct 1st 2nd 3rd 4th 5th.... - os.system('cls' if os.name == 'nt' else 'clear') # clear terminal + f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration of {times}') # correct 1st 2nd 3rd 4th 5th.... main() + system('cls' if name == 'nt' else 'clear') # clear terminal if __name__ == '__main__': try: - if os.getenv('TIMES_TO_RUN'): - run_many(int(os.getenv('TIMES_TO_RUN'))) + if getenv('TIMES_TO_RUN'): + run_many(int(getenv('TIMES_TO_RUN'))) else: main() except KeyboardInterrupt: diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 30ff8bd..6eb4639 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -31,7 +31,7 @@ def get_subreddit_threads(): passkey = getenv("REDDIT_PASSWORD") reddit = praw.Reddit(client_id=getenv("REDDIT_CLIENT_ID"), client_secret=getenv("REDDIT_CLIENT_SECRET"), user_agent="Accessing Reddit threads", username=getenv("REDDIT_USERNAME"), - passkey=passkey, ) + passkey=passkey, check_for_async=False,) """ Ask user for subreddit input """ diff --git a/video_creation/data/.gitignore b/video_creation/data/.gitignore index f96efd4..a8731e5 100644 --- a/video_creation/data/.gitignore +++ b/video_creation/data/.gitignore @@ -1 +1,2 @@ videos.json + #todo add videos on github From d1f27337c1ef03619524dc28d016636d1106efa0 Mon Sep 17 00:00:00 2001 From: Jason <66544866+JasonLovesDoggo@users.noreply.github.com> Date: Tue, 7 Jun 2022 10:29:21 -0400 Subject: [PATCH 21/23] Create videos.json gitignore fix --- video_creation/data/videos.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 video_creation/data/videos.json diff --git a/video_creation/data/videos.json b/video_creation/data/videos.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/video_creation/data/videos.json @@ -0,0 +1 @@ +[] From ad2a043aadcc33ddbc2d9020bf5c99dd010e249c Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 7 Jun 2022 10:34:28 -0400 Subject: [PATCH 22/23] added giant banner modified version of https://github.com/elebumm/RedditVideoMakerBot/pull/354/commits/c24234aa5362f129382e38adbd1a50f591ef1d56 --- main.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main.py b/main.py index 8fc880c..5168aa3 100755 --- a/main.py +++ b/main.py @@ -9,6 +9,15 @@ from video_creation.final_video import make_final_video from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.voices import save_text_to_mp3 +banner = ''' +██████╗ ███████╗██████╗ ██████╗ ██╗████████╗ ██╗ ██╗██╗██████╗ ███████╗ ██████╗ ███╗ ███╗ █████╗ ██╗ ██╗███████╗██████╗ +██╔══██╗██╔════╝██╔══██╗██╔══██╗██║╚══██╔══╝ ██║ ██║██║██╔══██╗██╔════╝██╔═══██╗ ████╗ ████║██╔══██╗██║ ██╔╝██╔════╝██╔══██╗ +██████╔╝█████╗ ██║ ██║██║ ██║██║ ██║ ██║ ██║██║██║ ██║█████╗ ██║ ██║ ██╔████╔██║███████║█████╔╝ █████╗ ██████╔╝ +██╔══██╗██╔══╝ ██║ ██║██║ ██║██║ ██║ ╚██╗ ██╔╝██║██║ ██║██╔══╝ ██║ ██║ ██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗ +██║ ██║███████╗██████╔╝██████╔╝██║ ██║ ╚████╔╝ ██║██████╔╝███████╗╚██████╔╝ ██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗██║ ██║ +╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ +''' +print(banner) load_dotenv() # base code by elebumm print_markdown( From 9ba4500c27e54ca517c7ffcee92313dd28bace65 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 7 Jun 2022 10:57:49 -0400 Subject: [PATCH 23/23] added stats --- main.py | 6 ++++-- reddit/subreddit.py | 11 +++++++---- video_creation/screenshot_downloader.py | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 5168aa3..c3d2f83 100755 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ import time +from subprocess import Popen + from dotenv import load_dotenv -from os import system, getenv, name +from os import getenv, name from reddit.subreddit import get_subreddit_threads from utils.cleanup import cleanup from utils.console import print_markdown, print_step @@ -47,7 +49,7 @@ def run_many(times): print_step( f'on the {x}{("st" if x == 1 else ("nd" if x == 2 else ("rd" if x == 3 else "th")))} iteration of {times}') # correct 1st 2nd 3rd 4th 5th.... main() - system('cls' if name == 'nt' else 'clear') # clear terminal + Popen('cls' if name == 'nt' else 'clear', shell=True).wait() if __name__ == '__main__': diff --git a/reddit/subreddit.py b/reddit/subreddit.py index 6eb4639..e6f5274 100644 --- a/reddit/subreddit.py +++ b/reddit/subreddit.py @@ -51,11 +51,14 @@ def get_subreddit_threads(): submission = check_done(submission) if submission is None: return get_subreddit_threads() # submission already done. rerun - print_substep(f"Video will be: {submission.title} :thumbsup:") - - print_substep( - f'subreddit thread is: {submission.title}\n(if you dont like this, you can change it by exiting and rerunning the program)') + upvotes = submission.score + ratio = submission.upvote_ratio * 100 + num_comments = submission.num_comments + print_substep(f"Video will be: {submission.title} :thumbsup:", style='bold green') + print_substep(f"Thread has " + str(upvotes) + " upvotes", style='bold blue') + print_substep(f"Thread has a upvote ratio of " + str(ratio) + "%", style='bold blue') + print_substep(f"Thread has " + str(num_comments) + " comments", style='bold blue') environ["VIDEO_TITLE"] = str(textify(submission.title)) # todo use global instend of env vars environ["VIDEO_ID"] = str(textify(submission.id)) try: diff --git a/video_creation/screenshot_downloader.py b/video_creation/screenshot_downloader.py index 6c910b8..6be00fc 100644 --- a/video_creation/screenshot_downloader.py +++ b/video_creation/screenshot_downloader.py @@ -2,6 +2,7 @@ import json from os import getenv from pathlib import Path +from playwright.async_api import async_playwright from playwright.sync_api import sync_playwright, ViewportSize from rich.progress import track