Merge branch 'develop' into master

pull/1172/head
cooler 3 years ago committed by GitHub
commit 7f6b57a838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,28 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: bug
assignees: ""
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System (please complete the following information):**
- Python Version: [e.g. Python 3.6]
- OS: [e.g. Windows 11]
- App version / Branch [e.g. latest, V2.0, master, develop ]
**Additional context**
Add any other context about the problem here.

@ -0,0 +1,64 @@
name: Bug Report
title: "[Bug]: "
labels: bug
description: Report broken or incorrect behaviour
body:
- type: markdown
attributes:
value: >
Thanks for taking the time to fill out a bug.
Please note that this form is for bugs only!
- type: textarea
id: what-happened
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Reproduction Steps
description: >
What you did to make it happen.
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: >
A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Screenshots
description: >
If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: textarea
attributes:
label: System Information
description: please fill your system informations
value: >
Operating System : [e.g. Windows 11]
Python version : [e.g. Python 3.6]
App version / Branch : [e.g. latest, V2.0, master, develop]
validations:
required: true
- type: checkboxes
attributes:
label: Checklist
description: >
Let's make sure you've properly done due diligence when reporting this issue!
options:
- label: I have searched the open issues for duplicates.
required: true
- label: I have shown the entire traceback, if possible.
required: true
- type: textarea
attributes:
label: Additional Context
description: Add any other context about the problem here.

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
about: Join our discord server to ask questions and discuss with maintainers and contributors.
url: https://discord.gg/swqtb7AsNQ

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered** (optional)
A clear and concise description of any alternative solutions or features you've considered.
**Additional context** (optional)
Add any other context or screenshots about the feature request here.

@ -0,0 +1,39 @@
name: Feature Request
description: Suggest an idea for this project
labels: enhancement
title: "[Feature]: "
body:
- type: input
attributes:
label: Summary
description: >
A short summary of what your feature request is.
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem?
description: >
if yes, what becomes easier or possible when this feature is implemented?
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: >
A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: >
A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.

1
.gitignore vendored

@ -243,3 +243,4 @@ video_creation/data/videos.json
video_creation/data/envvars.txt video_creation/data/envvars.txt
config.toml config.toml
video_creation/data/videos.json

