Merge remote-tracking branch 'origin/master'
# Conflicts: # .env.template # reddit/subreddit.py # video_creation/TTSwrapper.py # video_creation/background.py
This commit is contained in:
commit
25c198dff3
9 files changed
+97
-70
No files matched your search
@@ -24,11 +24,6 @@ def main():
|
||||
|
||||
def get_obj():
|
||||
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
|
||||
|
||||
reddit_object = get_obj()
|
||||
@@ -36,7 +31,7 @@ def main():
|
||||
download_screenshots_of_reddit_posts(reddit_object, number_of_comments)
|
||||
download_background()
|
||||
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):
|
||||
|
||||
+26
-21
@@ -1,24 +1,26 @@
|
||||
import random
|
||||
from os import getenv, environ
|
||||
|
||||
import praw
|
||||
import re
|
||||
|
||||
from utils.console import print_step, print_substep
|
||||
import praw
|
||||
import random
|
||||
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 = {}
|
||||
if getenv("REDDIT_2FA").casefold() == "yes":
|
||||
print("\nEnter your two-factor authentication code from your authenticator app.\n")
|
||||
@@ -29,29 +31,32 @@ def get_subreddit_threads():
|
||||
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"),
|
||||
user_agent="Accessing Reddit threads", username=getenv("REDDIT_USERNAME"),
|
||||
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)
|
||||
if submission == None:
|
||||
return get_subreddit_threads() # todo check
|
||||
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_ID"] = str(textify(submission.id))
|
||||
try:
|
||||
@@ -61,11 +66,11 @@ def get_subreddit_threads():
|
||||
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, })
|
||||
|
||||
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 thread Successfully.", style="bold green")
|
||||
print_substep("Received subreddit threads Successfully.", style="bold green")
|
||||
return content
|
||||
Regular → Executable
+1
-2
@@ -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')
|
||||
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
|
||||
return None
|
||||
return redditobj
|
||||
@@ -1,6 +1,6 @@
|
||||
import base64
|
||||
import random
|
||||
import requests
|
||||
import requests, base64, random, os
|
||||
import re
|
||||
from moviepy.editor import AudioFileClip, concatenate_audioclips, CompositeAudioClip
|
||||
|
||||
# https://twitter.com/scanlime/status/1512598559769702406
|
||||
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='
|
||||
|
||||
def tts(self, req_text: str = "TikTok Text To Speech", filename: str = 'title.mp3', random_speaker: bool = False):
|
||||
if len(req_text) > 299:
|
||||
return ValueError("Text too long must be under 299 characters")
|
||||
if random_speaker:
|
||||
req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and")
|
||||
req_text = req_text.replace("+", "plus").replace(" ", "+").replace("&", "and")
|
||||
|
||||
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)]
|
||||
|
||||
b64d = base64.b64decode(vstr)
|
||||
audio_clips = []
|
||||
|
||||
with open(filename, "wb") as out:
|
||||
out.write(b64d)
|
||||
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)
|
||||
|
||||
with open(f"{filename}-{chunkId}", "wb") as out:
|
||||
out.write(b64d)
|
||||
|
||||
audio_clips.append(AudioFileClip(f"{filename}-{chunkId}"))
|
||||
|
||||
chunkId = chunkId+1;
|
||||
|
||||
audio_concat = concatenate_audioclips(audio_clips)
|
||||
audio_composite = CompositeAudioClip([audio_concat])
|
||||
audio_composite.write_audiofile(filename, 44100, 2, 2000, None)
|
||||
|
||||
@staticmethod
|
||||
def randomvoice():
|
||||
@@ -76,3 +87,4 @@ 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
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import random
|
||||
from os import listdir, environ, remove
|
||||
from os import listdir, environ
|
||||
from pathlib import Path
|
||||
from random import randrange
|
||||
|
||||
from moviepy.editor import VideoFileClip
|
||||
from pytube import YouTube
|
||||
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
|
||||
|
||||
@@ -30,31 +30,27 @@ 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:
|
||||
|
||||
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}')
|
||||
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
|
||||
|
||||
print_substep("Background videos downloaded successfully! 🎉", style="bold green")
|
||||
|
||||
|
||||
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'))
|
||||
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)
|
||||
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")
|
||||
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")
|
||||
@@ -4,5 +4,11 @@
|
||||
"value": "eyJwcmVmcyI6eyJ0b3BDb250ZW50RGlzbWlzc2FsVGltZSI6MCwiZ2xvYmFsVGhlbWUiOiJSRURESVQiLCJuaWdodG1vZGUiOnRydWUsImNvbGxhcHNlZFRyYXlTZWN0aW9ucyI6eyJmYXZvcml0ZXMiOmZhbHNlLCJtdWx0aXMiOmZhbHNlLCJtb2RlcmF0aW5nIjpmYWxzZSwic3Vic2NyaXB0aW9ucyI6ZmFsc2UsInByb2ZpbGVzIjpmYWxzZX0sInRvcENvbnRlbnRUaW1lc0Rpc21pc3NlZCI6MH19",
|
||||
"domain": ".reddit.com",
|
||||
"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": "/"
|
||||
}
|
||||
]
|
||||
Regular → Executable
+8
-4
@@ -3,8 +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 import io
|
||||
|
||||
from utils.cleanup import cleanup
|
||||
from utils.console import print_step, print_substep
|
||||
@@ -12,7 +12,7 @@ from utils.console import print_step, print_substep
|
||||
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 🎥")
|
||||
VideoFileClip.reW = lambda clip: clip.resize(width=W)
|
||||
VideoFileClip.reH = lambda clip: clip.resize(width=H)
|
||||
@@ -65,7 +65,11 @@ def make_final_video(number_of_clips):
|
||||
if not exists('./results'):
|
||||
print_substep('the results folder didn\'t exist so I made it')
|
||||
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 🗑")
|
||||
cleanups = cleanup()
|
||||
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()
|
||||
|
||||
if getenv("THEME").upper() == "DARK":
|
||||
cookie_file = open('./video_creation/data/cookie.json')
|
||||
cookies = json.load(cookie_file)
|
||||
context.add_cookies(cookies)
|
||||
cookie_file = open('./video_creation/data/cookie-dark-mode.json')
|
||||
else:
|
||||
cookie_file = open('./video_creation/data/cookie-light-mode.json')
|
||||
cookies = json.load(cookie_file)
|
||||
context.add_cookies(cookies)
|
||||
# Get the thread screenshot
|
||||
page = context.new_page()
|
||||
page.set_viewport_size(ViewportSize(width=1920, height=1080))
|
||||
|
||||
Reference in new issue
Block a user