merged develop

pull/963/head
Drugsosos 2 years ago
commit 1e64625f7a
No known key found for this signature in database
GPG Key ID: 8E35176FE617E28D

@ -48,7 +48,7 @@ On MacOS and Linux (debian, arch, fedora and centos, and based on those), you ca
This can also be used to update the installation This can also be used to update the installation
4. Run `python main.py` 4. Run `python main.py`
5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". 5. Visit [the Reddit Apps page.](https://www.reddit.com/prefs/apps), and set up an app that is a "script". Paste any URL in redirect URL. Ex:google.com
6. The bot will ask you to fill in your details to connect to the Reddit API, and configure the bot to your liking 6. The bot will ask you to fill in your details to connect to the Reddit API, and configure the bot to your liking
7. Enjoy 😎 7. Enjoy 😎
8. If you need to reconfigure the bot, simply open the `config.toml` file and delete the lines that need to be changed. On the next run of the bot, it will help you reconfigure those options. 8. If you need to reconfigure the bot, simply open the `config.toml` file and delete the lines that need to be changed. On the next run of the bot, it will help you reconfigure those options.
@ -61,7 +61,7 @@ https://user-images.githubusercontent.com/66544866/173453972-6526e4e6-c6ef-41c5-
## Contributing & Ways to improve 📈 ## Contributing & Ways to improve 📈
In its current state, this bot does exactly what it needs to do. However, lots of improvements can be made. In its current state, this bot does exactly what it needs to do. However, improvements can always 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!

