pull/2070/head
cyteon 1 year ago
parent 83f6b983d4
commit ffd7f2518e

1
.gitignore vendored

@ -240,6 +240,7 @@ out
.DS_Store .DS_Store
.setup-done-before .setup-done-before
results/* results/*
capcut_results/*
clipped/* clipped/*
reddit-bot-351418-5560ebc49cac.json reddit-bot-351418-5560ebc49cac.json
/.idea /.idea

@ -70,7 +70,7 @@ def run_many(times) -> None:
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....
main() main()
Popen("cls" if name == "nt" else "clear", shell=True).wait() #Popen("cls" if name == "nt" else "clear", shell=True).wait()
if settings.config["settings"]["mememode"]: if settings.config["settings"]["mememode"]:
make_meme_video() make_meme_video()
@ -103,7 +103,7 @@ if __name__ == "__main__":
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("+"))}'
) )
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"]: elif config["settings"]["times_to_run"]:
run_many(config["settings"]["times_to_run"]) run_many(config["settings"]["times_to_run"])
else: else:

@ -21,3 +21,4 @@ transformers==4.39.3
ffmpeg-python==0.2.0 ffmpeg-python==0.2.0
elevenlabs==0.2.17 elevenlabs==0.2.17
yt-dlp==2023.7.6 yt-dlp==2023.7.6
bs4

@ -5,6 +5,11 @@ username = { optional = false, nmin = 3, nmax = 20, explanation = "The username
password = { optional = false, nmin = 8, explanation = "The password of your reddit account", example = "fFAGRNJru1FTz70BzhT3Zg", oob_error = "Password too short" } 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 } 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 }
[capcut]
email = { optional = false, nmin = 3, nmax = 50, explanation = "The email of your CapCut account", example = ""}
password = { optional = false, nmin = 8, explanation = "The password of your CapCut account", example = ""}
cloud_id = { optional = false, nmin = 8, type="int", explanation = "The cloud id of your CapCut account", example = ""}
preset_number = { optional = true, default=18, type="int", explanation = "The preset number of your CapCut account", example = 1}
[reddit.thread] [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" } 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" }

@ -0,0 +1,191 @@
import json
import time
import os
from playwright.sync_api import sync_playwright
from playwright.async_api import async_playwright
import asyncio
from bs4 import BeautifulSoup
from utils import settings
# Utils
def check_similarity(video_title, text):
video_title_words = set(video_title.lower().split())
text_words = set(text.lower().split())
common_words = text_words.intersection(video_title_words)
return len(common_words) / len(text_words) >= 0.6
# Runthrough
def generate_captions(file_path, title):
with sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context(viewport={"width": 1920, "height": 1080})
page = context.new_page()
page.goto("https://www.capcut.com/")
email = settings.config["capcut"]["email"]
password = settings.config["capcut"]["password"]
video_title = title.lower()
video_file_name = title.replace(" ", "_")
page.click("//span[contains(text(),'Decline all')]")
page.click("//span[contains(text(),'OK')]")
page.click("//span[contains(text(),'Sign in')]")
page.fill("//input[@class='lv-input lv-input-size-default lv_sign_in_panel_wide-input']", email)
page.click("//span[normalize-space()='Continue']")
# time.sleep(5)
page.fill("//input[@type='password']", password)
page.click("//span[contains(text(),'Sign in')]")
try:
page.click("//div[@class='skip--kncMC']")
except:
pass
page.goto(f"https://www.capcut.com/my-cloud/{str(settings.config['capcut']['cloud_id'])}?start_tab=video&enter_from=page_header&from_page=work_space&tab=all")
try:
page.click("//span[contains(text(),'Decline all')]")
except:
pass
page.click("//div[@class='guide-modal-close-icon']")
page.hover("//div[@data-selectable-item-id]")
page.click("//*[@width='16']")
page.click("//div[contains(text(),'Move to Trash')]")
page.click("//span[contains(text(),'Confirm')]")
# time.sleep(2)
# page.click("//span[contains(text(),'Trash')]")
# page.hover("//div[@data-selectable-item-id]")
# page.screenshot(path="video_creation/Error3.png")
page.goto("https://www.capcut.com/editor?enter_from=create_new&current_page=landing_page&from_page=work_space&start_tab=video&__action_from=my_draft&position=my_draft&scenario=youtube_ads&scale=16%3A9")
page.click("//div[@class='guide-close-icon-f8J9FZ']//*[name()='svg']")
page.click("//div[@class='guide-placeholder-before-OsTdXF']")
page.click("//div[@class='guide-close-icon-f8J9FZ']//*[name()='svg']")
page.set_input_files("(//input[@type='file'])[1]", file_path)
time.sleep(20)
page.click("//div[@id='siderMenuCaption']//div[@class='menu-inner-box']//*[name()='svg']")
page.click("//div[normalize-space()='Auto captions']")
video_ready = False
while not video_ready:
page.click("//footer[@class='active-panel']//span[contains(text(),'Generate')]")
try:
# check if class="lv-message lv-message-error" is visible
if page.locator("//div[@class='lv-message lv-message-error']").is_visible():
video_ready = False
else:
video_ready = True
except:
pass
time.sleep(10)
print("Changing settings")
page.click("//div[@id='workbench-tool-bar-toolbarTextPreset']")
time.sleep(1)
page.click("//div[@id='lv-tabs-1-tab-1']")
time.sleep(1)
page.click(f"(//img[@class='image-DUnWNW'])[{str(settings.config['capcut']['preset_number'])}]")
time.sleep(2)
page.click("//div[@id='workbench-tool-bar-toolbarTextBasic']//div[@class='tool-bar-icon']//*[name()='svg']")
time.sleep(2)
page.fill("//input[@value='-255']", "0")
time.sleep(1)
page.fill("//input[@value='100' and @aria-valuemax='500']", "40")
time.sleep(2)
print("Cleaning up captions")
for _ in range(10):
element = page.query_selector("//div[@class='subtitle-list-content']/section[1]")
html_code = page.evaluate("element => element.innerHTML", element)
soup = BeautifulSoup(html_code, 'html.parser')
textarea = soup.find('textarea', {'class': 'lv-textarea'})
text = textarea.text.lower()
if check_similarity(video_title.lower(), text.lower()):
page.click("//section[@class='subtitle-list-item']")
page.click("//button[@class='lv-btn lv-btn-text lv-btn-size-default lv-btn-shape-square']//*[name()='svg']")
else:
break
print("Exporting video")
page.click("//div[contains(@data-id,'titlebarExport')]//div[contains(@style,'position: relative;')]")
page.click("//div[contains(@class,'content_7ddfe')]")
page.fill("//input[@id='form-video_name_input']", video_file_name )
page.click("//span[contains(text(),'720p')]")
page.click("//span[contains(text(),'1080p')]")
page.click("//span[contains(text(),'Recommended quality')]")
page.click("//li[contains(text(),'High quality')]")
page.click("//span[contains(text(),'30fps')]")
page.click("//li[contains(text(),'60fps')]")
time.sleep(2)
page.click("//button[@id='export-confirm-button']")
time.sleep(35)
with page.expect_download() as download_info:
page.locator("//a[@class='shadowAnchor_5bc06']").click()
dl = download_info.value
print(dl.path())
working_dir_path = os.getcwd()
os.makedirs(os.path.join(working_dir_path, "capcut_results", "videos"), exist_ok=True)
final_path = os.path.join(working_dir_path, "capcut_results", "videos", video_file_name + ".mp4")
print(final_path)
dl.save_as(final_path)
browser.close()

@ -16,6 +16,7 @@ from rich.console import Console
from rich.progress import track from rich.progress import track
from utils import settings from utils import settings
from utils import capcut
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.thumbnail import create_thumbnail from utils.thumbnail import create_thumbnail
@ -492,8 +493,16 @@ def make_final_video(
old_percentage = pbar.n old_percentage = pbar.n
pbar.update(100 - old_percentage) pbar.update(100 - old_percentage)
pbar.close() pbar.close()
if settings.config["settings"]["storymodemethod"] == 0:
print_step("Adding CapCut captions 📝")
file_path = os.getcwd() + f"/results/{subreddit}/{filename}.mp4"
capcut.generate_captions(file_path, filename)
save_data(subreddit, filename + ".mp4", title, idx, background_config["video"][2]) save_data(subreddit, filename + ".mp4", title, idx, background_config["video"][2])
print_step("Removing temporary files 🗑") print_step("Removing temporary files 🗑")
cleanups = cleanup(reddit_id) cleanups = cleanup(reddit_id)
print_substep(f"Removed {cleanups} temporary files 🗑") print_substep(f"Removed {cleanups} temporary files 🗑")
print_step("Done! 🎉 The video is in the results folder 📁") print_step("Done! 🎉 The video is in the results folder 📁")

Loading…
Cancel
Save