Merge remote-tracking branch 'origin/master'

# Conflicts:
#	.env.template
#	reddit/subreddit.py
#	video_creation/TTSwrapper.py
#	video_creation/background.py
pull/418/head
Jason 3 years ago
commit 25c198dff3

@ -24,11 +24,6 @@ def main():
def get_obj(): def get_obj():
reddit_obj = get_subreddit_threads() reddit_obj = get_subreddit_threads()
for comment in (reddit_obj["comments"]):
if len(comment) > 250:
print(comment)
reddit_obj["comments"].remove(comment)
print(reddit_obj["comments"])
return reddit_obj return reddit_obj
reddit_object = get_obj() reddit_object = get_obj()
@ -36,7 +31,7 @@ def main():
download_screenshots_of_reddit_posts(reddit_object, number_of_comments) download_screenshots_of_reddit_posts(reddit_object, number_of_comments)
download_background() download_background()
chop_background_video(length) chop_background_video(length)
final_video = make_final_video(number_of_comments) final_video = make_final_video(number_of_comments, length)
def run_many(times): def run_many(times):

@ -1,24 +1,26 @@
import random import re
from os import getenv, environ
from utils.console import print_step, print_substep
import praw import praw
import random
from dotenv import load_dotenv
from os import getenv, environ
from utils.console import print_step, print_substep
from utils.videos import check_done from utils.videos import check_done
TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890') TEXT_WHITELIST = set('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890')
def textify(text): def textify(text):
return ''.join(filter(TEXT_WHITELIST.__contains__, text)) return ''.join(filter(TEXT_WHITELIST.__contains__, text))
def get_subreddit_threads(): def get_subreddit_threads():
""" """
Returns a list of threads from the AskReddit subreddit. Returns a list of threads from the AskReddit subreddit.
""" """
print_step("Getting subreddit threads...") print_step("Getting subreddit threads...")
content = {} content = {}
if getenv("REDDIT_2FA").casefold() == "yes": if getenv("REDDIT_2FA").casefold() == "yes":
print("\nEnter your two-factor authentication code from your authenticator app.\n") print("\nEnter your two-factor authentication code from your authenticator app.\n")
@ -29,29 +31,32 @@ def get_subreddit_threads():
else: else:
passkey = getenv("REDDIT_PASSWORD") passkey = getenv("REDDIT_PASSWORD")
reddit = praw.Reddit(client_id=getenv("REDDIT_CLIENT_ID"), client_secret=getenv("REDDIT_CLIENT_SECRET"), reddit = praw.Reddit(client_id=getenv("REDDIT_CLIENT_ID"), client_secret=getenv("REDDIT_CLIENT_SECRET"),
user_agent="Accessing AskReddit threads", username=getenv("REDDIT_USERNAME"), user_agent="Accessing Reddit threads", username=getenv("REDDIT_USERNAME"),
passkey=passkey, ) passkey=passkey, )
""" """
Ask user for subreddit input 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'): if getenv('POST_ID'):
submission = reddit.submission(id=getenv('POST_ID')) submission = reddit.submission(id=getenv('POST_ID'))
else: 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) threads = subreddit.hot(limit=25)
submission = list(threads)[random.randrange(0, 25)] submission = list(threads)[random.randrange(0, 25)]
submission = check_done(submission) submission = check_done(submission)
if submission == None:
return get_subreddit_threads() # todo check
print_substep(f"Video will be: {submission.title} :thumbsup:") 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)) # todo use global instend of env vars environ["VIDEO_TITLE"] = str(textify(submission.title)) # todo use global instend of env vars
environ["VIDEO_ID"] = str(textify(submission.id)) environ["VIDEO_ID"] = str(textify(submission.id))
try: try:
@ -61,11 +66,11 @@ def get_subreddit_threads():
content["comments"] = [] content["comments"] = []
for top_level_comment in submission.comments: for top_level_comment in submission.comments:
content["comments"].append( if len(top_level_comment.body) <= int(environ["MAX_COMMENT_LENGTH"]):
{"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink, content["comments"].append(
"comment_id": top_level_comment.id, }) {"comment_body": top_level_comment.body, "comment_url": top_level_comment.permalink,
"comment_id": top_level_comment.id, })
except AttributeError as e: except AttributeError as e:
pass pass
print_substep("Received subreddit thread Successfully.", style="bold green") print_substep("Received subreddit threads Successfully.", style="bold green")
return content return content

@ -16,6 +16,5 @@ def check_done(redditobj): # don't set this to be run anyplace that isn't subre
'You already have done this video but since it was declared specifically in the .env file the program will continue') 'You already have done this video but since it was declared specifically in the .env file the program will continue')
return redditobj return redditobj
print_step('Getting new post as the current one has already been done') print_step('Getting new post as the current one has already been done')
from reddit.subreddit import get_subreddit_threads return None
return get_subreddit_threads() # recursive func
return redditobj return redditobj

