Merge upstream develop local changes to env-update

pull/563/head
owengaspard 3 years ago
parent ddc402c48d
commit 0fd031029b

@ -1,4 +1,3 @@
# This can be found in the email that reddit sent you when you created the app
REDDIT_CLIENT_ID=""
REDDIT_CLIENT_SECRET=""
@ -6,16 +5,8 @@ REDDIT_USERNAME=""
REDDIT_PASSWORD=""
# If no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: "no"
RANDOM_THREAD=""
RANDOM_THREAD="no"
# Filters the comments by range of length (min and max characters)
# Min has to be less or equal to max
# DO NOT INSERT ANY SPACES BETWEEN THE COMMA AND THE VALUES
COMMENT_LENGTH_RANGE = "min,max"
# The absolute path of the folder where you want to save the final video
# If empty or wrong, the path will be 'results/'
FINAL_VIDEO_PATH=""
# Valid options are "yes" and "no" for the variable below
REDDIT_2FA=""
SUBREDDIT="AskReddit"
@ -25,15 +16,16 @@ ALLOW_NSFW="False"
POST_ID=""
#set to either LIGHT or DARK
THEME="LIGHT"
# used if you want to run multiple times. set to an int e.g. 4 or 29 and leave blank for once
# used if you want to run multiple times. set to an int e.g. 4 or 29 and leave blank for 1
TIMES_TO_RUN=""
MAX_COMMENT_LENGTH="500"
# max number of characters a comment can have.
MAX_COMMENT_LENGTH="500" # default is 500
# Range is 0 -> 1 recommended around 0.8-0.9
OPACITY="1"
# see TTSwrapper.py for all valid options
# see different voice options: todo: add docs
VOICE="Matthew" # e.g. en_us_002
TTsChoice="polly" # todo add docs
TTsChoice="polly"
# IN-PROGRESS - not yet implemented
STORYMODE="False"

1
.gitattributes vendored

@ -0,0 +1 @@
* text=auto eol=lf

89
.gitignore vendored

