parent
adb12549ff
commit
ce63c9316d
@ -1,128 +1,431 @@
|
|||||||
import json
|
from main import main, shutdown
|
||||||
import re
|
|
||||||
import webbrowser
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Used "tomlkit" instead of "toml" because it doesn't change formatting on "dump"
|
from doctest import master
|
||||||
import tomlkit
|
import tkinter
|
||||||
from flask import (
|
import tkinter.messagebox
|
||||||
Flask,
|
import customtkinter
|
||||||
flash,
|
from utils.settings import settings
|
||||||
redirect,
|
|
||||||
render_template,
|
customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light"
|
||||||
request,
|
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
|
||||||
send_from_directory,
|
|
||||||
url_for,
|
|
||||||
|
class App(customtkinter.CTk):
|
||||||
|
|
||||||
|
WIDTH = 1200
|
||||||
|
HEIGHT = 600
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.title("Reddit Video Maker Bot GUI")
|
||||||
|
self.geometry(f"{App.WIDTH}x{App.HEIGHT}")
|
||||||
|
self.resizable(False, False)
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
||||||
|
self.resizable(False, False)
|
||||||
|
|
||||||
|
# ============ create two frames ============
|
||||||
|
|
||||||
|
# configure grid layout (2x1)
|
||||||
|
self.grid_columnconfigure(1, weight=1)
|
||||||
|
self.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
|
self.frame_left = customtkinter.CTkFrame(master=self,
|
||||||
|
width=180,
|
||||||
|
corner_radius=0)
|
||||||
|
self.frame_left.grid(row=0, column=0, sticky="nswe")
|
||||||
|
|
||||||
|
# Results Frame
|
||||||
|
self.frame_results = customtkinter.CTkFrame(master=self)
|
||||||
|
self.frame_results.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
||||||
|
|
||||||
|
# Settings Frame
|
||||||
|
self.frame_settings = customtkinter.CTkFrame(master=self)
|
||||||
|
self.frame_settings.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
||||||
|
|
||||||
|
# Home Frame
|
||||||
|
self.frame_home = customtkinter.CTkFrame(master=self)
|
||||||
|
self.frame_home.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
||||||
|
|
||||||
|
# ============ frame_left ============
|
||||||
|
|
||||||
|
# configure grid layout (1x11)
|
||||||
|
self.frame_left.grid_rowconfigure(0, minsize=10) # empty row with minsize as spacing
|
||||||
|
self.frame_left.grid_rowconfigure(5, weight=1) # empty row as spacing
|
||||||
|
self.frame_left.grid_rowconfigure(8, minsize=20) # empty row with minsize as spacing
|
||||||
|
self.frame_left.grid_rowconfigure(11, minsize=10) # empty row with minsize as spacing
|
||||||
|
|
||||||
|
self.label_1 = customtkinter.CTkLabel(master=self.frame_left,
|
||||||
|
text="Reddit Video Maker Bot",
|
||||||
|
text_font=("Roboto Medium", -16)) # font name and size in px
|
||||||
|
self.label_1.grid(row=1, column=0, pady=10, padx=10)
|
||||||
|
|
||||||
|
# Home Btn
|
||||||
|
self.home_btn = customtkinter.CTkButton(master=self.frame_left,
|
||||||
|
text="Home",
|
||||||
|
command=self.btn_home)
|
||||||
|
self.home_btn.grid(row=2, column=0, pady=10, padx=20)
|
||||||
|
|
||||||
|
# Settings Btn
|
||||||
|
self.settings_btn = customtkinter.CTkButton(master=self.frame_left,
|
||||||
|
text="Settings",
|
||||||
|
command=self.btn_settings)
|
||||||
|
self.settings_btn.grid(row=3, column=0, pady=10, padx=20)
|
||||||
|
|
||||||
|
# Results Btn
|
||||||
|
self.results_btn = customtkinter.CTkButton(master=self.frame_left,
|
||||||
|
text="Results",
|
||||||
|
command=self.btn_results)
|
||||||
|
self.results_btn.grid(row=4, column=0, pady=10, padx=20)
|
||||||
|
|
||||||
|
# Start Btn
|
||||||
|
self.start_btn = customtkinter.CTkButton(master=self.frame_left,
|
||||||
|
text="Start",
|
||||||
|
command=self.btn_start)
|
||||||
|
self.start_btn.grid(row=5, column=0, pady=10, padx=40)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Appeareance Stuff
|
||||||
|
self.label_mode = customtkinter.CTkLabel(master=self.frame_left, text="Appearance Mode:")
|
||||||
|
self.label_mode.grid(row=9, column=0, pady=10, padx=20, sticky="w")
|
||||||
|
|
||||||
|
self.optionmenu_1 = customtkinter.CTkOptionMenu(master=self.frame_left,
|
||||||
|
values=["Light", "Dark", "System"],
|
||||||
|
command=self.change_appearance_mode)
|
||||||
|
self.optionmenu_1.grid(row=10, column=0, pady=0, padx=20, sticky="w")
|
||||||
|
|
||||||
|
### Adds all the stuff for frame_settings ###
|
||||||
|
|
||||||
|
# Background within frame
|
||||||
|
self.frame_bg_settings = customtkinter.CTkFrame(master=self.frame_settings)
|
||||||
|
self.frame_bg_settings.grid(row=0, column=0, pady=15, padx=15, sticky=("nswe"))
|
||||||
|
|
||||||
|
self.frame_bg_settings.rowconfigure(10, weight=1)
|
||||||
|
self.frame_bg_settings.columnconfigure(10, weight=1)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
self.settings_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Settings",
|
||||||
|
text_font=("Courier_Bold", 24)
|
||||||
|
)
|
||||||
|
self.settings_title.grid(row=0, column=0, columnspan=8, pady=15, padx=15)
|
||||||
|
|
||||||
|
## USER SETTINGS ##
|
||||||
|
|
||||||
|
# User settings title
|
||||||
|
self.user_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="User Settings",
|
||||||
|
text_font=("Courier_Bold", 14)
|
||||||
|
)
|
||||||
|
self.user_title.grid(row=1, column=0, columnspan=2, pady=10)
|
||||||
|
|
||||||
|
# Client secret title
|
||||||
|
self.client_secret_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Client Secrect"
|
||||||
|
)
|
||||||
|
self.client_secret_title.grid(row=2, column=0, padx=15)
|
||||||
|
|
||||||
|
# Client secret input box
|
||||||
|
self.client_secret = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text = "Client Secret"
|
||||||
)
|
)
|
||||||
|
self.client_secret.grid(row=3, column=0, padx=15)
|
||||||
|
|
||||||
# Set the hostname
|
# Client id title
|
||||||
HOST = "localhost"
|
self.client_id_title = customtkinter.CTkLabel(
|
||||||
# Set the port number
|
master=self.frame_bg_settings,
|
||||||
PORT = 4000
|
text = "Client Id"
|
||||||
|
)
|
||||||
|
self.client_id_title.grid(row=4, column=0, padx=15)
|
||||||
|
|
||||||
# Configure application
|
# Client id input box
|
||||||
app = Flask(__name__, template_folder="GUI")
|
self.client_id = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Client Id"
|
||||||
|
)
|
||||||
|
self.client_id.grid(row=5, column=0, padx=15)
|
||||||
|
|
||||||
# Configure secret key only to use 'flash'
|
# Username title
|
||||||
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
|
self.user_name_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Username"
|
||||||
|
)
|
||||||
|
self.user_name_title.grid(row=2, column=1, padx=15)
|
||||||
|
|
||||||
|
# Username input box
|
||||||
|
self.user_name = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Username"
|
||||||
|
)
|
||||||
|
self.user_name.grid(row=3, column=1, padx=15)
|
||||||
|
|
||||||
# Ensure responses aren't cached
|
# Password title
|
||||||
@app.after_request
|
self.user_password_title = customtkinter.CTkLabel(
|
||||||
def after_request(response):
|
master=self.frame_bg_settings,
|
||||||
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
text="Password"
|
||||||
response.headers["Expires"] = 0
|
)
|
||||||
response.headers["Pragma"] = "no-cache"
|
self.user_password_title.grid(row=4, column=1, padx=15)
|
||||||
return response
|
|
||||||
|
|
||||||
|
# Password input box
|
||||||
|
self.user_password = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Password"
|
||||||
|
)
|
||||||
|
self.user_password.grid(row=5, column=1, padx=15)
|
||||||
|
|
||||||
# Display index.html
|
# 2fa label
|
||||||
@app.route("/")
|
self.user_2fa_label = customtkinter.CTkLabel(
|
||||||
def index():
|
master=self.frame_bg_settings,
|
||||||
return render_template("index.html")
|
text = "2FA enabled?"
|
||||||
|
)
|
||||||
|
self.user_2fa_label.grid(row=6, column=0, padx=15)
|
||||||
|
|
||||||
|
# 2fa option menu
|
||||||
|
self.user_2fa = customtkinter.CTkOptionMenu(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
values=["false", "true"]
|
||||||
|
)
|
||||||
|
self.user_2fa.grid(row=7, column=0, padx=15)
|
||||||
|
|
||||||
# Make videos.json accessible
|
# Thread Settings
|
||||||
@app.route("/videos.json")
|
|
||||||
def videos_json():
|
|
||||||
return send_from_directory("video_creation/data", "videos.json")
|
|
||||||
|
|
||||||
|
# Thread settings title
|
||||||
|
self.thread_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Thread Settings",
|
||||||
|
text_font=("Courier_Bold", 14)
|
||||||
|
)
|
||||||
|
self.thread_title.grid(row=1, column=2, columnspan=2, pady=10)
|
||||||
|
|
||||||
# Make videos in results folder accessible
|
# Random Title
|
||||||
@app.route("/results/<path:name>")
|
self.thread_random_title = customtkinter.CTkLabel(
|
||||||
def results(name):
|
master=self.frame_bg_settings,
|
||||||
return send_from_directory("results", name, as_attachment=True)
|
text="Random"
|
||||||
|
)
|
||||||
|
self.thread_random_title.grid(row=2, column=2, padx=15)
|
||||||
|
|
||||||
|
# Random option menu
|
||||||
|
self.thread_random = customtkinter.CTkOptionMenu(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
values=["false", "true"]
|
||||||
|
)
|
||||||
|
self.thread_random.grid(row=3, column=2, padx=15)
|
||||||
|
|
||||||
@app.route("/add_background", methods=["POST"])
|
# Subreddit title
|
||||||
def add_background():
|
self.thread_subreddit_title = customtkinter.CTkLabel(
|
||||||
# Get form values
|
master=self.frame_bg_settings,
|
||||||
youtube_uri = request.form.get("youtube_uri").strip()
|
text="Subreddit"
|
||||||
filename = request.form.get("filename").strip()
|
)
|
||||||
citation = request.form.get("citation").strip()
|
self.thread_subreddit_title.grid(row=2, column=3, padx=15)
|
||||||
position = request.form.get("position").strip()
|
|
||||||
|
|
||||||
# Validate YouTube URI
|
# Subreddit input box
|
||||||
regex = re.compile(
|
self.thread_subreddit = customtkinter.CTkEntry(
|
||||||
r"(?:\/|%3D|v=|vi=)([0-9A-z-_]{11})(?:[%#?&]|$)"
|
master=self.frame_bg_settings,
|
||||||
).search(youtube_uri)
|
placeholder_text="Subreddit"
|
||||||
|
)
|
||||||
|
self.thread_subreddit.grid(row=3, column=3, padx=15)
|
||||||
|
|
||||||
if not regex:
|
# Post id title
|
||||||
flash("YouTube URI is invalid!", "error")
|
self.thread_post_id_title = customtkinter.CTkLabel(
|
||||||
return redirect(url_for("index"))
|
master=self.frame_bg_settings,
|
||||||
|
text="Post Id"
|
||||||
|
)
|
||||||
|
self.thread_post_id_title.grid(row=4, column=2, padx=15)
|
||||||
|
|
||||||
youtube_uri = f"https://www.youtube.com/watch?v={regex.group(1)}"
|
# Post id input box
|
||||||
|
self.thread_post_id = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Post Id"
|
||||||
|
)
|
||||||
|
self.thread_post_id.grid(row=5, column=2, padx=15)
|
||||||
|
|
||||||
# Check if position is valid
|
# Max comment length title
|
||||||
if position == "" or position == "center":
|
self.thread_max_comment_length_title = customtkinter.CTkLabel(
|
||||||
position = "center"
|
master=self.frame_bg_settings,
|
||||||
|
text="Max comment length"
|
||||||
|
)
|
||||||
|
self.thread_max_comment_length_title.grid(row=4, column=3, padx=15)
|
||||||
|
|
||||||
elif position.isdecimal():
|
# Max comment length
|
||||||
position = int(position)
|
self.thread_max_comment_length = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Max comment length (NUM)"
|
||||||
|
)
|
||||||
|
self.thread_max_comment_length.grid(row=5, column=3, padx=15)
|
||||||
|
|
||||||
|
# Post lang title
|
||||||
|
self.thread_post_lang_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Post language"
|
||||||
|
)
|
||||||
|
self.thread_post_lang_title.grid(row=6, column=2, padx=15)
|
||||||
|
|
||||||
else:
|
# Post lang
|
||||||
flash('Position is invalid! It can be "center" or decimal number.', "error")
|
self.thread_post_lang = customtkinter.CTkEntry(
|
||||||
return redirect(url_for("index"))
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Post language (en/cr)"
|
||||||
|
)
|
||||||
|
self.thread_post_lang.grid(row=7, column=2, padx=15)
|
||||||
|
|
||||||
# Sanitize filename
|
# Min comment length title
|
||||||
filename = filename.replace(" ", "-").split(".")[0]
|
self.thread_min_comment_length_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Min comment length (NUM)"
|
||||||
|
)
|
||||||
|
self.thread_min_comment_length_title.grid(row=6, column=3, padx=15)
|
||||||
|
|
||||||
# Check if background doesn't already exist
|
# Min comment length
|
||||||
with open("utils/backgrounds.json", "r", encoding="utf-8") as backgrounds:
|
self.thread_min_comment_length = customtkinter.CTkEntry(
|
||||||
data = json.load(backgrounds)
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Min comment length"
|
||||||
|
)
|
||||||
|
self.thread_min_comment_length.grid(row=7, column=3, padx=15)
|
||||||
|
|
||||||
# Check if key isn't already taken
|
# Misc Settings
|
||||||
if filename in list(data.keys()):
|
|
||||||
flash("Background video with this name already exist!", "error")
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
|
|
||||||
# Check if the YouTube URI isn't already used under different name
|
# Misc settings title
|
||||||
if youtube_uri in [data[i][0] for i in list(data.keys())]:
|
self.misc_title = customtkinter.CTkLabel(
|
||||||
flash("Background video with this YouTube URI is already added!", "error")
|
master=self.frame_bg_settings,
|
||||||
return redirect(url_for("index"))
|
text="Misc Settings",
|
||||||
|
text_font=("Courier_Bold", 14)
|
||||||
|
)
|
||||||
|
self.misc_title.grid(row=8, column=0, columnspan=2, pady=10)
|
||||||
|
|
||||||
# Add background video to json file
|
# Allow nsfw title
|
||||||
with open("utils/backgrounds.json", "r+", encoding="utf-8") as backgrounds:
|
self.misc_allow_nsfw_title = customtkinter.CTkLabel(
|
||||||
data = json.load(backgrounds)
|
master=self.frame_bg_settings,
|
||||||
|
text="Allow NSFW"
|
||||||
|
)
|
||||||
|
self.misc_allow_nsfw_title.grid(row=9, column=0, padx=15)
|
||||||
|
|
||||||
data[filename] = [youtube_uri, filename + ".mp4", citation, position]
|
# Allow nsfw option box
|
||||||
backgrounds.seek(0)
|
self.misc_allow_nsfw = customtkinter.CTkOptionMenu(
|
||||||
json.dump(data, backgrounds, ensure_ascii=False, indent=4)
|
master=self.frame_bg_settings,
|
||||||
|
values=["False", "True"]
|
||||||
|
)
|
||||||
|
self.misc_allow_nsfw.grid(row=10, column=0, padx=15)
|
||||||
|
|
||||||
# Add background video to ".config.template.toml" to make it accessible
|
# Theme title
|
||||||
config = tomlkit.loads(Path("utils/.config.template.toml").read_text())
|
self.misc_theme_title = customtkinter.CTkLabel(
|
||||||
config["settings"]["background"]["background_choice"]["options"].append(filename)
|
master=self.frame_bg_settings,
|
||||||
|
text="Theme"
|
||||||
|
)
|
||||||
|
self.misc_theme_title.grid(row=9, column=1, padx=15)
|
||||||
|
|
||||||
with Path("utils/.config.template.toml").open("w") as toml_file:
|
# Theme
|
||||||
toml_file.write(tomlkit.dumps(config))
|
self.misc_theme = customtkinter.CTkOptionMenu(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
values=["dark", "light"]
|
||||||
|
)
|
||||||
|
self.misc_theme.grid(row=10, column=1, padx=15)
|
||||||
|
|
||||||
flash(f'Added "{citation}-{filename}.mp4" as a new background video!')
|
# Times to run title
|
||||||
|
self.misc_times_to_run_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Times to run (NUM)"
|
||||||
|
)
|
||||||
|
self.misc_times_to_run_title.grid(row=11, column=0, padx=15)
|
||||||
|
|
||||||
return redirect(url_for("index"))
|
# Times to run
|
||||||
|
self.misc_times_to_run = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Times to run"
|
||||||
|
)
|
||||||
|
self.misc_times_to_run.grid(row=12, column=0, padx=15)
|
||||||
|
|
||||||
|
# Opacity title
|
||||||
|
self.misc_opacity_title = customtkinter.CTkLabel(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
text="Opacity (NUM 0.1-0.9)"
|
||||||
|
)
|
||||||
|
self.misc_opacity_title.grid(row=11, column=1, padx=15)
|
||||||
|
|
||||||
# Run browser and start the app
|
# Opcaity
|
||||||
|
self.misc_opacity = customtkinter.CTkEntry(
|
||||||
|
master=self.frame_bg_settings,
|
||||||
|
placeholder_text="Opacity"
|
||||||
|
)
|
||||||
|
self.misc_opacity.grid(row=12, column=1, padx=15)
|
||||||
|
|
||||||
|
|
||||||
|
# configure grid layout (3x7)
|
||||||
|
|
||||||
|
self.frame_info = customtkinter.CTkFrame(master=self.frame_home)
|
||||||
|
self.frame_info.grid(row=0, column=0, columnspan=2, rowspan=4, pady=20, padx=20, sticky="nsew")
|
||||||
|
|
||||||
|
# ============ frame_info ============
|
||||||
|
|
||||||
|
# configure grid layout (1x1)
|
||||||
|
self.frame_info.rowconfigure(0, weight=1)
|
||||||
|
self.frame_info.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
self.label_info_1 = customtkinter.CTkLabel(master=self.frame_info,
|
||||||
|
text="Thanks for using this tool! \n" +
|
||||||
|
"Feel free to contribute to this project on GitHub!\n"+
|
||||||
|
"If you have any questions, feel free to reach out to\nme on Twitter or submit a GitHub issue. \n"+
|
||||||
|
"You can find solutions to many common problems in the Documentation\nhttps://reddit-video-maker-bot.netlify.app/" ,
|
||||||
|
height=100,
|
||||||
|
corner_radius=6, # <- custom corner radius
|
||||||
|
fg_color=("white", "gray38"), # <- custom tuple-color
|
||||||
|
justify=tkinter.LEFT)
|
||||||
|
self.label_info_1.grid(column=0, row=0, sticky="nwe", padx=15, pady=15)
|
||||||
|
|
||||||
|
self.progressbar = customtkinter.CTkProgressBar(master=self.frame_info)
|
||||||
|
self.progressbar.grid(row=1, column=0, sticky="ew", padx=15, pady=15)
|
||||||
|
|
||||||
|
|
||||||
|
# set default values
|
||||||
|
self.optionmenu_1.set("Dark")
|
||||||
|
###self.button_3.configure(state="disabled", text="Disabled CTkButton")
|
||||||
|
###self.combobox_1.set("CTkCombobox")
|
||||||
|
###self.radio_button_1.select()
|
||||||
|
###self.slider_1.set(0.2)
|
||||||
|
###self.slider_2.set(0.7)
|
||||||
|
###self.progressbar.set(0.5)
|
||||||
|
###self.switch_2.select()
|
||||||
|
###self.radio_button_3.configure(state=tkinter.DISABLED)
|
||||||
|
###self.check_box_1.configure(state=tkinter.DISABLED, text="CheckBox disabled")
|
||||||
|
###self.check_box_2.select()
|
||||||
|
|
||||||
|
def load_value_from_toml(self):
|
||||||
|
self.client_secret.set(config["settings"]["times_to_run"])
|
||||||
|
# Show frame
|
||||||
|
def showFrame(self, frame):
|
||||||
|
frame.tkraise()
|
||||||
|
|
||||||
|
# Home button event
|
||||||
|
def btn_home(self):
|
||||||
|
self.showFrame(self.frame_home)
|
||||||
|
|
||||||
|
# Settings button event
|
||||||
|
def btn_settings(self):
|
||||||
|
self.showFrame(self.frame_settings)
|
||||||
|
|
||||||
|
# Results button event
|
||||||
|
def btn_results(self):
|
||||||
|
print("Results Pressed!")
|
||||||
|
|
||||||
|
# Start button event
|
||||||
|
def btn_start(self):
|
||||||
|
print("Start Pressed!")
|
||||||
|
|
||||||
|
# Appearance event
|
||||||
|
def change_appearance_mode(self, new_appearance_mode):
|
||||||
|
customtkinter.set_appearance_mode(new_appearance_mode)
|
||||||
|
|
||||||
|
# Close event
|
||||||
|
def on_closing(self, event=0):
|
||||||
|
self.destroy()
|
||||||
|
shutdown()
|
||||||
|
|
||||||
|
def start():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
webbrowser.open(f"http://{HOST}:{PORT}", new=2)
|
app = App()
|
||||||
print("Website opened in new tab. Refresh if it didn't load.")
|
app.mainloop()
|
||||||
app.run(port=PORT)
|
|
||||||
|
start()
|
@ -1,428 +0,0 @@
|
|||||||
from main import main, shutdown
|
|
||||||
|
|
||||||
from doctest import master
|
|
||||||
import tkinter
|
|
||||||
import tkinter.messagebox
|
|
||||||
import customtkinter
|
|
||||||
|
|
||||||
customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light"
|
|
||||||
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
|
|
||||||
|
|
||||||
|
|
||||||
class App(customtkinter.CTk):
|
|
||||||
|
|
||||||
WIDTH = 1200
|
|
||||||
HEIGHT = 600
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.title("Reddit Video Maker Bot GUI")
|
|
||||||
self.geometry(f"{App.WIDTH}x{App.HEIGHT}")
|
|
||||||
self.resizable(False, False)
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self.on_closing) # call .on_closing() when app gets closed
|
|
||||||
self.resizable(False, False)
|
|
||||||
|
|
||||||
# ============ create two frames ============
|
|
||||||
|
|
||||||
# configure grid layout (2x1)
|
|
||||||
self.grid_columnconfigure(1, weight=1)
|
|
||||||
self.grid_rowconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.frame_left = customtkinter.CTkFrame(master=self,
|
|
||||||
width=180,
|
|
||||||
corner_radius=0)
|
|
||||||
self.frame_left.grid(row=0, column=0, sticky="nswe")
|
|
||||||
|
|
||||||
# Results Frame
|
|
||||||
self.frame_results = customtkinter.CTkFrame(master=self)
|
|
||||||
self.frame_results.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
|
||||||
|
|
||||||
# Settings Frame
|
|
||||||
self.frame_settings = customtkinter.CTkFrame(master=self)
|
|
||||||
self.frame_settings.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
|
||||||
|
|
||||||
# Home Frame
|
|
||||||
self.frame_home = customtkinter.CTkFrame(master=self)
|
|
||||||
self.frame_home.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
|
|
||||||
|
|
||||||
# ============ frame_left ============
|
|
||||||
|
|
||||||
# configure grid layout (1x11)
|
|
||||||
self.frame_left.grid_rowconfigure(0, minsize=10) # empty row with minsize as spacing
|
|
||||||
self.frame_left.grid_rowconfigure(5, weight=1) # empty row as spacing
|
|
||||||
self.frame_left.grid_rowconfigure(8, minsize=20) # empty row with minsize as spacing
|
|
||||||
self.frame_left.grid_rowconfigure(11, minsize=10) # empty row with minsize as spacing
|
|
||||||
|
|
||||||
self.label_1 = customtkinter.CTkLabel(master=self.frame_left,
|
|
||||||
text="Reddit Video Maker Bot",
|
|
||||||
text_font=("Roboto Medium", -16)) # font name and size in px
|
|
||||||
self.label_1.grid(row=1, column=0, pady=10, padx=10)
|
|
||||||
|
|
||||||
# Home Btn
|
|
||||||
self.home_btn = customtkinter.CTkButton(master=self.frame_left,
|
|
||||||
text="Home",
|
|
||||||
command=self.btn_home)
|
|
||||||
self.home_btn.grid(row=2, column=0, pady=10, padx=20)
|
|
||||||
|
|
||||||
# Settings Btn
|
|
||||||
self.settings_btn = customtkinter.CTkButton(master=self.frame_left,
|
|
||||||
text="Settings",
|
|
||||||
command=self.btn_settings)
|
|
||||||
self.settings_btn.grid(row=3, column=0, pady=10, padx=20)
|
|
||||||
|
|
||||||
# Results Btn
|
|
||||||
self.results_btn = customtkinter.CTkButton(master=self.frame_left,
|
|
||||||
text="Results",
|
|
||||||
command=self.btn_results)
|
|
||||||
self.results_btn.grid(row=4, column=0, pady=10, padx=20)
|
|
||||||
|
|
||||||
# Start Btn
|
|
||||||
self.start_btn = customtkinter.CTkButton(master=self.frame_left,
|
|
||||||
text="Start",
|
|
||||||
command=self.btn_start)
|
|
||||||
self.start_btn.grid(row=5, column=0, pady=10, padx=40)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Appeareance Stuff
|
|
||||||
self.label_mode = customtkinter.CTkLabel(master=self.frame_left, text="Appearance Mode:")
|
|
||||||
self.label_mode.grid(row=9, column=0, pady=10, padx=20, sticky="w")
|
|
||||||
|
|
||||||
self.optionmenu_1 = customtkinter.CTkOptionMenu(master=self.frame_left,
|
|
||||||
values=["Light", "Dark", "System"],
|
|
||||||
command=self.change_appearance_mode)
|
|
||||||
self.optionmenu_1.grid(row=10, column=0, pady=0, padx=20, sticky="w")
|
|
||||||
|
|
||||||
### Adds all the stuff for frame_settings ###
|
|
||||||
|
|
||||||
# Background within frame
|
|
||||||
self.frame_bg_settings = customtkinter.CTkFrame(master=self.frame_settings)
|
|
||||||
self.frame_bg_settings.grid(row=0, column=0, pady=15, padx=15, sticky=("nswe"))
|
|
||||||
|
|
||||||
self.frame_bg_settings.rowconfigure(10, weight=1)
|
|
||||||
self.frame_bg_settings.columnconfigure(10, weight=1)
|
|
||||||
|
|
||||||
# Title
|
|
||||||
self.settings_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Settings",
|
|
||||||
text_font=("Courier_Bold", 24)
|
|
||||||
)
|
|
||||||
self.settings_title.grid(row=0, column=0, columnspan=8, pady=15, padx=15)
|
|
||||||
|
|
||||||
## USER SETTINGS ##
|
|
||||||
|
|
||||||
# User settings title
|
|
||||||
self.user_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="User Settings",
|
|
||||||
text_font=("Courier_Bold", 14)
|
|
||||||
)
|
|
||||||
self.user_title.grid(row=1, column=0, columnspan=2, pady=10)
|
|
||||||
|
|
||||||
# Client secret title
|
|
||||||
self.client_secret_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Client Secrect"
|
|
||||||
)
|
|
||||||
self.client_secret_title.grid(row=2, column=0, padx=15)
|
|
||||||
|
|
||||||
# Client secret input box
|
|
||||||
self.client_secret = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text = "Client Secret"
|
|
||||||
)
|
|
||||||
self.client_secret.grid(row=3, column=0, padx=15)
|
|
||||||
|
|
||||||
# Client id title
|
|
||||||
self.client_id_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text = "Client Id"
|
|
||||||
)
|
|
||||||
self.client_id_title.grid(row=4, column=0, padx=15)
|
|
||||||
|
|
||||||
# Client id input box
|
|
||||||
self.client_id = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Client Id"
|
|
||||||
)
|
|
||||||
self.client_id.grid(row=5, column=0, padx=15)
|
|
||||||
|
|
||||||
# Username title
|
|
||||||
self.user_name_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Username"
|
|
||||||
)
|
|
||||||
self.user_name_title.grid(row=2, column=1, padx=15)
|
|
||||||
|
|
||||||
# Username input box
|
|
||||||
self.user_name = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Username"
|
|
||||||
)
|
|
||||||
self.user_name.grid(row=3, column=1, padx=15)
|
|
||||||
|
|
||||||
# Password title
|
|
||||||
self.user_password_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Password"
|
|
||||||
)
|
|
||||||
self.user_password_title.grid(row=4, column=1, padx=15)
|
|
||||||
|
|
||||||
# Password input box
|
|
||||||
self.user_password = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Password"
|
|
||||||
)
|
|
||||||
self.user_password.grid(row=5, column=1, padx=15)
|
|
||||||
|
|
||||||
# 2fa label
|
|
||||||
self.user_2fa_label = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text = "2FA enabled?"
|
|
||||||
)
|
|
||||||
self.user_2fa_label.grid(row=6, column=0, padx=15)
|
|
||||||
|
|
||||||
# 2fa option menu
|
|
||||||
self.user_2fa = customtkinter.CTkOptionMenu(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
values=["false", "true"]
|
|
||||||
)
|
|
||||||
self.user_2fa.grid(row=7, column=0, padx=15)
|
|
||||||
|
|
||||||
# Thread Settings
|
|
||||||
|
|
||||||
# Thread settings title
|
|
||||||
self.thread_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Thread Settings",
|
|
||||||
text_font=("Courier_Bold", 14)
|
|
||||||
)
|
|
||||||
self.thread_title.grid(row=1, column=2, columnspan=2, pady=10)
|
|
||||||
|
|
||||||
# Random Title
|
|
||||||
self.thread_random_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Random"
|
|
||||||
)
|
|
||||||
self.thread_random_title.grid(row=2, column=2, padx=15)
|
|
||||||
|
|
||||||
# Random option menu
|
|
||||||
self.thread_random = customtkinter.CTkOptionMenu(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
values=["false", "true"]
|
|
||||||
)
|
|
||||||
self.thread_random.grid(row=3, column=2, padx=15)
|
|
||||||
|
|
||||||
# Subreddit title
|
|
||||||
self.thread_subreddit_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Subreddit"
|
|
||||||
)
|
|
||||||
self.thread_subreddit_title.grid(row=2, column=3, padx=15)
|
|
||||||
|
|
||||||
# Subreddit input box
|
|
||||||
self.thread_subreddit = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Subreddit"
|
|
||||||
)
|
|
||||||
self.thread_subreddit.grid(row=3, column=3, padx=15)
|
|
||||||
|
|
||||||
# Post id title
|
|
||||||
self.thread_post_id_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Post Id"
|
|
||||||
)
|
|
||||||
self.thread_post_id_title.grid(row=4, column=2, padx=15)
|
|
||||||
|
|
||||||
# Post id input box
|
|
||||||
self.thread_post_id = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Post Id"
|
|
||||||
)
|
|
||||||
self.thread_post_id.grid(row=5, column=2, padx=15)
|
|
||||||
|
|
||||||
# Max comment length title
|
|
||||||
self.thread_max_comment_length_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Max comment length"
|
|
||||||
)
|
|
||||||
self.thread_max_comment_length_title.grid(row=4, column=3, padx=15)
|
|
||||||
|
|
||||||
# Max comment length
|
|
||||||
self.thread_max_comment_length = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Max comment length (NUM)"
|
|
||||||
)
|
|
||||||
self.thread_max_comment_length.grid(row=5, column=3, padx=15)
|
|
||||||
|
|
||||||
# Post lang title
|
|
||||||
self.thread_post_lang_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Post language"
|
|
||||||
)
|
|
||||||
self.thread_post_lang_title.grid(row=6, column=2, padx=15)
|
|
||||||
|
|
||||||
# Post lang
|
|
||||||
self.thread_post_lang = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Post language (en/cr)"
|
|
||||||
)
|
|
||||||
self.thread_post_lang.grid(row=7, column=2, padx=15)
|
|
||||||
|
|
||||||
# Min comment length title
|
|
||||||
self.thread_min_comment_length_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Min comment length (NUM)"
|
|
||||||
)
|
|
||||||
self.thread_min_comment_length_title.grid(row=6, column=3, padx=15)
|
|
||||||
|
|
||||||
# Min comment length
|
|
||||||
self.thread_min_comment_length = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Min comment length"
|
|
||||||
)
|
|
||||||
self.thread_min_comment_length.grid(row=7, column=3, padx=15)
|
|
||||||
|
|
||||||
# Misc Settings
|
|
||||||
|
|
||||||
# Misc settings title
|
|
||||||
self.misc_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Misc Settings",
|
|
||||||
text_font=("Courier_Bold", 14)
|
|
||||||
)
|
|
||||||
self.misc_title.grid(row=8, column=0, columnspan=2, pady=10)
|
|
||||||
|
|
||||||
# Allow nsfw title
|
|
||||||
self.misc_allow_nsfw_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Allow NSFW"
|
|
||||||
)
|
|
||||||
self.misc_allow_nsfw_title.grid(row=9, column=0, padx=15)
|
|
||||||
|
|
||||||
# Allow nsfw option box
|
|
||||||
self.misc_allow_nsfw = customtkinter.CTkOptionMenu(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
values=["False", "True"]
|
|
||||||
)
|
|
||||||
self.misc_allow_nsfw.grid(row=10, column=0, padx=15)
|
|
||||||
|
|
||||||
# Theme title
|
|
||||||
self.misc_theme_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Theme"
|
|
||||||
)
|
|
||||||
self.misc_theme_title.grid(row=9, column=1, padx=15)
|
|
||||||
|
|
||||||
# Theme
|
|
||||||
self.misc_theme = customtkinter.CTkOptionMenu(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
values=["dark", "light"]
|
|
||||||
)
|
|
||||||
self.misc_theme.grid(row=10, column=1, padx=15)
|
|
||||||
|
|
||||||
# Times to run title
|
|
||||||
self.misc_times_to_run_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Times to run (NUM)"
|
|
||||||
)
|
|
||||||
self.misc_times_to_run_title.grid(row=11, column=0, padx=15)
|
|
||||||
|
|
||||||
# Times to run
|
|
||||||
self.misc_times_to_run = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Times to run"
|
|
||||||
)
|
|
||||||
self.misc_times_to_run.grid(row=12, column=0, padx=15)
|
|
||||||
|
|
||||||
# Opacity title
|
|
||||||
self.misc_opacity_title = customtkinter.CTkLabel(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
text="Opacity (NUM 0.1-0.9)"
|
|
||||||
)
|
|
||||||
self.misc_opacity_title.grid(row=11, column=1, padx=15)
|
|
||||||
|
|
||||||
# Opcaity
|
|
||||||
self.misc_opacity = customtkinter.CTkEntry(
|
|
||||||
master=self.frame_bg_settings,
|
|
||||||
placeholder_text="Opacity"
|
|
||||||
)
|
|
||||||
self.misc_opacity.grid(row=12, column=1, padx=15)
|
|
||||||
|
|
||||||
|
|
||||||
# configure grid layout (3x7)
|
|
||||||
|
|
||||||
self.frame_info = customtkinter.CTkFrame(master=self.frame_home)
|
|
||||||
self.frame_info.grid(row=0, column=0, columnspan=2, rowspan=4, pady=20, padx=20, sticky="nsew")
|
|
||||||
|
|
||||||
# ============ frame_info ============
|
|
||||||
|
|
||||||
# configure grid layout (1x1)
|
|
||||||
self.frame_info.rowconfigure(0, weight=1)
|
|
||||||
self.frame_info.columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.label_info_1 = customtkinter.CTkLabel(master=self.frame_info,
|
|
||||||
text="Thanks for using this tool! \n" +
|
|
||||||
"Feel free to contribute to this project on GitHub!\n"+
|
|
||||||
"If you have any questions, feel free to reach out to\nme on Twitter or submit a GitHub issue. \n"+
|
|
||||||
"You can find solutions to many common problems in the Documentation\nhttps://reddit-video-maker-bot.netlify.app/" ,
|
|
||||||
height=100,
|
|
||||||
corner_radius=6, # <- custom corner radius
|
|
||||||
fg_color=("white", "gray38"), # <- custom tuple-color
|
|
||||||
justify=tkinter.LEFT)
|
|
||||||
self.label_info_1.grid(column=0, row=0, sticky="nwe", padx=15, pady=15)
|
|
||||||
|
|
||||||
self.progressbar = customtkinter.CTkProgressBar(master=self.frame_info)
|
|
||||||
self.progressbar.grid(row=1, column=0, sticky="ew", padx=15, pady=15)
|
|
||||||
|
|
||||||
|
|
||||||
# set default values
|
|
||||||
self.optionmenu_1.set("Dark")
|
|
||||||
###self.button_3.configure(state="disabled", text="Disabled CTkButton")
|
|
||||||
###self.combobox_1.set("CTkCombobox")
|
|
||||||
###self.radio_button_1.select()
|
|
||||||
###self.slider_1.set(0.2)
|
|
||||||
###self.slider_2.set(0.7)
|
|
||||||
###self.progressbar.set(0.5)
|
|
||||||
###self.switch_2.select()
|
|
||||||
###self.radio_button_3.configure(state=tkinter.DISABLED)
|
|
||||||
###self.check_box_1.configure(state=tkinter.DISABLED, text="CheckBox disabled")
|
|
||||||
###self.check_box_2.select()
|
|
||||||
|
|
||||||
# Show frame
|
|
||||||
def showFrame(self, frame):
|
|
||||||
frame.tkraise()
|
|
||||||
|
|
||||||
# Home button event
|
|
||||||
def btn_home(self):
|
|
||||||
self.showFrame(self.frame_home)
|
|
||||||
|
|
||||||
# Settings button event
|
|
||||||
def btn_settings(self):
|
|
||||||
self.showFrame(self.frame_settings)
|
|
||||||
|
|
||||||
# Results button event
|
|
||||||
def btn_results(self):
|
|
||||||
print("Results Pressed!")
|
|
||||||
|
|
||||||
# Start button event
|
|
||||||
def btn_start(self):
|
|
||||||
print("Start Pressed!")
|
|
||||||
|
|
||||||
# Appearance event
|
|
||||||
def change_appearance_mode(self, new_appearance_mode):
|
|
||||||
customtkinter.set_appearance_mode(new_appearance_mode)
|
|
||||||
|
|
||||||
# Close event
|
|
||||||
def on_closing(self, event=0):
|
|
||||||
self.destroy()
|
|
||||||
shutdown()
|
|
||||||
|
|
||||||
def start():
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = App()
|
|
||||||
app.mainloop()
|
|
||||||
|
|
||||||
start()
|
|
@ -1,404 +0,0 @@
|
|||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta http-equiv="cache-control" content="no-cache" />
|
|
||||||
<title>RedditVideoMakerBot</title>
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css"
|
|
||||||
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
|
||||||
<link href="https://getbootstrap.com/docs/5.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bd-placeholder-img {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
text-anchor: middle;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.bd-placeholder-img-lg {
|
|
||||||
font-size: 3.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-example-divider {
|
|
||||||
height: 3rem;
|
|
||||||
background-color: rgba(0, 0, 0, .1);
|
|
||||||
border: solid rgba(0, 0, 0, .15);
|
|
||||||
border-width: 1px 0;
|
|
||||||
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-example-vr {
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bi {
|
|
||||||
vertical-align: -.125em;
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-scroller {
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
height: 2.75rem;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-scroller .nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
margin-top: -1px;
|
|
||||||
overflow-x: auto;
|
|
||||||
text-align: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tooltip {
|
|
||||||
background-color: #333;
|
|
||||||
color: white;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
{% if get_flashed_messages() %}
|
|
||||||
{% for category, message in get_flashed_messages(with_categories=true) %}
|
|
||||||
|
|
||||||
{% if category == "error" %}
|
|
||||||
<div class="alert alert-danger mb-0 text-center" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-success mb-0 text-center" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="navbar navbar-dark bg-dark shadow-sm">
|
|
||||||
<div class="container">
|
|
||||||
<a href="#" class="navbar-brand d-flex align-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
|
|
||||||
stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="me-2"
|
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
|
|
||||||
<circle cx="12" cy="13" r="4" />
|
|
||||||
</svg>
|
|
||||||
<strong>RedditVideoMakerBot</strong>
|
|
||||||
</a>
|
|
||||||
<!-- Button trigger modal -->
|
|
||||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#backgroundModal">
|
|
||||||
Add background video
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Modal -->
|
|
||||||
<div class="modal fade" id="backgroundModal" tabindex="-1" role="dialog" aria-labelledby="backgroundModalLabel"
|
|
||||||
aria-hidden="true">
|
|
||||||
<div class="modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="backgroundModalLabel">Add Background Video</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<!-- Add video form -->
|
|
||||||
<form action="/add_background" method="post">
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-4 col-form-label" for="youtube_uri">YouTube URI</label>
|
|
||||||
<div class="col-8">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<div class="input-group-text">
|
|
||||||
<i class="bi bi-youtube"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input id="youtube_uri" name="youtube_uri" placeholder="https://www.youtube.com/watch?v=..."
|
|
||||||
type="text" class="form-control" required="required">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="filename" class="col-4 col-form-label">Filename</label>
|
|
||||||
<div class="col-8">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<div class="input-group-text">
|
|
||||||
<i class="bi bi-file-earmark"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input id="filename" name="filename" placeholder="example: cool-background" type="text"
|
|
||||||
aria-describedby="filenameHelpBlock" required="required" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="citation" class="col-4 col-form-label">Credits (owner of the video)</label>
|
|
||||||
<div class="col-8">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<div class="input-group-text">
|
|
||||||
<i class="bi bi-person-circle"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input id="citation" name="citation" placeholder="YouTube Channel" type="text"
|
|
||||||
class="form-control" required="required" aria-describedby="citationHelpBlock">
|
|
||||||
</div>
|
|
||||||
<span id="citationHelpBlock" class="form-text text-muted">Include the channel name of the owner of
|
|
||||||
the background video you are adding.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="position" class="col-4 col-form-label">Position of screenshots</label>
|
|
||||||
<div class="col-8">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<div class="input-group-text">
|
|
||||||
<i class="bi bi-arrows-fullscreen"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input id="position" name="position" placeholder="Example: center" type="text"
|
|
||||||
class="form-control" aria-describedby="positionHelpBlock">
|
|
||||||
</div>
|
|
||||||
<span id="positionHelpBlock" class="form-text text-muted">Advanced option (you can leave it
|
|
||||||
empty). Valid options are "center" and decimal numbers</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button name="submit" type="submit" class="btn btn-primary">Add background</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="album py-2 bg-light">
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="row mt-2">
|
|
||||||
<div class="col-12 col-md-3 mb-3">
|
|
||||||
<input type="text" class="form-control" placeholder="Search videos" aria-label="Search videos"
|
|
||||||
onkeyup="searchFilter()">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3" id="videos">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="text-muted py-5">
|
|
||||||
<div class="container">
|
|
||||||
<p class="float-end mb-1">
|
|
||||||
<a href="#">Back to top</a>
|
|
||||||
</p>
|
|
||||||
<p class="mb-1"><a href="https://getbootstrap.com/docs/5.2/examples/album/" target="_blank">Album</a> Example
|
|
||||||
Theme by © Bootstrap. <a
|
|
||||||
href="https://github.com/elebumm/RedditVideoMakerBot/blob/master/README.md#developers-and-maintainers"
|
|
||||||
target="_blank">Developers and Maintainers</a></p>
|
|
||||||
<p class="mb-0">If your data is not refreshing, try to hard reload(Ctrl + F5) and visit your local <a
|
|
||||||
href="../video_creation/data/videos.json" target="_blank">videos.json</a> file.</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.3/dist/umd/popper.min.js"
|
|
||||||
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/js/bootstrap.min.js"
|
|
||||||
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.10/clipboard.min.js"></script>
|
|
||||||
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const intervals = [
|
|
||||||
{ label: 'year', seconds: 31536000 },
|
|
||||||
{ label: 'month', seconds: 2592000 },
|
|
||||||
{ label: 'day', seconds: 86400 },
|
|
||||||
{ label: 'hour', seconds: 3600 },
|
|
||||||
{ label: 'minute', seconds: 60 },
|
|
||||||
{ label: 'second', seconds: 1 }
|
|
||||||
];
|
|
||||||
|
|
||||||
function timeSince(date) {
|
|
||||||
const seconds = Math.floor((Date.now() / 1000 - date));
|
|
||||||
const interval = intervals.find(i => i.seconds < seconds);
|
|
||||||
const count = Math.floor(seconds / interval.seconds);
|
|
||||||
return `${count} ${interval.label}${count !== 1 ? 's' : ''} ago`;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.getJSON("videos.json",
|
|
||||||
function (data) {
|
|
||||||
data.sort((b, a) => a['time'] - b['time'])
|
|
||||||
var video = '';
|
|
||||||
$.each(data, function (key, value) {
|
|
||||||
|
|
||||||
video += '<div class="col">';
|
|
||||||
video += '<div class="card shadow-sm">';
|
|
||||||
//keeping original themed image card for future thumbnail usage video += '<svg class="bd-placeholder-img card-img-top" width="100%" height="225" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#55595c"/><text x="50%" y="50%" fill="#eceeef" dy=".3em">r/'+value.subreddit+'</text></svg>';
|
|
||||||
|
|
||||||
video += '<div class="card-body">';
|
|
||||||
video += '<p class="card-text">r/' + value.subreddit + ' • ' + checkTitle(value.reddit_title, value.filename) + '</p>';
|
|
||||||
video += '<div class="d-flex justify-content-between align-items-center">';
|
|
||||||
video += '<div class="btn-group">';
|
|
||||||
video += '<a href="https://www.reddit.com/r/' + value.subreddit + '/comments/' + value.id + '/" class="btn btn-sm btn-outline-secondary" target="_blank">View</a>';
|
|
||||||
video += '<a href="http://localhost:4000/results/' + value.subreddit + '/' + value.filename + '" class="btn btn-sm btn-outline-secondary" download>Download</a>';
|
|
||||||
video += '</div>';
|
|
||||||
video += '<div class="btn-group">';
|
|
||||||
video += '<button type="button" data-toggle="tooltip" id="copy" data-original-title="Copy to clipboard" class="btn btn-sm btn-outline-secondary" data-clipboard-text="' + getCopyData(value.subreddit, value.reddit_title, value.filename, value.background_credit) + '"><i class="bi bi-card-text"></i></button>';
|
|
||||||
video += '<button type="button" data-toggle="tooltip" id="copy" data-original-title="Copy to clipboard" class="btn btn-sm btn-outline-secondary" data-clipboard-text="' + checkTitle(value.reddit_title, value.filename) + ' #Shorts #reddit"><i class="bi bi-youtube"></i></button>';
|
|
||||||
video += '<button type="button" data-toggle="tooltip" id="copy" data-original-title="Copy to clipboard" class="btn btn-sm btn-outline-secondary" data-clipboard-text="' + checkTitle(value.reddit_title, value.filename) + ' #reddit"><i class="bi bi-instagram"></i></button>';
|
|
||||||
video += '</div>';
|
|
||||||
video += '<small class="text-muted">' + timeSince(value.time) + '</small>';
|
|
||||||
video += '</div>';
|
|
||||||
video += '</div>';
|
|
||||||
video += '</div>';
|
|
||||||
video += '</div>';
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#videos').append(video);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
$('[data-toggle="tooltip"]').on('click', function () {
|
|
||||||
$(this).tooltip('hide');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#copy').tooltip({
|
|
||||||
trigger: 'click',
|
|
||||||
placement: 'bottom'
|
|
||||||
});
|
|
||||||
|
|
||||||
function setTooltip(btn, message) {
|
|
||||||
$(btn).tooltip('hide')
|
|
||||||
.attr('data-original-title', message)
|
|
||||||
.tooltip('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
function hoverTooltip(btn, message) {
|
|
||||||
$(btn).tooltip('hide')
|
|
||||||
.attr('data-original-title', message)
|
|
||||||
.tooltip('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideTooltip(btn) {
|
|
||||||
setTimeout(function () {
|
|
||||||
$(btn).tooltip('hide');
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function disposeTooltip(btn) {
|
|
||||||
setTimeout(function () {
|
|
||||||
$(btn).tooltip('dispose');
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
|
|
||||||
var clipboard = new ClipboardJS('#copy');
|
|
||||||
|
|
||||||
clipboard.on('success', function (e) {
|
|
||||||
e.clearSelection();
|
|
||||||
console.info('Action:', e.action);
|
|
||||||
console.info('Text:', e.text);
|
|
||||||
console.info('Trigger:', e.trigger);
|
|
||||||
setTooltip(e.trigger, 'Copied!');
|
|
||||||
hideTooltip(e.trigger);
|
|
||||||
disposeTooltip(e.trigger);
|
|
||||||
});
|
|
||||||
|
|
||||||
clipboard.on('error', function (e) {
|
|
||||||
console.error('Action:', e.action);
|
|
||||||
console.error('Trigger:', e.trigger);
|
|
||||||
setTooltip(e.trigger, fallbackMessage(e.action));
|
|
||||||
hideTooltip(e.trigger);
|
|
||||||
});
|
|
||||||
|
|
||||||
function getCopyData(subreddit, reddit_title, filename, background_credit) {
|
|
||||||
|
|
||||||
if (subreddit == undefined) {
|
|
||||||
subredditCopy = "";
|
|
||||||
} else {
|
|
||||||
subredditCopy = "r/" + subreddit + "\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = filename.slice(0, -4);
|
|
||||||
if (reddit_title == file) {
|
|
||||||
titleCopy = reddit_title;
|
|
||||||
} else {
|
|
||||||
titleCopy = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
var copyData = "";
|
|
||||||
copyData += subredditCopy;
|
|
||||||
copyData += titleCopy;
|
|
||||||
copyData += "\n\nBackground credit: " + background_credit;
|
|
||||||
return copyData;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLink(subreddit, id, reddit_title) {
|
|
||||||
if (subreddit == undefined) {
|
|
||||||
return reddit_title;
|
|
||||||
} else {
|
|
||||||
return "<a target='_blank' href='https://www.reddit.com/r/" + subreddit + "/comments/" + id + "/'>" + reddit_title + "</a>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkTitle(reddit_title, filename) {
|
|
||||||
const file = filename.slice(0, -4);
|
|
||||||
if (reddit_title == file) {
|
|
||||||
return reddit_title;
|
|
||||||
} else {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var searchFilter = () => {
|
|
||||||
const input = document.querySelector(".form-control");
|
|
||||||
const cards = document.getElementsByClassName("col");
|
|
||||||
console.log(cards[1])
|
|
||||||
let filter = input.value
|
|
||||||
for (let i = 0; i < cards.length; i++) {
|
|
||||||
let title = cards[i].querySelector(".card-text");
|
|
||||||
if (title.innerText.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
|
|
||||||
cards[i].classList.remove("d-none")
|
|
||||||
} else {
|
|
||||||
cards[i].classList.add("d-none")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
Loading…
Reference in new issue