@ -1,6 +1,6 @@
import base64 import requests, base64, random, os
import random import re
import requests from moviepy.editor import AudioFileClip, concatenate_audioclips, CompositeAudioClip
# https://twitter.com/scanlime/status/1512598559769702406 # https://twitter.com/scanlime/status/1512598559769702406
voices = [ # DISNEY VOICES voices = [ # DISNEY VOICES
@ -56,19 +56,30 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper
self.URI_BASE = 'https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker=' 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):
if len(req_text) > 299: req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and")
return ValueError("Text too long must be under 299 characters")
if random_speaker:
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 'en_us_002'
r = requests.post(f"{self.URI_BASE}{voice}&req_text={req_text}&speaker_map_type=0")
vstr = [r.json()["data"]["v_str"]][0] chunks = [m.group().strip() for m in re.finditer(r' *((.{0,200})(\.|.$))',req_text)]
audio_clips = []
chunkId = 0
for chunk in chunks:
r = requests.post(f"{self.URI_BASE}{voice}&req_text={chunk}&speaker_map_type=0")
vstr = [r.json()["data"]["v_str"]][0]
b64d = base64.b64decode(vstr)
b64d = base64.b64decode(vstr) with open(f"{filename}-{chunkId}", "wb") as out:
out.write(b64d)
with open(filename, "wb") as out: audio_clips.append(AudioFileClip(f"{filename}-{chunkId}"))
out.write(b64d)
chunkId = chunkId+1;
audio_concat = concatenate_audioclips(audio_clips)
audio_composite = CompositeAudioClip([audio_concat])
audio_composite.write_audiofile(filename, 44100, 2, 2000, None)
@staticmethod @staticmethod
def randomvoice(): def randomvoice():
@ -76,3 +87,4 @@ class TTTTSWrapper: # TikTok Text-to-Speech Wrapper
if ok_or_good == 1: # 1/10 chance of ok voice if ok_or_good == 1: # 1/10 chance of ok voice
return random.choice(good_voices['ok']) return random.choice(good_voices['ok'])
return random.choice(good_voices['good']) # 9/10 chance of good voice return random.choice(good_voices['good']) # 9/10 chance of good voice

@ -1,11 +1,11 @@
import random import random
from os import listdir, environ, remove from os import listdir, environ
from pathlib import Path from pathlib import Path
from random import randrange from random import randrange
from pytube import YouTube
from moviepy.editor import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from yt_dlp import YoutubeDL from moviepy.editor import VideoFileClip
from rich.progress import Progress
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
@ -30,31 +30,27 @@ def download_background():
background_options): # if there are any background videos not installed 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_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 🙏 ") print_substep("Downloading the backgrounds videos... please be patient 🙏 ")
with Progress() as progress:
for uri, filename, credit in background_options: download_task = progress.add_task("[green]Downloading...", total=2)
filename = f"{credit}-{filename}"
ydl_opts = {'outtmpl': f'assets/backgrounds/_raw_{filename}', 'merge_output_format': 'mp4', } for uri, filename, credit in background_options:
with YoutubeDL(ydl_opts) as ydl: print_substep(f"Downloading {filename} from {uri}")
ydl.download(uri) YouTube(uri).streams.filter(res="1080p").first().download("assets/backgrounds",
videoclip = VideoFileClip(f"assets/backgrounds/{filename}") filename=f"{credit}-{filename}")
new_clip = videoclip.without_audio() progress.update(download_task, advance=1) # todo remove
new_clip.write_videofile(f"assets/backgrounds/{filename}")
remove(f'assets/backgrounds/_raw_{filename}')
print_substep("Background videos downloaded successfully! 🎉", style="bold green") print_substep("Background videos downloaded successfully! 🎉", style="bold green")
def chop_background_video(video_length): def chop_background_video(video_length):
print_step("Finding a spot in the background video to chop...") print_step("Finding a spot in the backgrounds video to chop...✂️")
choice = random.choice(listdir('assets/backgrounds')) choice = random.choice(listdir('assets/backgrounds'))
environ["background_credit"] = choice.split('-')[0] environ["background_credit"] = choice.split('-')[0]
background = VideoFileClip(f"assets/backgrounds/{choice}") background = VideoFileClip(f"assets/backgrounds/{choice}")
start_time, end_time = get_start_and_end_times(video_length, background.duration) start_time, end_time = get_start_and_end_times(video_length, background.duration)
print_substep(choice) ffmpeg_extract_subclip(f'assets/backgrounds/{choice}', start_time, end_time,
ffmpeg_extract_subclip( targetname="assets/temp/background.mp4", )
f"assets/backgrounds/{choice}", print_substep("Background video chopped successfully! 🎉", style="bold green")
start_time,
end_time,
targetname="assets/temp/background.mp4",
)
print_substep("Background video chopped successfully!", style="bold green")