@ -153,22 +153,91 @@ dmypy.json
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
assets/
out
.DS_Store
.setup-done-before
assets/
results/*
.env
reddit-bot-351418-5560ebc49cac.json
/.idea
*.pyc
/video_creation/data/videos.json
utils/envUpdate.py.old
envVars.txt
video_creation/data/videos.json
video_creation/data/envvars.txt

@ -39,21 +39,22 @@ The only original thing being done is the editing and gathering of all materials
## Installation 👩‍💻
1. Clone this repository
2. 2a **Automatic Install**: Run `python3 main.py` and type 'yes' to activate the setup assistant.
2. 2a **Automatic Install**: Run `python main.py` and type 'yes' to activate the setup assistant.
2b **Manual Install**: 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. install [SoX](https://sourceforge.net/projects/sox/files/sox/)
4.
5. Run `pip3 install -r requirements.txt`
3. Install [SoX](https://sourceforge.net/projects/sox/files/sox/)
6. Run `playwright install` and `playwright install-deps`.
4. Run `pip install -r requirements.txt`
7. Run `python3 main.py` (unless you chose automatic install, then the installer will automatically run main.py)
5. Run `playwright install` and `playwright install-deps`. (if this fails try adding python -m to the front of the command)
6. Run `python main.py` (unless you chose automatic install, then the installer will automatically run main.py)
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.
8. Enjoy 😎
7. Enjoy 😎
(Note if you got an error installing or running the bot try first rerunning the command with a three after the name e.g. python3 or pip3)
## Video
https://user-images.githubusercontent.com/66544866/173453972-6526e4e6-c6ef-41c5-ab40-5d275e724e7c.mp4
@ -71,7 +72,7 @@ I have tried to simplify the code so anyone can read it and start contributing a
- [x] Allowing users to change voice.
- [x] Checks if a video has already been created
- [x] Light and Dark modes
- [x] Nsfw post filter
- [x] NSFW post filter
Please read our [contributing guidelines](CONTRIBUTING.md) for more detailed information.

@ -59,9 +59,7 @@ class POLLY:
f.write(voice_data.content)
except (KeyError, JSONDecodeError):
if response.json()["error"] == "Text length is too long!":
chunks = [
m.group().strip() for m in re.finditer(r" *((.{0,499})(\.|.$))", req_text)
]
chunks = [m.group().strip() for m in re.finditer(r" *((.{0,499})(\.|.$))", req_text)]
audio_clips = []
cbn = sox.Combiner()

@ -67,7 +67,9 @@ noneng = [
class TikTok: # 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="
self.URI_BASE = (
"https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker="
)
def tts(
self,

@ -5,17 +5,20 @@ from dotenv import load_dotenv
from TTS.GTTS import GTTS
from TTS.POLLY import POLLY
from TTS.TikTok import TikTok
from utils.console import print_substep
CHOICE_DIR = {"tiktok": TikTok, "gtts": GTTS, 'polly': POLLY}
CHOICE_DIR = {"tiktok": TikTok, "gtts": GTTS, "polly": POLLY}
class TTS:
def __new__(cls):
load_dotenv()
try:
CHOICE = getenv("TTsChoice").casefold()
except AttributeError:
print_substep("None defined. Defaulting to 'polly.'")
CHOICE = "polly"
valid_keys = [key.lower() for key in CHOICE_DIR.keys()]
if CHOICE not in valid_keys:
raise ValueError(
f"{CHOICE} is not valid. Please use one of these {valid_keys} options"
)
raise ValueError(f"{CHOICE} is not valid. Please use one of these {valid_keys} options")
return CHOICE_DIR.get(CHOICE)()

@ -2,11 +2,11 @@ import time
from subprocess import Popen
from dotenv import load_dotenv
from os import getenv, name
from os import getenv, name, path
from reddit.subreddit import get_subreddit_threads
from utils.cleanup import cleanup
from utils.console import print_markdown, print_step
from utils.envUpdate import envUpdate
from utils.console import print_markdown, print_step, print_substep
from utils.checker import checkforEnv, envUpdate
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
@ -23,7 +23,6 @@ print(
"""
)
load_dotenv()
# Modified by JasonLovesDoggo
print_markdown(
"### Thanks for using this tool! [Feel free to contribute to this project on GitHub!](https://lewismenelaws.com) If you have any questions, feel free to reach out to me on Twitter or submit a GitHub issue. You can find solutions to many common problems in the [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/)"
)
@ -36,8 +35,8 @@ username = getenv("REDDIT_USERNAME")
password = getenv("REDDIT_PASSWORD")
reddit2fa = getenv("REDDIT_2FA")
def main():
checkforEnv()
envUpdate()
cleanup()
@ -52,7 +51,6 @@ def main():
chop_background_video(length)
make_final_video(number_of_comments, length)
def run_many(times):
for x in range(times):
x = x + 1
@ -62,7 +60,6 @@ def run_many(times):
main()
Popen("cls" if name == "nt" else "clear", shell=True).wait()
if __name__ == "__main__":
try:
if getenv("TIMES_TO_RUN") and isinstance(int(getenv("TIMES_TO_RUN")), int):

@ -1,3 +1,4 @@
import re
from os import getenv, environ
import praw
@ -14,6 +15,13 @@ def textify(text):
return "".join(filter(TEXT_WHITELIST.__contains__, text))
def try_env(param, backup):
try:
return environ[param]
except KeyError:
return backup
def get_subreddit_threads():
"""
Returns a list of threads from the AskReddit subreddit.
@ -44,10 +52,15 @@ def get_subreddit_threads():
print_step("Getting subreddit threads...")
if not getenv(
"SUBREDDIT"
): # note to self. you can have multiple subreddits via reddit.subreddit("redditdev+learnpython")
): # note to user. you can have multiple subreddits via reddit.subreddit("redditdev+learnpython")
try:
subreddit = reddit.subreddit(
input("What subreddit would you like to pull from? ")
) # if the env isnt set, ask user
re.sub(r"r\/", "", input("What subreddit would you like to pull from? "))
# removes the r/ from the input
)
except ValueError:
subreddit = reddit.subreddit("askreddit")
print_substep("Subreddit not defined. Using AskReddit.")
else:
print_substep(f"Using subreddit: r/{getenv('SUBREDDIT')} from environment variable config")
subreddit = reddit.subreddit(
@ -83,7 +96,7 @@ def get_subreddit_threads():
if top_level_comment.body in ["[removed]", "[deleted]"]:
continue # # see https://github.com/JasonLovesDoggo/RedditVideoMakerBot/issues/78
if not top_level_comment.stickied:
if len(top_level_comment.body) <= int(environ["MAX_COMMENT_LENGTH"]):
if len(top_level_comment.body) <= int(try_env("MAX_COMMENT_LENGTH", 500)):
content["comments"].append(
{
"comment_body": top_level_comment.body,

@ -40,14 +40,10 @@ def handle_input(
except ValueError:
console.log("[red]" + err_message) # Type conversion failed
continue
if (
nmin is not None and len(user_input) < nmin
): # Check if string is long enough
if nmin is not None and len(user_input) < nmin: # Check if string is long enough
console.log("[red]" + oob_error)
continue
if (
nmax is not None and len(user_input) > nmax
): # Check if string is not too long
if nmax is not None and len(user_input) > nmax: # Check if string is not too long
console.log("[red]" + oob_error)
continue
break

@ -0,0 +1,63 @@
import os
import subprocess
import tempfile
from os import path
from sys import platform
from utils.console import print_markdown, print_step, print_substep
ACCEPTABLE_TO_BE_LEFT_BLANK = ["RANDOM_THREAD", "TIMES_TO_RUN"]
def checkforEnv():
if path.exists(".env") == True:
return
else:
print_markdown("[ERROR] Could not find .env. \n If this is an error, please report it [on GitHub](https://github.com/elebumm/RedditVideoMakerBot/issues).")
exit()
def envUpdate():
if path.exists(".env.template"): # if .env.template exists
if platform == "win32" or platform == "cygwin":
runPS("utils/scripts/envValidator.ps1")
with open(".\\video_creation\\data\\envvars.txt", "rb") as f:
envTemplate = f.read()
elif platform == "darwin" or platform == "linux":
envTemplate = subprocess.check_output(
"awk -F '=' 'NF {print $1}' .env.template | grep --regexp=^[a-zA-Z]",
shell=True,
)
else:
raise OSError("[WARN] Could not validate your .env file due to an unsupported platform.")
else:
raise FileNotFoundError("[ERROR] Could not find .env.template.")
tempEnv = tempfile.TemporaryFile()
tempEnv.write(envTemplate)
tempEnv.seek(0)
envVars = tempEnv.readlines()
missing = []
isMissingEnvs = False
for env in envVars:
try:
env = env.decode("utf-8").strip()
except AttributeError:
env = env.strip()
if env not in os.environ:
if str(env) in ACCEPTABLE_TO_BE_LEFT_BLANK:
continue
isMissingEnvs = True
missing.append(env)
if isMissingEnvs:
printstr = ""
[printstr + str(var) for var in missing]
print(
f"The following environment variables are missing: {printstr}. Please add them to the .env file."
)
exit(-1)
def runPS(cmd):
completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True)
return completed

@ -5,9 +5,7 @@ from os.path import exists
def cleanup() -> int:
if exists("./assets/temp"):
count = 0
files = [
f for f in os.listdir(".") if f.endswith(".mp4") and "temp" in f.lower()
]
files = [f for f in os.listdir(".") if f.endswith(".mp4") and "temp" in f.lower()]
count += len(files)
for f in files:
os.remove(f)

@ -1,48 +0,0 @@
import os
import subprocess
import tempfile
import logging
from os import path
from sys import platform, stderr
log = logging.getLogger(__name__)
def envUpdate():
if path.exists(".env.template"):
if platform == "win32" or platform == "cygwin":
runPS('utils\envUpdateWin.ps1')
f = open("envVars.txt", "rb")
envTemplate = f.read()
elif platform == "darwin" or platform == "linux":
envTemplate = subprocess.check_output(
"awk -F '=' 'NF {print $1}' .env.template | grep --regexp=^[a-zA-Z]",
shell=True,
)
return
tempEnv = tempfile.TemporaryFile()
tempEnv.write(envTemplate)
tempEnv.seek(0)
envVars = tempEnv.readlines()
missing = []
isMissingEnvs = False
for env in envVars:
try:
env = env.decode("utf-8").strip()
except AttributeError:
env = env.strip()
if env not in os.environ:
isMissingEnvs = True
missing.append(env)
if isMissingEnvs:
log.error(
f"[ERROR] The following environment variables are missing: {missing}.)"
)
exit(-1)
def runPS(cmd):
completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True)
return completed

@ -2,7 +2,7 @@ $envFile = Get-Content ".\.env.template"
$envFile -split "=" | Where-Object {$_ -notmatch '\"'} | Set-Content ".\envVarsbefSpl.txt"
Get-Content ".\envVarsbefSpl.txt" | Where-Object {$_ -notmatch '\#'} | Set-Content ".\envVarsN.txt"
Get-Content ".\envVarsN.txt" | Where-Object {$_ -ne ''} | Set-Content ".\envVars.txt"
Get-Content ".\envVarsN.txt" | Where-Object {$_ -ne ''} | Set-Content ".\video_creation\data\envvars.txt"
Remove-Item ".\envVarsbefSpl.txt"
Remove-Item ".\envVarsN.txt"

@ -14,11 +14,14 @@ def get_subreddit_undone(submissions: List, subreddit):
if already_done(done_videos, submission):
continue
if submission.over_18:
try:
if getenv("ALLOW_NSFW").casefold() == "false":
print_substep("NSFW Post Detected. Skipping...")
continue
except AttributeError:
print_substep("NSFW settings not defined. Skipping NSFW post...")
return submission
print('all submissions have been done going by top submission order')
print("all submissions have been done going by top submission order")
return get_subreddit_undone(
subreddit.top(time_filter="hour"), subreddit
) # all of the videos in hot have already been done

@ -40,9 +40,7 @@ def download_background():
"assets/backgrounds", filename=f"{credit}-{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):

@ -1,2 +0,0 @@
videos.json
#todo add videos on github

@ -61,8 +61,7 @@ def make_final_video(number_of_clips, length):
ImageClip("assets/temp/png/title.png")
.set_duration(audio_clips[0].duration)
.set_position("center")
.resize(width=W - 100)
.set_opacity(float(opacity)),
.resize(width=W - 100),
)
else:
image_clips.insert(
@ -70,7 +69,8 @@ def make_final_video(number_of_clips, length):
ImageClip("assets/temp/png/title.png")
.set_duration(audio_clips[0].duration)
.set_position("center")
.resize(width=W - 100),
.resize(width=W - 100)
.set_opacity(float(opacity)),
)
for i in range(0, number_of_clips):

@ -40,7 +40,7 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num):
context.add_cookies(cookies) # load preference cookies
# Get the thread screenshot
page = context.new_page()
page.goto(reddit_object["thread_url"])
page.goto(reddit_object["thread_url"], timeout=0)
page.set_viewport_size(ViewportSize(width=1920, height=1080))
if page.locator('[data-testid="content-gate"]').is_visible():
# This means the post is NSFW and requires to click the proceed button.
@ -51,9 +51,7 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num):
'[data-click-id="text"] button'
).click() # Remove "Click to see nsfw" Button in Screenshot
page.locator('[data-test-id="post-content"]').screenshot(
path="assets/temp/png/title.png"
)
page.locator('[data-test-id="post-content"]').screenshot(path="assets/temp/png/title.png")
if storymode:
page.locator('[data-click-id="text"]').screenshot(
path="assets/temp/png/story_content.png"
@ -70,7 +68,7 @@ def download_screenshots_of_reddit_posts(reddit_object, screenshot_num):
if page.locator('[data-testid="content-gate"]').is_visible():
page.locator('[data-testid="content-gate"] button').click()
page.goto(f'https://reddit.com{comment["comment_url"]}')
page.goto(f'https://reddit.com{comment["comment_url"]}', timeout=0)
page.locator(f"#t1_{comment['comment_id']}").screenshot(
path=f"assets/temp/png/comment_{idx}.png"
)

Loading…
Cancel
Save