@ -28,7 +28,7 @@ All types of contributions are encouraged and valued. See the [Table of Contents
## I Have a Question ## I Have a Question
> If you want to ask a question, we assume that you have read the available [Documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/). > If you want to ask a question, we assume that you have read the available [Documentation](https://reddit-video-maker-bot.netlify.app/).
Before you ask a question, it is best to search for existing [Issues](https://github.com/elebumm/RedditVideoMakerBot/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. Before you ask a question, it is best to search for existing [Issues](https://github.com/elebumm/RedditVideoMakerBot/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
@ -144,4 +144,4 @@ When making your PR, follow these guidelines:
### Improving The Documentation ### Improving The Documentation
All updates to the documentation should be made in a pull request to [this repo](https://github.com/LukaHietala/reddit-bot-docs) All updates to the documentation should be made in a pull request to [this repo](https://github.com/LukaHietala/RedditVideoMakerBot-website)

@ -39,12 +39,11 @@ The only original thing being done is the editing and gathering of all materials
1. Clone this repository 1. Clone this repository
2. Run `pip install -r requirements.txt` 2. Run `pip install -r requirements.txt`
3. Run `python -m playwright install` and `python -m playwright install-deps` 3. Run `python -m playwright install` and `python -m playwright install-deps`
**EXPERIMENTAL!!!!** **EXPERIMENTAL!!!!**
On MacOS and Linux (debian, arch, fedora and centos, and based on those), you can run an install script that will automatically install steps 1 to 3. (requires bash) On macOS and Linux (debian, arch, fedora and centos, and based on those), you can run an install script that will automatically install steps 1 to 3. (requires bash)
`bash <(curl -sL https://raw.githubusercontent.com/elebumm/RedditVideoMakerBot/master/install.sh)` `bash <(curl -sL https://raw.githubusercontent.com/elebumm/RedditVideoMakerBot/master/install.sh)`
@ -58,7 +57,7 @@ This can also be used to update the installation
(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) (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)
If you want to read more detailed guide about the bot, please refer to the [documentation](https://luka-hietala.gitbook.io/documentation-for-the-reddit-bot/) If you want to read more detailed guide about the bot, please refer to the [documentation](https://reddit-video-maker-bot.netlify.app/)
## Video ## Video

@ -1,9 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import random import random
from utils import settings
from gtts import gTTS from gtts import gTTS
max_chars = 0 from utils import settings
class GTTS: class GTTS:

@ -1,9 +1,11 @@
import base64 import base64
from utils import settings
import random import random
import requests import requests
from requests.adapters import HTTPAdapter, Retry from requests.adapters import HTTPAdapter, Retry
from utils import settings
# from profanity_filter import ProfanityFilter # from profanity_filter import ProfanityFilter
# pf = ProfanityFilter() # pf = ProfanityFilter()
# Code by @JasonLovesDoggo # Code by @JasonLovesDoggo
@ -62,9 +64,7 @@ noneng = [
class TikTok: # TikTok Text-to-Speech Wrapper class TikTok: # TikTok Text-to-Speech Wrapper
def __init__(self): def __init__(self):
self.URI_BASE = ( self.URI_BASE = "https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker="
"https://api16-normal-useast5.us.tiktokv.com/media/api/text/speech/invoke/?text_speaker="
)
self.max_chars = 300 self.max_chars = 300
self.voices = {"human": human, "nonhuman": nonhuman, "noneng": noneng} self.voices = {"human": human, "nonhuman": nonhuman, "noneng": noneng}
@ -75,10 +75,7 @@ class TikTok: # TikTok Text-to-Speech Wrapper
voice = ( voice = (
self.randomvoice() self.randomvoice()
if random_voice if random_voice
else ( else (settings.config["settings"]["tts"]["tiktok_voice"] or random.choice(self.voices["human"]))
settings.config["settings"]["tts"]["tiktok_voice"]
or random.choice(self.voices["human"])
)
) )
try: try:
r = requests.post(f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0") r = requests.post(f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0")

@ -1,9 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import random
import sys
from boto3 import Session from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError, ProfileNotFound from botocore.exceptions import BotoCoreError, ClientError, ProfileNotFound
import sys
from utils import settings from utils import settings
import random
voices = [ voices = [
"Brian", "Brian",
@ -37,15 +39,11 @@ class AWSPolly:
voice = self.randomvoice() voice = self.randomvoice()
else: else:
if not settings.config["settings"]["tts"]["aws_polly_voice"]: if not settings.config["settings"]["tts"]["aws_polly_voice"]:
raise ValueError( raise ValueError(f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}")
f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}"
)
voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize() voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize()
try: try:
# Request speech synthesis # Request speech synthesis
response = polly.synthesize_speech( response = polly.synthesize_speech(Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural")
Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural"
)
except (BotoCoreError, ClientError) as error: except (BotoCoreError, ClientError) as error:
# The service returned an error, exit gracefully # The service returned an error, exit gracefully
print(error) print(error)

@ -1,17 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import re
from pathlib import Path from pathlib import Path
from typing import Tuple from typing import Tuple
import re
# import sox # import sox
# from mutagen import MutagenError # from mutagen import MutagenError
# from mutagen.mp3 import MP3, HeaderNotFoundError # from mutagen.mp3 import MP3, HeaderNotFoundError
import translators as ts import translators as ts
from rich.progress import track
from moviepy.editor import AudioFileClip, CompositeAudioClip, concatenate_audioclips from moviepy.editor import AudioFileClip, CompositeAudioClip, concatenate_audioclips
from rich.progress import track
from utils import settings
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
from utils.voice import sanitize_text from utils.voice import sanitize_text
from utils import settings
DEFAULT_MAX_LENGTH: int = 50 # video length variable DEFAULT_MAX_LENGTH: int = 50 # video length variable
@ -70,9 +71,7 @@ class TTSEngine:
self.length -= self.last_clip_length self.length -= self.last_clip_length
idx -= 1 idx -= 1
break break
if ( if len(comment["comment_body"]) > self.tts_module.max_chars: # Split the comment if it is too long
len(comment["comment_body"]) > self.tts_module.max_chars
): # Split the comment if it is too long
self.split_post(comment["comment_body"], idx) # Split the comment self.split_post(comment["comment_body"], idx) # Split the comment
else: # If the comment is not too long, just call the tts engine else: # If the comment is not too long, just call the tts engine
self.call_tts(f"{idx}", process_text(comment["comment_body"])) self.call_tts(f"{idx}", process_text(comment["comment_body"]))
@ -83,10 +82,7 @@ class TTSEngine:
def split_post(self, text: str, idx: int): def split_post(self, text: str, idx: int):
split_files = [] split_files = []
split_text = [ split_text = [
x.group().strip() x.group().strip() for x in re.finditer(r" *(((.|\n){0," + str(self.tts_module.max_chars) + "})(\.|.$))", text)
for x in re.finditer(
r" *(((.|\n){0," + str(self.tts_module.max_chars) + "})(\.|.$))", text
)
] ]
offset = 0 offset = 0
for idy, text_cut in enumerate(split_text): for idy, text_cut in enumerate(split_text):

@ -1,5 +1,7 @@
import random import random
import pyttsx3 import pyttsx3
from utils import settings from utils import settings
@ -30,9 +32,7 @@ class pyttsx:
voice_id = self.randomvoice() voice_id = self.randomvoice()
engine = pyttsx3.init() engine = pyttsx3.init()
voices = engine.getProperty("voices") voices = engine.getProperty("voices")
engine.setProperty( engine.setProperty("voice", voices[voice_id].id) # changing index changes voices but ony 0 and 1 are working here
"voice", voices[voice_id].id
) # changing index changes voices but ony 0 and 1 are working here
engine.save_to_file(text, f"{filepath}") engine.save_to_file(text, f"{filepath}")
engine.runAndWait() engine.runAndWait()

@ -1,6 +1,8 @@
import random import random
import requests import requests
from requests.exceptions import JSONDecodeError from requests.exceptions import JSONDecodeError
from utils import settings from utils import settings
from utils.voice import check_ratelimit from utils.voice import check_ratelimit
@ -37,9 +39,7 @@ class StreamlabsPolly:
voice = self.randomvoice() voice = self.randomvoice()
else: else:
if not settings.config["settings"]["tts"]["streamlabs_polly_voice"]: if not settings.config["settings"]["tts"]["streamlabs_polly_voice"]:
raise ValueError( raise ValueError(f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}")
f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}"
)
voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize() voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize()
body = {"voice": voice, "text": text, "service": "polly"} body = {"voice": voice, "text": text, "service": "polly"}
response = requests.post(self.url, data=body) response = requests.post(self.url, data=body)

@ -62,7 +62,13 @@ function install_macos(){
fi fi
# Install the required packages # Install the required packages
echo "Installing required Packages" echo "Installing required Packages"
brew install python@3.10 tcl-tk python-tk if [! command --version python3 &> /dev/null ]; then
echo "Installing python3"
brew install python@3.10
else
echo "python3 already installed."
fi
brew install tcl-tk python-tk
} }
# Function to install for arch (and other forks like manjaro) # Function to install for arch (and other forks like manjaro)

@ -9,12 +9,11 @@ from sys import platform
from prawcore import ResponseException from prawcore import ResponseException
from reddit.subreddit import get_subreddit_threads from reddit.subreddit import get_subreddit_threads
from utils.cleanup import cleanup
from utils.console import print_markdown, print_step, print_substep
from utils import settings from utils import settings
from utils.cleanup import cleanup
from utils.console import print_markdown, print_step
from utils.id import id from utils.id import id
from utils.version import checkversion from utils.version import checkversion
from video_creation.background import ( from video_creation.background import (
download_background, download_background,
chop_background_video, chop_background_video,
@ -24,7 +23,7 @@ from video_creation.final_video import make_final_video
from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts from video_creation.screenshot_downloader import download_screenshots_of_reddit_posts
from video_creation.voices import save_text_to_mp3 from video_creation.voices import save_text_to_mp3
__VERSION__ = "2.4.1" __VERSION__ = "2.4.2"
### 3 util functions. by github.com/notcooler ### ### 3 util functions. by github.com/notcooler ###
def getPlatform(): def getPlatform():
@ -77,7 +76,7 @@ print(
) )
# Modified by JasonLovesDoggo # Modified by JasonLovesDoggo
print_markdown( 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/)" "### 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://reddit-video-maker-bot.netlify.app/"
) )
checkversion(__VERSION__) checkversion(__VERSION__)
@ -116,14 +115,13 @@ def shutdown():
print("Exiting...") print("Exiting...")
exit() exit()
if __name__ == "__main__": if __name__ == "__main__":
assert sys.version_info >= (3, 9), "Python 3.10 or higher is required"
config = settings.check_toml("utils/.config.template.toml", "config.toml") config = settings.check_toml("utils/.config.template.toml", "config.toml")
config is False and exit() config is False and exit()
try: try:
if config["settings"]["times_to_run"]: if len(config["reddit"]["thread"]["post_id"].split("+")) > 1:
run_many(config["settings"]["times_to_run"])
elif len(config["reddit"]["thread"]["post_id"].split("+")) > 1:
for index, post_id in enumerate(config["reddit"]["thread"]["post_id"].split("+")): for index, post_id in enumerate(config["reddit"]["thread"]["post_id"].split("+")):
index += 1 index += 1
print_step( print_step(
@ -131,6 +129,8 @@ if __name__ == "__main__":
) )
main(post_id) main(post_id)
Popen("cls" if name == "nt" else "clear", shell=True).wait() Popen("cls" if name == "nt" else "clear", shell=True).wait()
elif config["settings"]["times_to_run"]:
run_many(config["settings"]["times_to_run"])
else: else:
main() main()
except KeyboardInterrupt: except KeyboardInterrupt:

@ -1,11 +1,10 @@
import re import re
from prawcore.exceptions import ResponseException
from utils import settings
import praw import praw
from praw.models import MoreComments from praw.models import MoreComments
from prawcore.exceptions import ResponseException
from utils import settings
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
from utils.subreddit import get_subreddit_undone from utils.subreddit import get_subreddit_undone
from utils.videos import check_done from utils.videos import check_done
@ -41,9 +40,8 @@ def get_subreddit_threads(POST_ID: str):
check_for_async=False, check_for_async=False,
) )
except ResponseException as e: except ResponseException as e:
match e.response.status_code: if e.response.status_code == 401:
case 401: print("Invalid credentials - please check them in config.toml")
print("Invalid credentials - please check them in config.toml")
except: except:
print("Something went wrong...") print("Something went wrong...")
@ -105,12 +103,9 @@ def get_subreddit_threads(POST_ID: str):
sanitised = sanitize_text(top_level_comment.body) sanitised = sanitize_text(top_level_comment.body)
if not sanitised or sanitised == " ": if not sanitised or sanitised == " ":
continue continue
if len(top_level_comment.body) <= int( if len(top_level_comment.body) <= int(settings.config["reddit"]["thread"]["max_comment_length"]):
settings.config["reddit"]["thread"]["max_comment_length"]
):
if ( if (
top_level_comment.author is not None top_level_comment.author is not None and sanitize_text(top_level_comment.body) is not None
and sanitize_text(top_level_comment.body) is not None
): # if errors occur with this change to if not. ): # if errors occur with this change to if not.
content["comments"].append( content["comments"].append(
{ {

@ -1,11 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import re
from rich.columns import Columns
from rich.console import Console from rich.console import Console
from rich.markdown import Markdown from rich.markdown import Markdown
from rich.padding import Padding from rich.padding import Padding
from rich.panel import Panel from rich.panel import Panel
from rich.text import Text from rich.text import Text
from rich.columns import Columns
import re
console = Console() console = Console()
@ -54,11 +55,7 @@ def handle_input(
return default if default is not NotImplemented else "" return default if default is not NotImplemented else ""
if default is not NotImplemented: if default is not NotImplemented:
console.print( console.print(
"[green]" "[green]" + message + '\n[blue bold]The default value is "' + str(default) + '"\nDo you want to use it?(y/n)'
+ message
+ '\n[blue bold]The default value is "'
+ str(default)
+ '"\nDo you want to use it?(y/n)'
) )
if input().casefold().startswith("y"): if input().casefold().startswith("y"):
return default return default
@ -71,9 +68,7 @@ def handle_input(
if check_type is not False: if check_type is not False:
try: try:
user_input = check_type(user_input) user_input = check_type(user_input)
if (nmin is not None and user_input < nmin) or ( if (nmin is not None and user_input < nmin) or (nmax is not None and user_input > nmax):
nmax is not None and user_input > nmax
):
# FAILSTATE Input out of bounds # FAILSTATE Input out of bounds
console.print("[red]" + oob_error) console.print("[red]" + oob_error)
continue continue
@ -89,9 +84,7 @@ def handle_input(
continue continue
else: else:
# FAILSTATE Input STRING out of bounds # FAILSTATE Input STRING out of bounds
if (nmin is not None and len(user_input) < nmin) or ( if (nmin is not None and len(user_input) < nmin) or (nmax is not None and len(user_input) > nmax):
nmax is not None and len(user_input) > nmax
):
console.print("[red bold]" + oob_error) console.print("[red bold]" + oob_error)
continue continue
break # SUCCESS Input STRING in bounds break # SUCCESS Input STRING in bounds
@ -105,16 +98,8 @@ def handle_input(
isinstance(eval(user_input), check_type) isinstance(eval(user_input), check_type)
return check_type(user_input) return check_type(user_input)
except: except:
console.print( console.print("[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + ".")
"[red bold]"
+ err_message
+ "\nValid options are: "
+ ", ".join(map(str, options))
+ "."
)
continue continue
if user_input in options: if user_input in options:
return user_input return user_input
console.print( console.print("[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + ".")
"[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + "."
)

@ -1,6 +1,8 @@
import re import re
from utils.console import print_substep from utils.console import print_substep
def id(reddit_obj: dict): def id(reddit_obj: dict):
""" """
This function takes a reddit object and returns the post id This function takes a reddit object and returns the post id

@ -1,12 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python
import toml
from rich.console import Console
import re import re
from typing import Tuple, Dict from typing import Tuple, Dict
from utils.console import handle_input import toml
from rich.console import Console
from utils.console import handle_input
console = Console() console = Console()
config = dict # autocomplete config = dict # autocomplete
@ -35,17 +34,12 @@ def check(value, checks, name):
except: except:
incorrect = True incorrect = True
if ( if not incorrect and "options" in checks and value not in checks["options"]: # FAILSTATE Value is not one of the options
not incorrect and "options" in checks and value not in checks["options"]
): # FAILSTATE Value is not one of the options
incorrect = True incorrect = True
if ( if (
not incorrect not incorrect
and "regex" in checks and "regex" in checks
and ( and ((isinstance(value, str) and re.match(checks["regex"], value) is None) or not isinstance(value, str))
(isinstance(value, str) and re.match(checks["regex"], value) is None)
or not isinstance(value, str)
)
): # FAILSTATE Value doesn't match regex, or has regex but is not a string. ): # FAILSTATE Value doesn't match regex, or has regex but is not a string.
incorrect = True incorrect = True
@ -85,9 +79,7 @@ def check(value, checks, name):
err_message=get_check_value("input_error", "Incorrect input"), err_message=get_check_value("input_error", "Incorrect input"),
nmin=get_check_value("nmin", None), nmin=get_check_value("nmin", None),
nmax=get_check_value("nmax", None), nmax=get_check_value("nmax", None),
oob_error=get_check_value( oob_error=get_check_value("oob_error", "Input out of bounds(Value too high/low/long/short)"),
"oob_error", "Input out of bounds(Value too high/low/long/short)"
),
options=get_check_value("options", None), options=get_check_value("options", None),
optional=get_check_value("optional", False), optional=get_check_value("optional", False),
) )

@ -54,9 +54,7 @@ def get_subreddit_undone(submissions: list, subreddit, times_checked=0):
print("all time filters have been checked you absolute madlad ") print("all time filters have been checked you absolute madlad ")
return get_subreddit_undone( return get_subreddit_undone(
subreddit.top( subreddit.top(time_filter=VALID_TIME_FILTERS[index], limit=(50 if int(index) == 0 else index + 1 * 50)),
time_filter=VALID_TIME_FILTERS[index], limit=(50 if int(index) == 0 else index + 1 * 50)
),
subreddit, subreddit,
times_checked=index, times_checked=index,
) # all the videos in hot have already been done ) # all the videos in hot have already been done

@ -1,11 +1,10 @@
import requests import requests
from utils.console import print_step from utils.console import print_step
def checkversion(__VERSION__): def checkversion(__VERSION__):
response = requests.get( response = requests.get("https://api.github.com/repos/elebumm/RedditVideoMakerBot/releases/latest")
"https://api.github.com/repos/elebumm/RedditVideoMakerBot/releases/latest"
)
latestversion = response.json()["tag_name"] latestversion = response.json()["tag_name"]
if __VERSION__ == latestversion: if __VERSION__ == latestversion:
print_step(f"You are using the newest version ({__VERSION__}) of the bot") print_step(f"You are using the newest version ({__VERSION__}) of the bot")

@ -1,7 +1,6 @@
from __future__ import annotations from __future__ import annotations
from ast import Str
import re
import re
from typing import Tuple from typing import Tuple
from PIL import ImageFont, Image, ImageDraw, ImageEnhance from PIL import ImageFont, Image, ImageDraw, ImageEnhance
@ -37,9 +36,7 @@ class Video:
im.save(path) im.save(path)
return ImageClip(path) return ImageClip(path)
def add_watermark( def add_watermark(self, text, redditid, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15):
self, text, redditid, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15
):
compensation = round( compensation = round(
(position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])), (position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])),
ndigits=2, ndigits=2,

@ -1,6 +1,5 @@
import json import json
import time import time
from typing import Dict
from praw.models import Submission from praw.models import Submission

@ -1,7 +1,7 @@
import re import re
import sys import sys
from datetime import datetime
import time as pytime import time as pytime
from datetime import datetime
from time import sleep from time import sleep
from requests import Response from requests import Response
@ -81,7 +81,7 @@ def sanitize_text(text: str) -> str:
result = re.sub(regex_urls, " ", text) result = re.sub(regex_urls, " ", text)
# note: not removing apostrophes # note: not removing apostrophes
regex_expr = r"\s['|]|['|]\s|[\^_~@!&;#:\-–—%“”‘\"%\*/{}\[\]\(\)\\|<>=+]" regex_expr = r"\s['|]|['|]\s|[\^_~@!&;#:\-%“”‘\"%\*/{}\[\]\(\)\\|<>=+]"
result = re.sub(regex_expr, " ", result) result = re.sub(regex_expr, " ", result)
result = result.replace("+", "plus").replace("&", "and") result = result.replace("+", "plus").replace("&", "and")
# remove extra whitespace # remove extra whitespace

@ -1,10 +1,9 @@
from pathlib import Path
import random import random
from random import randrange
import re import re
from pathlib import Path
from random import randrange
from typing import Any, Tuple from typing import Any, Tuple
from moviepy.editor import VideoFileClip 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 pytube import YouTube from pytube import YouTube
@ -52,9 +51,7 @@ def download_background(background_config: Tuple[str, str, str, Any]):
uri, filename, credit, _ = background_config uri, filename, credit, _ = background_config
if Path(f"assets/backgrounds/{credit}-{filename}").is_file(): if Path(f"assets/backgrounds/{credit}-{filename}").is_file():
return return
print_step( print_step("We need to download the backgrounds videos. they are fairly large but it's only done once. 😎")
"We need to download the backgrounds 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 🙏 ")
print_substep(f"Downloading {filename} from {uri}") print_substep(f"Downloading {filename} from {uri}")
YouTube(uri, on_progress_callback=on_progress).streams.filter(res="1080p").first().download( YouTube(uri, on_progress_callback=on_progress).streams.filter(res="1080p").first().download(

@ -4,6 +4,7 @@ import os
import re import re
from os.path import exists from os.path import exists
from typing import Tuple, Any from typing import Tuple, Any
from moviepy.audio.AudioClip import concatenate_audioclips, CompositeAudioClip from moviepy.audio.AudioClip import concatenate_audioclips, CompositeAudioClip
from moviepy.audio.io.AudioFileClip import AudioFileClip from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.VideoClip import ImageClip from moviepy.video.VideoClip import ImageClip
@ -13,11 +14,11 @@ from moviepy.video.io.VideoFileClip import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from rich.console import Console from rich.console import Console
from utils import settings
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
from utils.video import Video from utils.video import Video
from utils.videos import save_data from utils.videos import save_data
from utils import settings
console = Console() console = Console()
W, H = 1080, 1920 W, H = 1080, 1920
@ -118,9 +119,7 @@ def make_final_video(
# ) # )
# else: story mode stuff # else: story mode stuff
img_clip_pos = background_config[3] img_clip_pos = background_config[3]
image_concat = concatenate_videoclips(image_clips).set_position( image_concat = concatenate_videoclips(image_clips).set_position(img_clip_pos) # note transition kwarg for delay in imgs
img_clip_pos
) # note transition kwarg for delay in imgs
image_concat.audio = audio_composite image_concat.audio = audio_composite
final = CompositeVideoClip([background_clip, image_concat]) final = CompositeVideoClip([background_clip, image_concat])
title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"]) title = re.sub(r"[^\w\s-]", "", reddit_obj["thread_title"])
@ -140,9 +139,7 @@ def make_final_video(
# # lowered_audio = audio_background.multiply_volume( # todo get this to work # # lowered_audio = audio_background.multiply_volume( # todo get this to work
# # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx # # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx
# final.set_audio(final_audio) # final.set_audio(final_audio)
final = Video(final).add_watermark( final = Video(final).add_watermark(text=f"Background credit: {background_config[2]}", opacity=0.4, redditid=reddit_obj)
text=f"Background credit: {background_config[2]}", opacity=0.4, redditid=reddit_obj
)
final.write_videofile( final.write_videofile(
f"assets/temp/{id}/temp.mp4", f"assets/temp/{id}/temp.mp4",
fps=30, fps=30,
@ -163,6 +160,4 @@ def make_final_video(
print_substep(f"Removed {cleanups} temporary files 🗑") print_substep(f"Removed {cleanups} temporary files 🗑")
print_substep("See result in the results folder!") print_substep("See result in the results folder!")
print_step( print_step(f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}')
f'Reddit title: {reddit_obj["thread_title"]} \n Background Credit: {background_config[2]}'
)

@ -1,19 +1,17 @@
import json import json
from pathlib import Path
import re import re
from pathlib import Path
from typing import Dict from typing import Dict
from utils import settings
from playwright.async_api import async_playwright # pylint: disable=unused-import
# do not remove the above line
import translators as ts
from playwright.sync_api import sync_playwright, ViewportSize from playwright.sync_api import sync_playwright, ViewportSize
from rich.progress import track from rich.progress import track
import translators as ts
from utils import settings
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
# do not remove the above line
storymode = False storymode = False
@ -32,7 +30,7 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
with sync_playwright() as p: with sync_playwright() as p:
print_substep("Launching Headless Browser...") print_substep("Launching Headless Browser...")
browser = p.chromium.launch() browser = p.chromium.launch(headless=True) # add headless=False for debug
context = browser.new_context() context = browser.new_context()
if settings.config["settings"]["theme"] == "dark": if settings.config["settings"]["theme"] == "dark":
@ -53,9 +51,7 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
page.wait_for_load_state() # Wait for page to fully load page.wait_for_load_state() # Wait for page to fully load
if page.locator('[data-click-id="text"] button').is_visible(): if page.locator('[data-click-id="text"] button').is_visible():
page.locator( page.locator('[data-click-id="text"] button').click() # Remove "Click to see nsfw" Button in Screenshot
'[data-click-id="text"] button'
).click() # Remove "Click to see nsfw" Button in Screenshot
# translate code # translate code
@ -74,16 +70,12 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
print_substep("Skipping translation...") print_substep("Skipping translation...")
postcontentpath = f"assets/temp/{id}/png/title.png" postcontentpath = f"assets/temp/{id}/png/title.png"
page.locator('[data-test-id="post-content"]').screenshot(path= postcontentpath) page.locator('[data-test-id="post-content"]').screenshot(path=postcontentpath)
if storymode: if storymode:
page.locator('[data-click-id="text"]').screenshot( page.locator('[data-click-id="text"]').screenshot(path=f"assets/temp/{id}/png/story_content.png")
path=f"assets/temp/{id}/png/story_content.png"
)
else: else:
for idx, comment in enumerate( for idx, comment in enumerate(track(reddit_object["comments"], "Downloading screenshots...")):
track(reddit_object["comments"], "Downloading screenshots...")
):
# Stop if we have reached the screenshot_num # Stop if we have reached the screenshot_num
if idx >= screenshot_num: if idx >= screenshot_num:
break break
@ -105,9 +97,7 @@ def download_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: in
[comment_tl, comment["comment_id"]], [comment_tl, comment["comment_id"]],
) )
try: try:
page.locator(f"#t1_{comment['comment_id']}").screenshot( page.locator(f"#t1_{comment['comment_id']}").screenshot(path=f"assets/temp/{id}/png/comment_{idx}.png")
path=f"assets/temp/{id}/png/comment_{idx}.png"
)
except TimeoutError: except TimeoutError:
del reddit_object["comments"] del reddit_object["comments"]
screenshot_num += 1 screenshot_num += 1

@ -1,19 +1,18 @@
#!/usr/bin/env python #!/usr/bin/env python
from typing import Dict, Tuple from typing import Tuple
from rich.console import Console from rich.console import Console
from TTS.engine_wrapper import TTSEngine
from TTS.GTTS import GTTS from TTS.GTTS import GTTS
from TTS.streamlabs_polly import StreamlabsPolly
from TTS.aws_polly import AWSPolly
from TTS.TikTok import TikTok from TTS.TikTok import TikTok
from TTS.aws_polly import AWSPolly
from TTS.engine_wrapper import TTSEngine
from TTS.pyttsx import pyttsx from TTS.pyttsx import pyttsx
from TTS.streamlabs_polly import StreamlabsPolly
from utils import settings from utils import settings
from utils.console import print_table, print_step from utils.console import print_table, print_step
console = Console() console = Console()
TTSProviders = { TTSProviders = {

Loading…
Cancel
Save