commit
3eff3e4386
@ -0,0 +1,30 @@
|
||||
# Import the server module
|
||||
import http.server
|
||||
import webbrowser
|
||||
# Set the hostname
|
||||
HOST = "localhost"
|
||||
# Set the port number
|
||||
PORT = 4000
|
||||
|
||||
# Define class to display the index page of the web server
|
||||
class PythonServer(http.server.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
if self.path == '/GUI':
|
||||
self.path = 'index.html'
|
||||
return http.server.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
# Declare object of the class
|
||||
webServer = http.server.HTTPServer((HOST, PORT), PythonServer)
|
||||
# Print the URL of the webserver, new =2 opens in a new tab
|
||||
print(f"Server started at http://{HOST}:{PORT}/GUI/")
|
||||
webbrowser.open(f'http://{HOST}:{PORT}/GUI/', new = 2)
|
||||
print("Website opened in new tab")
|
||||
print("Press Ctrl+C to quit")
|
||||
try:
|
||||
# Run the web server
|
||||
webServer.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
# Stop the web server
|
||||
webServer.server_close()
|
||||
print("The server is stopped.")
|
||||
exit()
|
@ -0,0 +1,42 @@
|
||||
import random
|
||||
import pyttsx3
|
||||
from utils import settings
|
||||
|
||||
|
||||
class pyttsx:
|
||||
def __init__(self):
|
||||
self.max_chars = 5000
|
||||
self.voices = []
|
||||
|
||||
def run(
|
||||
self,
|
||||
text: str,
|
||||
filepath: str,
|
||||
random_voice=False,
|
||||
):
|
||||
voice_id = settings.config["settings"]["tts"]["python_voice"]
|
||||
voice_num = settings.config["settings"]["tts"]["py_voice_num"]
|
||||
if voice_id == "" or voice_num == "":
|
||||
voice_id = 2
|
||||
voice_num = 3
|
||||
raise ValueError(
|
||||
"set pyttsx values to a valid value, switching to defaults"
|
||||
)
|
||||
else:
|
||||
voice_id = int(voice_id)
|
||||
voice_num = int(voice_num)
|
||||
for i in range(voice_num):
|
||||
self.voices.append(i)
|
||||
i = +1
|
||||
if random_voice:
|
||||
voice_id = self.randomvoice()
|
||||
engine = pyttsx3.init()
|
||||
voices = engine.getProperty("voices")
|
||||
engine.setProperty(
|
||||
"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.runAndWait()
|
||||
|
||||
def randomvoice(self):
|
||||
return random.choice(self.voices)
|
@ -0,0 +1,10 @@
|
||||
import pyttsx3
|
||||
|
||||
engine = pyttsx3.init()
|
||||
voices = engine.getProperty("voices")
|
||||
for voice in voices:
|
||||
print(voice, voice.id)
|
||||
engine.setProperty("voice", voice.id)
|
||||
engine.say("Hello World!")
|
||||
engine.runAndWait()
|
||||
engine.stop()
|
@ -1,45 +1,39 @@
|
||||
[reddit.creds]
|
||||
client_id = { optional = false, nmin = 12, nmax = 30, explanation = "the ID of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The ID should be over 12 and under 30 characters, double check your input." }
|
||||
client_secret = { optional = false, nmin = 20, nmax = 40, explanation = "the SECRET of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The secret should be over 20 and under 40 characters, double check your input." }
|
||||
username = { optional = false, nmin = 3, nmax = 20, explanation = "the username of your reddit account", example = "JasonLovesDoggo", regex = "^[-_0-9a-zA-Z]+$", oob_error = "A username HAS to be between 3 and 20 characters" }
|
||||
password = { optional = false, nmin = 8, explanation = "the password of your reddit account", example = "fFAGRNJru1FTz70BzhT3Zg", oob_error = "Password too short" }
|
||||
2fa = { optional = true, type = "bool", options = [true,
|
||||
false,
|
||||
], default = false, explanation = "Whether you have Reddit 2FA enabled, Valid options are True and False", example = true }
|
||||
client_id = { optional = false, nmin = 12, nmax = 30, explanation = "The ID of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The ID should be over 12 and under 30 characters, double check your input." }
|
||||
client_secret = { optional = false, nmin = 20, nmax = 40, explanation = "The SECRET of your Reddit app of SCRIPT type", example = "fFAGRNJru1FTz70BzhT3Zg", regex = "^[-a-zA-Z0-9._~+/]+=*$", input_error = "The client ID can only contain printable characters.", oob_error = "The secret should be over 20 and under 40 characters, double check your input." }
|
||||
username = { optional = false, nmin = 3, nmax = 20, explanation = "The username of your reddit account", example = "JasonLovesDoggo", regex = "^[-_0-9a-zA-Z]+$", oob_error = "A username HAS to be between 3 and 20 characters" }
|
||||
password = { optional = false, nmin = 8, explanation = "The password of your reddit account", example = "fFAGRNJru1FTz70BzhT3Zg", oob_error = "Password too short" }
|
||||
2fa = { optional = true, type = "bool", options = [true, false,], default = false, explanation = "Whether you have Reddit 2FA enabled, Valid options are True and False", example = true }
|
||||
|
||||
|
||||
[reddit.thread]
|
||||
random = { optional = true, options = [true,
|
||||
false,
|
||||
], default = false, type = "bool", explanation = "If set to no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: 'False'", example = "True" }
|
||||
subreddit = { optional = false, regex = "[_0-9a-zA-Z]+$", nmin = 3, explanation = "what subreddit to pull posts from, the name of the sub, not the URL", example = "AskReddit", oob_error = "A subreddit name HAS to be between 3 and 20 characters" }
|
||||
post_id = { optional = true, default = "", regex = "^((?!://|://)[+a-zA-Z])*$", explanation = "Used if you want to use a specific post.", example = "urdtfx" }
|
||||
random = { optional = true, options = [true, false,], default = false, type = "bool", explanation = "If set to no, it will ask you a thread link to extract the thread, if yes it will randomize it. Default: 'False'", example = "True" }
|
||||
subreddit = { optional = false, regex = "[_0-9a-zA-Z]+$", nmin = 3, explanation = "What subreddit to pull posts from, the name of the sub, not the URL", example = "AskReddit", oob_error = "A subreddit name HAS to be between 3 and 20 characters" }
|
||||
post_id = { optional = true, default = "", regex = "^((?!://|://)[+a-zA-Z0-9])*$", explanation = "Used if you want to use a specific post.", example = "urdtfx" }
|
||||
max_comment_length = { default = 500, optional = false, nmin = 10, nmax = 10000, type = "int", explanation = "max number of characters a comment can have. default is 500", example = 500, oob_error = "the max comment length should be between 10 and 10000" }
|
||||
post_lang = { default = "", optional = true, explanation = "The language you would like to translate to.", example = "es-cr" }
|
||||
min_comments = { default = 20, optional = false, nmin = 15, type = "int", explanation = "The minimum number of comments a post should have to be included. default is 20", example = 29, oob_error = "the minimum number of comments should be between 15 and 999999" }
|
||||
|
||||
|
||||
[settings]
|
||||
allow_nsfw = { optional = false, type = "bool", default = false, example = false, options = [true,
|
||||
false,
|
||||
], explanation = "Whether to allow NSFW content, True or False" }
|
||||
theme = { optional = false, default = "dark", example = "light", options = ["dark",
|
||||
"light",
|
||||
], explanation = "sets the Reddit theme, either LIGHT or DARK" }
|
||||
times_to_run = { optional = false, default = 1, example = 2, explanation = "used if you want to run multiple times. set to an int e.g. 4 or 29 or 1", type = "int", nmin = 1, oob_error = "It's very hard to run something less than once." }
|
||||
allow_nsfw = { optional = false, type = "bool", default = false, example = false, options = [true, false,], explanation = "Whether to allow NSFW content, True or False" }
|
||||
theme = { optional = false, default = "dark", example = "light", options = ["dark", "light",], explanation = "Sets the Reddit theme, either LIGHT or DARK" }
|
||||
times_to_run = { optional = false, default = 1, example = 2, explanation = "Used if you want to run multiple times. Set to an int e.g. 4 or 29 or 1", type = "int", nmin = 1, oob_error = "It's very hard to run something less than once." }
|
||||
opacity = { optional = false, default = 0.9, example = 0.8, explanation = "Sets the opacity of the comments when overlayed over the background", type = "float", nmin = 0, nmax = 1, oob_error = "The opacity HAS to be between 0 and 1", input_error = "The opacity HAS to be a decimal number between 0 and 1" }
|
||||
storymode = { optional = true, type = "bool", default = false, example = false, options = [true,
|
||||
false,
|
||||
], explanation = "not yet implemented" }
|
||||
transition = { optional = true, default = 0.2, example = 0.2, explanation = "Sets the transition time (in seconds) between the comments. Set to 0 if you want to disable it.", type = "float", nmin = 0, nmax = 2, oob_error = "The transition HAS to be between 0 and 2", input_error = "The opacity HAS to be a decimal number between 0 and 2" }
|
||||
storymode = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Only read out title and post content, not yet implemented" }
|
||||
|
||||
|
||||
[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_audio = { optional = true, type = "bool", default = false, example = false, options = [true,
|
||||
# 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.)" }
|
||||
background_choice = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", ""], explanation = "Sets the background for the video based on game name" }
|
||||
#background_audio = { optional = true, type = "bool", default = false, example = false, options = [true, false,], explanation = "Sets a audio to play in the background (put a background.mp3 file in the assets/backgrounds directory for it to be used.)" }
|
||||
#background_audio_volume = { optional = true, type = "float", default = 0.3, example = 0.1, explanation="Sets the volume of the background audio. only used if the background_audio is also set to true" }
|
||||
|
||||
|
||||
[settings.tts]
|
||||
choice = { optional = false, default = "", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", ], example = "streamlabspolly", explanation = "The backend used for TTS generation. This can be left blank and you will be prompted to choose at runtime." }
|
||||
voice_choice = { optional = false, default = "", options = ["streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx",], example = "tiktok", explanation = "The voice platform used for TTS generation. This can be left blank and you will be prompted to choose at runtime." }
|
||||
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" }
|
||||
streamlabs_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for Streamlabs Polly" }
|
||||
tiktok_voice = { optional = false, default = "en_us_006", example = "en_us_006", explanation = "The voice used for TikTok TTS" }
|
||||
python_voice = {optional = false, default = "1", example = "1", explanation = "The index of the system tts voices (can be downloaded externally, run ptt.py to find value, start from zero)"}
|
||||
py_voice_num = {optional = false, default = "2", example = "2", explanation= "the number of system voices(2 are pre-installed in windows)"}
|
@ -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),
|
||||
),
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
from __future__ import annotations
|
||||
|
||||
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])
|
||||
# print(f'{compensation=}')
|
||||
# print(f'{position=}')
|
||||
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 dara 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
|
@ -1 +1 @@
|
||||
[]
|
||||
[]
|
Loading…
Reference in new issue