@ -2,6 +2,9 @@
from asyncio import run from asyncio import run
from subprocess import Popen from subprocess import Popen
from os import name from os import name
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.cleanup import cleanup
from utils.console import print_markdown, print_step from utils.console import print_markdown, print_step
@ -14,8 +17,8 @@ from video_creation.final_video import make_final_video
from video_creation.screenshot_downloader import RedditScreenshot from video_creation.screenshot_downloader import RedditScreenshot
from video_creation.voices import save_text_to_mp3 from video_creation.voices import save_text_to_mp3
__VERSION__ = "2.3" __VERSION__ = "2.3.1"
__BRANCH__ = "master" __BRANCH__ = "develop"
print( print(
""" """
@ -48,14 +51,20 @@ async def main(
async def run_many(times): async def run_many(times):
for x in range(1, times + 1): for x in range(1, times + 1):
print_step( print_step(
f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th","th", "th")[x%10]} iteration of {times}' f'on the {x}{("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")[x % 10]} iteration of {times}'
) # correct 1st 2nd 3rd 4th 5th.... ) # correct 1st 2nd 3rd 4th 5th....
await main() await main()
Popen("cls" if name == "nt" else "clear", shell=True).wait() Popen("cls" if name == "nt" else "clear", shell=True).wait()
def shutdown():
print_markdown("## Clearing temp files")
cleanup()
exit()
if __name__ == "__main__": if __name__ == "__main__":
config = settings.check_toml(".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 config["settings"]["times_to_run"]:
@ -67,7 +76,7 @@ if __name__ == "__main__":
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(
f'on the {index}{("st" if index%10 == 1 else ("nd" if index%10 == 2 else ("rd" if index%10 == 3 else "th")))} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}' f'on the {index}{("st" if index % 10 == 1 else ("nd" if index % 10 == 2 else ("rd" if index % 10 == 3 else "th")))} post of {len(config["reddit"]["thread"]["post_id"].split("+"))}'
) )
run( run(
main(post_id) main(post_id)
@ -76,6 +85,12 @@ if __name__ == "__main__":
else: else:
main() main()
except KeyboardInterrupt: except KeyboardInterrupt:
print_markdown("## Clearing temp files") shutdown()
cleanup() except ResponseException:
exit() # error for invalid credentials
print_markdown("## Invalid credentials")
print_markdown("Please check your credentials in the config.toml file")
shutdown()
# todo error

@ -10,3 +10,4 @@ toml==0.10.2
translators==5.3.1 translators==5.3.1
pyppeteer==1.0.2 pyppeteer==1.0.2
attrs==21.4.0 attrs==21.4.0
Pillow~=9.1.1

@ -38,7 +38,7 @@ video_width = { optional = true, default = 1080, example = 1080, explanation = "
video_height = { optional = true, default = 1920, example = 1920, explanation = "Final video height", type = "int", nmin = 800, oob_error = "Choose at least 800 pixels long" } video_height = { optional = true, default = 1920, example = 1920, explanation = "Final video height", type = "int", nmin = 800, oob_error = "Choose at least 800 pixels long" }
[settings.background] [settings.background]
background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", ""], explanation = "Sets the background for the video" } background_choice = { optional = true, default = "minecraft", example = "minecraft", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", ""], explanation = "Sets the background for the video" }
#background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, #background_audio = { optional = true, type = "bool", default = false, example = false, options = [true,
# false, # false,
#], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" } #], explaination="Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" }

@ -0,0 +1,45 @@
# Supported Background. Can add/remove background video here....
# <key>-<value> : key -> used as keyword for TOML file. value -> background configuration
# Format (value):
# 1. Youtube URI
# 2. filename
# 3. Citation (owner of the video)
# 4. Position of image clips in the background. See moviepy reference for more information. (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position)
background_options = {
"motor-gta": ( # Motor-GTA Racing
"https://www.youtube.com/watch?v=vw5L4xCPy9Q",
"bike-parkour-gta.mp4",
"Achy Gaming",
lambda t: ("center", 480 + t),
),
"rocket-league": ( # Rocket League
"https://www.youtube.com/watch?v=2X9QGY__0II",
"rocket_league.mp4",
"Orbital Gameplay",
lambda t: ("center", 200 + t),
),
"minecraft": ( # Minecraft parkour
"https://www.youtube.com/watch?v=n_Dv4JMiwK8",
"parkour.mp4",
"bbswitzer",
"center",
),
"gta": ( # GTA Stunt Race
"https://www.youtube.com/watch?v=qGa9kWREOnE",
"gta-stunt-race.mp4",
"Achy Gaming",
lambda t: ("center", 480 + t),
),
"csgo-surf": ( # CSGO Surf
"https://www.youtube.com/watch?v=E-8JlyO59Io",
"csgo-surf.mp4",
"Aki",
"center",
),
"cluster-truck": ( # Cluster Truck Gameplay
"https://www.youtube.com/watch?v=uVKxtdMgJVU",
"cluster_truck.mp4",
"No Copyright Gameplay",
lambda t: ("center", 480 + t),
),
}

@ -2,6 +2,10 @@ import os
from os.path import exists from os.path import exists
def _listdir(d): # listdir with full path
return [os.path.join(d, f) for f in os.listdir(d)]
def cleanup() -> int: def cleanup() -> int:
"""Deletes all temporary assets in assets/temp """Deletes all temporary assets in assets/temp
@ -14,14 +18,12 @@ def cleanup() -> int:
count += len(files) count += len(files)
for f in files: for f in files:
os.remove(f) os.remove(f)
try: REMOVE_DIRS = ["./assets/temp/mp3/", "./assets/temp/png/"]
for file in os.listdir("./assets/temp/mp4"): files_to_remove = list(map(_listdir, REMOVE_DIRS))
for directory in files_to_remove:
for file in directory:
count += 1 count += 1
os.remove("./assets/temp/mp4/" + file) os.remove(file)
except FileNotFoundError:
pass
for file in os.listdir("./assets/temp/mp3"):
count += 1
os.remove("./assets/temp/mp3/" + file)
return count return count
return 0 return 0

@ -167,4 +167,4 @@ If you see any prompts, that means that you have unset/incorrectly set variables
if __name__ == "__main__": if __name__ == "__main__":
check_toml(".config.template.toml", "config.toml") check_toml("utils/.config.template.toml", "config.toml")

@ -5,10 +5,11 @@ from utils import settings
from utils.console import print_substep from utils.console import print_substep
def get_subreddit_undone(submissions: list, subreddit): def get_subreddit_undone(submissions: list, subreddit, times_checked=0):
"""_summary_ """_summary_
Args: Args:
times_checked: (int): For internal use, number of times function was called
submissions (list): List of posts that are going to potentially be generated into a video submissions (list): List of posts that are going to potentially be generated into a video
subreddit (praw.Reddit.SubredditHelper): Chosen subreddit subreddit (praw.Reddit.SubredditHelper): Chosen subreddit
@ -36,13 +37,30 @@ def get_subreddit_undone(submissions: list, subreddit):
continue continue
if submission.num_comments < int(settings.config["reddit"]["thread"]["min_comments"]): if submission.num_comments < int(settings.config["reddit"]["thread"]["min_comments"]):
print_substep( print_substep(
f'This post has under the specified minimum of comments ({settings.config["reddit"]["thread"]["min_comments"]}). Skipping...' 'This post has under the specified minimum of comments'
f'({settings.config["reddit"]["thread"]["min_comments"]}). Skipping...'
) )
continue continue
return submission return submission
print("all submissions have been done going by top submission order") print("all submissions have been done going by top submission order")
VALID_TIME_FILTERS = [
"hour",
"day",
"month",
"week",
"year",
"all",
] # set doesn't have __getitem__
index = times_checked + 1 if times_checked != 0 else times_checked
if index == len(VALID_TIME_FILTERS):
print("all time filters have been checked you absolute madlad ")
return get_subreddit_undone( return get_subreddit_undone(
subreddit.top(time_filter="hour"), subreddit subreddit.top(
time_filter=VALID_TIME_FILTERS[index], limit=100
),
subreddit,
times_checked=index,
) # all the videos in hot have already been done ) # all the videos in hot have already been done

@ -0,0 +1,51 @@
from typing import Tuple
from PIL import ImageFont, Image, ImageDraw, ImageEnhance
from moviepy.video.VideoClip import VideoClip, ImageClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
class Video:
def __init__(self, video: VideoClip, *args, **kwargs):
self.video: VideoClip = video
self.fps = self.video.fps
self.duration = self.video.duration
@staticmethod
def _create_watermark(text, fontsize, opacity=0.5):
path = "./assets/temp/png/watermark.png"
width = int(fontsize * len(text))
height = int(fontsize * len(text) / 2)
white = (255, 255, 255)
transparent = (0, 0, 0, 0)
font = ImageFont.load_default()
wm = Image.new("RGBA", (width, height), transparent)
im = Image.new("RGBA", (width, height), transparent) # Change this line too.
draw = ImageDraw.Draw(wm)
w, h = draw.textsize(text, font)
draw.text(((width - w) / 2, (height - h) / 2), text, white, font)
en = ImageEnhance.Brightness(wm) # TODO allow it to use the fontsize
mask = en.enhance(1 - opacity)
im.paste(wm, (25, 25), mask)
im.save(path)
return ImageClip(path)
def add_watermark(
self, text, opacity=0.5, duration: int | float = 5, position: Tuple = (0.7, 0.9), fontsize=15
):
compensation = round(
(position[0] / ((len(text) * (fontsize / 5) / 1.5) / 100 + position[0] * position[0])),
ndigits=2,
)
position = (compensation, position[1])
img_clip = self._create_watermark(text, opacity=opacity, fontsize=fontsize)
img_clip = img_clip.set_opacity(opacity).set_duration(duration)
img_clip = img_clip.set_position(
position, relative=True
) # TODO get data from utils/CONSTANTS.py and adapt position accordingly
# Overlay the img clip on the first video clip
self.video = CompositeVideoClip([self.video, img_clip])
return self.video

@ -10,42 +10,9 @@ from pytube import YouTube
from pytube.cli import on_progress from pytube.cli import on_progress
from utils import settings from utils import settings
from utils.CONSTANTS import background_options
from utils.console import print_step, print_substep from utils.console import print_step, print_substep
# Supported Background. Can add/remove background video here....
# <key>-<value> : key -> used as keyword for TOML file. value -> background configuration
# Format (value):
# 1. Youtube URI
# 2. filename
# 3. Citation (owner of the video)
# 4. Position of image clips in the background. See moviepy reference for more information. (https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.set_position)
background_options = {
"motor-gta": ( # Motor-GTA Racing
"https://www.youtube.com/watch?v=vw5L4xCPy9Q",
"bike-parkour-gta.mp4",
"Achy Gaming",
lambda t: ("center", 480 + t),
),
"rocket-league": ( # Rocket League
"https://www.youtube.com/watch?v=2X9QGY__0II",
"rocket_league.mp4",
"Orbital Gameplay",
lambda t: ("center", 200 + t),
),
"minecraft": ( # Minecraft parkour
"https://www.youtube.com/watch?v=n_Dv4JMiwK8",
"parkour.mp4",
"bbswitzer",
"center",
),
"gta": ( # GTA Stunt Race
"https://www.youtube.com/watch?v=qGa9kWREOnE",
"gta-stunt-race.mp4",
"Achy Gaming",
lambda t: ("center", 480 + t),
),
}
def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]: def get_start_and_end_times(video_length: int, length_of_clip: int) -> Tuple[int, int]:
"""Generates a random interval of time to be used as the background of the video. """Generates a random interval of time to be used as the background of the video.
@ -92,7 +59,7 @@ def download_background(background_config: Tuple[str, str, str, Any]):
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(
"assets/backgrounds", filename=f"{credit}-{filename}" "assets/backgrounds", filename=f"{credit}-{filename}"
) )
print_substep("Background videos downloaded successfully! 🎉", style="bold green") print_substep("Background video downloaded successfully! 🎉", style="bold green")
def chop_background_video(background_config: Tuple[str, str, str, Any], video_length: int): def chop_background_video(background_config: Tuple[str, str, str, Any], video_length: int):

@ -18,6 +18,7 @@ from rich.progress import track
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.videos import save_data from utils.videos import save_data
from utils import settings from utils import settings
from video_creation.background import download_background, chop_background_video from video_creation.background import download_background, chop_background_video
@ -171,6 +172,8 @@ def make_final_video(
# .set_opacity(float(opacity)), # .set_opacity(float(opacity)),
# ) # )
# else: story mode stuff # else: story mode stuff
# Can't use concatenate_videoclips here, it resets clips' start point
image_concat = CompositeVideoClip(image_clips).set_position(background_config[3]) image_concat = CompositeVideoClip(image_clips).set_position(background_config[3])
download_background(background_config) download_background(background_config)
@ -219,6 +222,18 @@ def make_final_video(
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.makedirs(f'./results/{subreddit}') os.makedirs(f'./results/{subreddit}')
# if settings.config["settings"]['background']["background_audio"] and exists(f"assets/backgrounds/background.mp3"):
# audioclip = mpe.AudioFileClip(f"assets/backgrounds/background.mp3").set_duration(final.duration)
# audioclip = audioclip.fx( volumex, 0.2)
# final_audio = mpe.CompositeAudioClip([final.audio, audioclip])
# # lowered_audio = audio_background.multiply_volume( # todo get this to work
# # VOLUME_MULTIPLIER) # lower volume by background_audio_volume, use with fx
# final.set_audio(final_audio)
final = Video(final).add_watermark(
text=f"Background credit: {background_config[2]}", opacity=0.4
)
final.write_videofile( final.write_videofile(
'assets/temp/temp.mp4', 'assets/temp/temp.mp4',
fps=30, fps=30,

Loading…
Cancel
Save