@ -4,5 +4,11 @@
"value": "eyJwcmVmcyI6eyJ0b3BDb250ZW50RGlzbWlzc2FsVGltZSI6MCwiZ2xvYmFsVGhlbWUiOiJSRURESVQiLCJuaWdodG1vZGUiOnRydWUsImNvbGxhcHNlZFRyYXlTZWN0aW9ucyI6eyJmYXZvcml0ZXMiOmZhbHNlLCJtdWx0aXMiOmZhbHNlLCJtb2RlcmF0aW5nIjpmYWxzZSwic3Vic2NyaXB0aW9ucyI6ZmFsc2UsInByb2ZpbGVzIjpmYWxzZX0sInRvcENvbnRlbnRUaW1lc0Rpc21pc3NlZCI6MH19", "value": "eyJwcmVmcyI6eyJ0b3BDb250ZW50RGlzbWlzc2FsVGltZSI6MCwiZ2xvYmFsVGhlbWUiOiJSRURESVQiLCJuaWdodG1vZGUiOnRydWUsImNvbGxhcHNlZFRyYXlTZWN0aW9ucyI6eyJmYXZvcml0ZXMiOmZhbHNlLCJtdWx0aXMiOmZhbHNlLCJtb2RlcmF0aW5nIjpmYWxzZSwic3Vic2NyaXB0aW9ucyI6ZmFsc2UsInByb2ZpbGVzIjpmYWxzZX0sInRvcENvbnRlbnRUaW1lc0Rpc21pc3NlZCI6MH19",
"domain": ".reddit.com", "domain": ".reddit.com",
"path": "/" "path": "/"
},
{
"name": "eu_cookie",
"value": "{%22opted%22:true%2C%22nonessential%22:false}",
"domain": ".reddit.com",
"path": "/"
} }
] ]

@ -0,0 +1,8 @@
[
{
"name": "eu_cookie",
"value": "{%22opted%22:true%2C%22nonessential%22:false}",
"domain": ".reddit.com",
"path": "/"
}
]

@ -3,8 +3,8 @@ import os
import time import time
from os.path import exists from os.path import exists
from moviepy.editor import (VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips, from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips, concatenate_audioclips, CompositeAudioClip, CompositeVideoClip
CompositeAudioClip, CompositeVideoClip) from moviepy.video import io
from utils.cleanup import cleanup from utils.cleanup import cleanup
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
@ -12,7 +12,7 @@ from utils.console import print_step, print_substep
W, H = 1080, 1920 W, H = 1080, 1920
def make_final_video(number_of_clips): def make_final_video(number_of_clips, length):
print_step("Creating the final video 🎥") print_step("Creating the final video 🎥")
VideoFileClip.reW = lambda clip: clip.resize(width=W) VideoFileClip.reW = lambda clip: clip.resize(width=W)
VideoFileClip.reH = lambda clip: clip.resize(width=H) VideoFileClip.reH = lambda clip: clip.resize(width=H)
@ -65,7 +65,11 @@ def make_final_video(number_of_clips):
if not exists('./results'): if not exists('./results'):
print_substep('the results folder didn\'t exist so I made it') print_substep('the results folder didn\'t exist so I made it')
os.mkdir("./results") os.mkdir("./results")
final.write_videofile(f"results/{filename}", fps=30, audio_codec="aac", audio_bitrate="192k")
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")
print_step("Removing temporary files 🗑") print_step("Removing temporary files 🗑")
cleanups = cleanup() cleanups = cleanup()
print_substep(f"Removed {cleanups} temporary files 🗑") print_substep(f"Removed {cleanups} temporary files 🗑")

@ -27,9 +27,11 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num):
context = browser.new_context() context = browser.new_context()
if getenv("THEME").upper() == "DARK": if getenv("THEME").upper() == "DARK":
cookie_file = open('./video_creation/data/cookie.json') cookie_file = open('./video_creation/data/cookie-dark-mode.json')
cookies = json.load(cookie_file) else:
context.add_cookies(cookies) cookie_file = open('./video_creation/data/cookie-light-mode.json')
cookies = json.load(cookie_file)
context.add_cookies(cookies)
# Get the thread screenshot # Get the thread screenshot
page = context.new_page() page = context.new_page()
page.set_viewport_size(ViewportSize(width=1920, height=1080)) page.set_viewport_size(ViewportSize(width=1920, height=1080))

Loading…
Cancel
Save