29 files changed
+215
-120
No files matched your search
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
@@ -3,30 +3,35 @@
|
||||
# Othewrwise, Black is run and its changes are committed back to the incoming pull request.
|
||||
# https://github.com/cclauss/autoblack
|
||||
|
||||
name: autoblack
|
||||
name: fmt
|
||||
on:
|
||||
push:
|
||||
branches: ["develop"]
|
||||
jobs:
|
||||
build:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Black
|
||||
run: pip install black
|
||||
- name: Run black --check .
|
||||
run: black --check .
|
||||
- name: If needed, commit black changes to the pull request
|
||||
python-version: 3.10.14
|
||||
- name: Install Black & isort
|
||||
run: pip install black isort
|
||||
- name: Run black check
|
||||
run: black --check . --line-length 101
|
||||
- name: Run isort check
|
||||
run: isort . --check-only --diff --profile black
|
||||
- name: If needed, commit changes to the pull request
|
||||
if: failure()
|
||||
run: |
|
||||
black . --line-length 101
|
||||
isort . --profile black
|
||||
git config --global user.name github-actions
|
||||
git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
|
||||
git checkout $GITHUB_HEAD_REF
|
||||
git commit -am "fixup: Format Python code with Black"
|
||||
git push origin HEAD:develop
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: psf/black@stable
|
||||
with:
|
||||
options: "--line-length 101"
|
||||
- uses: isort/isort-action@v1
|
||||
with:
|
||||
configuration: "--check-only --diff --profile black"
|
||||
+3
-2
@@ -231,7 +231,8 @@ fabric.properties
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
assets/
|
||||
assets/temp
|
||||
assets/backgrounds
|
||||
/.vscode
|
||||
out
|
||||
.DS_Store
|
||||
@@ -244,4 +245,4 @@ video_creation/data/videos.json
|
||||
video_creation/data/envvars.txt
|
||||
|
||||
config.toml
|
||||
*.exe
|
||||
*.exe
|
||||
+1
-5
@@ -1,4 +1,4 @@
|
||||
FROM python:3.10.9-slim
|
||||
FROM python:3.10.14-slim
|
||||
|
||||
RUN apt update
|
||||
RUN apt-get install -y ffmpeg
|
||||
@@ -9,8 +9,4 @@ ADD . /app
|
||||
WORKDIR /app
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
# tricks for pytube : https://github.com/elebumm/RedditVideoMakerBot/issues/142
|
||||
# (NOTE : This is no longer useful since pytube was removed from the dependencies)
|
||||
# RUN sed -i 's/re.compile(r"^\\w+\\W")/re.compile(r"^\\$*\\w+\\W")/' /usr/local/lib/python3.8/dist-packages/pytube/cipher.py
|
||||
|
||||
CMD ["python3", "main.py"]
|
||||
+2
-2
@@ -205,7 +205,7 @@
|
||||
<select name="background_choice" class="form-select" data-toggle="tooltip"
|
||||
data-original-title='Sets the background of the video'>
|
||||
<option value=" ">Random Video</option>
|
||||
{% for background in checks["background_choice"]["options"][1:] %}
|
||||
{% for background in checks["background_video"]["options"][1:] %}
|
||||
<option value="{{background}}">{{background}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
@@ -618,4 +618,4 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -50,7 +50,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
|
||||
|
||||
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". Paste any URL in redirect URL. Ex:google.com
|
||||
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:`https://jasoncameron.dev`
|
||||
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 😎
|
||||
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.
|
||||
@@ -81,7 +81,7 @@ I have tried to simplify the code so anyone can read it and start contributing a
|
||||
|
||||
Please read our [contributing guidelines](CONTRIBUTING.md) for more detailed information.
|
||||
|
||||
### For any questions or support join the [Discord](https://discord.gg/WBQT52RrHV) server
|
||||
### For any questions or support join the [Discord](https://discord.gg/qfQSx45xCV) server
|
||||
|
||||
## Developers and maintainers.
|
||||
|
||||
@@ -101,6 +101,8 @@ Freebiell (Freebie#3263) - https://github.com/FreebieII
|
||||
|
||||
Aman Raza (electro199#8130) - https://github.com/electro199
|
||||
|
||||
Cyteon (cyteon) - https://github.com/cyteon
|
||||
|
||||
|
||||
## LICENSE
|
||||
[Roboto Fonts](https://fonts.google.com/specimen/Roboto/about) are licensed under [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
import base64
|
||||
import random
|
||||
import time
|
||||
from typing import Optional, Final
|
||||
from typing import Final, Optional
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
+13
-17
@@ -1,33 +1,28 @@
|
||||
import random
|
||||
|
||||
from elevenlabs import generate, save
|
||||
from elevenlabs import save
|
||||
from elevenlabs.client import ElevenLabs
|
||||
|
||||
from utils import settings
|
||||
|
||||
voices = [
|
||||
"Adam",
|
||||
"Antoni",
|
||||
"Arnold",
|
||||
"Bella",
|
||||
"Domi",
|
||||
"Elli",
|
||||
"Josh",
|
||||
"Rachel",
|
||||
"Sam",
|
||||
]
|
||||
|
||||
|
||||
class elevenlabs:
|
||||
def __init__(self):
|
||||
self.max_chars = 2500
|
||||
self.voices = voices
|
||||
self.client: ElevenLabs = None
|
||||
|
||||
def run(self, text, filepath, random_voice: bool = False):
|
||||
if self.client is None:
|
||||
self.initialize()
|
||||
if random_voice:
|
||||
voice = self.randomvoice()
|
||||
else:
|
||||
voice = str(settings.config["settings"]["tts"]["elevenlabs_voice_name"]).capitalize()
|
||||
|
||||
audio = self.client.generate(text=text, voice=voice, model="eleven_multilingual_v1")
|
||||
save(audio=audio, filename=filepath)
|
||||
|
||||
def initialize(self):
|
||||
if settings.config["settings"]["tts"]["elevenlabs_api_key"]:
|
||||
api_key = settings.config["settings"]["tts"]["elevenlabs_api_key"]
|
||||
else:
|
||||
@@ -35,8 +30,9 @@ class elevenlabs:
|
||||
"You didn't set an Elevenlabs API key! Please set the config variable ELEVENLABS_API_KEY to a valid API key."
|
||||
)
|
||||
|
||||
audio = generate(api_key=api_key, text=text, voice=voice, model="eleven_multilingual_v1")
|
||||
save(audio=audio, filename=filepath)
|
||||
self.client = ElevenLabs(api_key=api_key)
|
||||
|
||||
def randomvoice(self):
|
||||
return random.choice(self.voices)
|
||||
if self.client is None:
|
||||
self.initialize()
|
||||
return random.choice(self.client.voices.get_all().voices).voice_name
|
||||
@@ -14,14 +14,12 @@ from utils import settings
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.voice import sanitize_text
|
||||
|
||||
|
||||
DEFAULT_MAX_LENGTH: int = (
|
||||
50 # Video length variable, edit this on your own risk. It should work, but it's not supported
|
||||
)
|
||||
|
||||
|
||||
class TTSEngine:
|
||||
|
||||
"""Calls the given TTS engine to reduce code duplication and allow multiple TTS engines.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -43,9 +43,11 @@ class StreamlabsPolly:
|
||||
f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}"
|
||||
)
|
||||
voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize()
|
||||
|
||||
body = {"voice": voice, "text": text, "service": "polly"}
|
||||
headers = {"Referer": "https://streamlabs.com/"}
|
||||
response = requests.post(self.url, headers=headers, data=body)
|
||||
|
||||
if not check_ratelimit(response):
|
||||
self.run(text, filepath, random_voice)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@@ -7,25 +7,25 @@ from subprocess import Popen
|
||||
from typing import NoReturn
|
||||
|
||||
from prawcore import ResponseException
|
||||
from utils.console import print_substep
|
||||
|
||||
from reddit.subreddit import get_subreddit_threads
|
||||
from utils import settings
|
||||
from utils.cleanup import cleanup
|
||||
from utils.console import print_markdown, print_step
|
||||
from utils.console import print_markdown, print_step, print_substep
|
||||
from utils.ffmpeg_install import ffmpeg_install
|
||||
from utils.id import id
|
||||
from utils.version import checkversion
|
||||
from video_creation.background import (
|
||||
download_background_video,
|
||||
download_background_audio,
|
||||
chop_background,
|
||||
download_background_audio,
|
||||
download_background_video,
|
||||
get_background_config,
|
||||
)
|
||||
from video_creation.final_video import make_final_video
|
||||
from video_creation.screenshot_downloader import get_screenshots_of_reddit_posts
|
||||
from video_creation.voices import save_text_to_mp3
|
||||
from utils.ffmpeg_install import ffmpeg_install
|
||||
|
||||
__VERSION__ = "3.2.1"
|
||||
__VERSION__ = "3.3.0"
|
||||
|
||||
print(
|
||||
"""
|
||||
@@ -37,7 +37,6 @@ print(
|
||||
╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
"""
|
||||
)
|
||||
# Modified by JasonLovesDoggo
|
||||
print_markdown(
|
||||
"### Thanks for using this tool! Feel free to contribute to this project on GitHub! If you have any questions, feel free to join my Discord server or submit a GitHub issue. You can find solutions to many common problems in the documentation: https://reddit-video-maker-bot.netlify.app/"
|
||||
)
|
||||
|
||||
+4
-6
@@ -1,18 +1,16 @@
|
||||
import re
|
||||
|
||||
from prawcore.exceptions import ResponseException
|
||||
|
||||
from utils import settings
|
||||
import praw
|
||||
from praw.models import MoreComments
|
||||
from prawcore.exceptions import ResponseException
|
||||
|
||||
from utils import settings
|
||||
from utils.ai_methods import sort_by_similarity
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.posttextparser import posttextparser
|
||||
from utils.subreddit import get_subreddit_undone
|
||||
from utils.videos import check_done
|
||||
from utils.voice import sanitize_text
|
||||
from utils.posttextparser import posttextparser
|
||||
from utils.ai_methods import sort_by_similarity
|
||||
|
||||
|
||||
def get_subreddit_threads(POST_ID: str):
|
||||
@@ -106,7 +104,7 @@ def get_subreddit_threads(POST_ID: str):
|
||||
upvotes = submission.score
|
||||
ratio = submission.upvote_ratio * 100
|
||||
num_comments = submission.num_comments
|
||||
threadurl = f"https://reddit.com{submission.permalink}"
|
||||
threadurl = f"https://new.reddit.com/{submission.permalink}"
|
||||
|
||||
print_substep(f"Video will be: {submission.title} :thumbsup:", style="bold green")
|
||||
print_substep(f"Thread url is: {threadurl} :thumbsup:", style="bold green")
|
||||
|
||||
+18
-17
@@ -1,23 +1,24 @@
|
||||
boto3==1.26.142
|
||||
botocore==1.29.142
|
||||
gTTS==2.3.2
|
||||
boto3==1.34.127
|
||||
botocore==1.34.127
|
||||
gTTS==2.5.1
|
||||
moviepy==1.0.3
|
||||
playwright==1.34.0
|
||||
praw==7.7.0
|
||||
playwright==1.44.0
|
||||
praw==7.7.1
|
||||
prawcore~=2.3.0
|
||||
requests==2.31.0
|
||||
rich==13.4.1
|
||||
requests==2.32.3
|
||||
rich==13.7.1
|
||||
toml==0.10.2
|
||||
translators==5.7.6
|
||||
translators==5.9.2
|
||||
pyttsx3==2.90
|
||||
Pillow==9.5.0
|
||||
tomlkit==0.11.8
|
||||
Flask==2.3.3
|
||||
Pillow==10.3.0
|
||||
tomlkit==0.12.5
|
||||
Flask==3.0.3
|
||||
clean-text==0.6.0
|
||||
unidecode==1.3.6
|
||||
spacy==3.5.3
|
||||
torch==2.0.1
|
||||
transformers==4.29.2
|
||||
unidecode==1.3.8
|
||||
spacy==3.7.5
|
||||
torch==2.3.1
|
||||
transformers==4.41.2
|
||||
ffmpeg-python==0.2.0
|
||||
elevenlabs==0.2.17
|
||||
yt-dlp==2023.7.6
|
||||
elevenlabs==1.3.0
|
||||
yt-dlp==2024.5.27
|
||||
numpy==1.26.4
|
||||
@@ -31,6 +31,7 @@ storymode_max_length = { optional = true, default = 1000, example = 1000, explan
|
||||
resolution_w = { optional = false, default = 1080, example = 1440, explantation = "Sets the width in pixels of the final video" }
|
||||
resolution_h = { optional = false, default = 1920, example = 2560, explantation = "Sets the height in pixels of the final video" }
|
||||
zoom = { optional = true, default = 1, example = 1.1, explanation = "Sets the browser zoom level. Useful if you want the text larger.", type = "float", nmin = 0.1, nmax = 2, oob_error = "The text is really difficult to read at a zoom level higher than 2" }
|
||||
channel_name = { optional = true, default = "Reddit Tales", example = "Reddit Stories", explanation = "Sets the channel name for the video" }
|
||||
|
||||
[settings.background]
|
||||
background_video = { optional = true, default = "minecraft", example = "rocket-league", options = ["minecraft", "gta", "rocket-league", "motor-gta", "csgo-surf", "cluster-truck", "minecraft-2","multiversus","fall-guys","steep", ""], explanation = "Sets the background for the video based on game name" }
|
||||
@@ -44,7 +45,7 @@ background_thumbnail_font_color = { optional = true, default = "255,255,255", ex
|
||||
|
||||
[settings.tts]
|
||||
voice_choice = { optional = false, default = "tiktok", options = ["elevenlabs", "streamlabspolly", "tiktok", "googletranslate", "awspolly", "pyttsx", ], example = "tiktok", explanation = "The voice platform used for TTS generation. " }
|
||||
random_voice = { optional = false, default = true, example = true, type = "bool", options = [true, false,], explanation = "Randomizes the voice used for each comment" }
|
||||
random_voice = { optional = false, type = "bool", default = true, example = true, options = [true, false,], explanation = "Randomizes the voice used for each comment" }
|
||||
elevenlabs_voice_name = { optional = false, default = "Bella", example = "Bella", explanation = "The voice used for elevenlabs", options = ["Adam", "Antoni", "Arnold", "Bella", "Domi", "Elli", "Josh", "Rachel", "Sam", ] }
|
||||
elevenlabs_api_key = { optional = true, example = "21f13f91f54d741e2ae27d2ab1b99d59", explanation = "Elevenlabs API key" }
|
||||
aws_polly_voice = { optional = false, default = "Matthew", example = "Matthew", explanation = "The voice used for AWS Polly" }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import numpy as np
|
||||
from transformers import AutoTokenizer, AutoModel
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
|
||||
# Mean Pooling - Take attention mask into account for correct averaging
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from os.path import exists
|
||||
import shutil
|
||||
from os.path import exists
|
||||
|
||||
|
||||
def _listdir(d): # listdir with full path
|
||||
|
||||
+11
-4
@@ -1,7 +1,8 @@
|
||||
import zipfile
|
||||
import requests
|
||||
import os
|
||||
import subprocess
|
||||
import zipfile
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def ffmpeg_install_windows():
|
||||
@@ -39,7 +40,10 @@ def ffmpeg_install_windows():
|
||||
# Rename and move files
|
||||
os.rename(f"{ffmpeg_extracted_folder}-6.0-full_build", ffmpeg_extracted_folder)
|
||||
for file in os.listdir(os.path.join(ffmpeg_extracted_folder, "bin")):
|
||||
os.rename(os.path.join(ffmpeg_extracted_folder, "bin", file), os.path.join(".", file))
|
||||
os.rename(
|
||||
os.path.join(ffmpeg_extracted_folder, "bin", file),
|
||||
os.path.join(".", file),
|
||||
)
|
||||
os.rmdir(os.path.join(ffmpeg_extracted_folder, "bin"))
|
||||
for file in os.listdir(os.path.join(ffmpeg_extracted_folder, "doc")):
|
||||
os.remove(os.path.join(ffmpeg_extracted_folder, "doc", file))
|
||||
@@ -101,7 +105,10 @@ def ffmpeg_install():
|
||||
try:
|
||||
# Try to run the FFmpeg command
|
||||
subprocess.run(
|
||||
["ffmpeg", "-version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
["ffmpeg", "-version"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
# Check if there's ffmpeg.exe in the current directory
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from PIL.ImageFont import FreeTypeFont, ImageFont
|
||||
|
||||
|
||||
def getsize(font: ImageFont | FreeTypeFont, text: str):
|
||||
left, top, right, bottom = font.getbbox(text)
|
||||
width = right - left
|
||||
height = bottom - top
|
||||
return width, height
|
||||
|
||||
|
||||
def getheight(font: ImageFont | FreeTypeFont, text: str):
|
||||
_, height = getsize(font, text)
|
||||
return height
|
||||
+6
-12
@@ -1,10 +1,12 @@
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
import os
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from rich.progress import track
|
||||
|
||||
from TTS.engine_wrapper import process_text
|
||||
from utils.fonts import getheight, getsize
|
||||
|
||||
|
||||
def draw_multiple_line_text(
|
||||
@@ -14,12 +16,12 @@ def draw_multiple_line_text(
|
||||
Draw multiline text over given image
|
||||
"""
|
||||
draw = ImageDraw.Draw(image)
|
||||
Fontperm = font.getsize(text)
|
||||
font_height = getheight(font, text)
|
||||
image_width, image_height = image.size
|
||||
lines = textwrap.wrap(text, width=wrap)
|
||||
y = (image_height / 2) - (((Fontperm[1] + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
y = (image_height / 2) - (((font_height + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
for line in lines:
|
||||
line_width, line_height = font.getsize(line)
|
||||
line_width, line_height = getsize(font, line)
|
||||
if transparent:
|
||||
shadowcolor = "black"
|
||||
for i in range(1, 5):
|
||||
@@ -55,25 +57,17 @@ def imagemaker(theme, reddit_obj: dict, txtclr, padding=5, transparent=False) ->
|
||||
"""
|
||||
Render Images for video
|
||||
"""
|
||||
title = process_text(reddit_obj["thread_title"], False)
|
||||
texts = reddit_obj["thread_post"]
|
||||
id = re.sub(r"[^\w\s-]", "", reddit_obj["thread_id"])
|
||||
|
||||
if transparent:
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100)
|
||||
tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100)
|
||||
else:
|
||||
tfont = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 100) # for title
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Regular.ttf"), 100)
|
||||
size = (1920, 1080)
|
||||
|
||||
image = Image.new("RGBA", size, theme)
|
||||
|
||||
# for title
|
||||
draw_multiple_line_text(image, title, tfont, txtclr, padding, wrap=30, transparent=transparent)
|
||||
|
||||
image.save(f"assets/temp/{id}/png/title.png")
|
||||
|
||||
for idx, text in track(enumerate(texts), "Rendering Image"):
|
||||
image = Image.new("RGBA", size, theme)
|
||||
text = process_text(text, False)
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import re
|
||||
from typing import Tuple, Dict
|
||||
from pathlib import Path
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import toml
|
||||
from rich.console import Console
|
||||
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ import json
|
||||
from os.path import exists
|
||||
|
||||
from utils import settings
|
||||
from utils.console import print_substep
|
||||
from utils.ai_methods import sort_by_similarity
|
||||
from utils.console import print_substep
|
||||
|
||||
|
||||
def get_subreddit_undone(submissions: list, subreddit, times_checked=0, similarity_scores=None):
|
||||
|
||||
+1
-1
@@ -4,10 +4,10 @@ import time as pytime
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
|
||||
from cleantext import clean
|
||||
from requests import Response
|
||||
|
||||
from utils import settings
|
||||
from cleantext import clean
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from datetime import timezone
|
||||
|
||||
@@ -3,13 +3,14 @@ import random
|
||||
import re
|
||||
from pathlib import Path
|
||||
from random import randrange
|
||||
from typing import Any, Tuple, Dict
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
from moviepy.editor import VideoFileClip, AudioFileClip
|
||||
import yt_dlp
|
||||
from moviepy.editor import AudioFileClip, VideoFileClip
|
||||
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
|
||||
|
||||
from utils import settings
|
||||
from utils.console import print_step, print_substep
|
||||
import yt_dlp
|
||||
|
||||
|
||||
def load_background_options():
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -1,25 +1,26 @@
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import textwrap
|
||||
import threading
|
||||
import time
|
||||
from os.path import exists # Needs to be imported specifically
|
||||
from typing import Final
|
||||
from typing import Tuple, Any, Dict
|
||||
from pathlib import Path
|
||||
from typing import Dict, Final, Tuple
|
||||
|
||||
import ffmpeg
|
||||
import translators
|
||||
from PIL import Image
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from rich.console import Console
|
||||
from rich.progress import track
|
||||
|
||||
from utils import settings
|
||||
from utils.cleanup import cleanup
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.fonts import getheight
|
||||
from utils.thumbnail import create_thumbnail
|
||||
from utils.videos import save_data
|
||||
from utils import settings
|
||||
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
|
||||
console = Console()
|
||||
|
||||
@@ -107,6 +108,63 @@ def prepare_background(reddit_id: str, W: int, H: int) -> str:
|
||||
return output_path
|
||||
|
||||
|
||||
def create_fancy_thumbnail(image, text, text_color, padding, wrap=35):
|
||||
print_step(f"Creating fancy thumbnail for: {text}")
|
||||
font_title_size = 47
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
|
||||
image_width, image_height = image.size
|
||||
lines = textwrap.wrap(text, width=wrap)
|
||||
y = (
|
||||
(image_height / 2)
|
||||
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
+ 30
|
||||
)
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
username_font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), 30)
|
||||
draw.text(
|
||||
(205, 825),
|
||||
settings.config["settings"]["channel_name"],
|
||||
font=username_font,
|
||||
fill=text_color,
|
||||
align="left",
|
||||
)
|
||||
|
||||
if len(lines) == 3:
|
||||
lines = textwrap.wrap(text, width=wrap + 10)
|
||||
font_title_size = 40
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
|
||||
y = (
|
||||
(image_height / 2)
|
||||
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
+ 35
|
||||
)
|
||||
elif len(lines) == 4:
|
||||
lines = textwrap.wrap(text, width=wrap + 10)
|
||||
font_title_size = 35
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
|
||||
y = (
|
||||
(image_height / 2)
|
||||
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
+ 40
|
||||
)
|
||||
elif len(lines) > 4:
|
||||
lines = textwrap.wrap(text, width=wrap + 10)
|
||||
font_title_size = 30
|
||||
font = ImageFont.truetype(os.path.join("fonts", "Roboto-Bold.ttf"), font_title_size)
|
||||
y = (
|
||||
(image_height / 2)
|
||||
- (((getheight(font, text) + (len(lines) * padding) / len(lines)) * len(lines)) / 2)
|
||||
+ 30
|
||||
)
|
||||
|
||||
for line in lines:
|
||||
draw.text((120, y), line, font=font, fill=text_color, align="left")
|
||||
y += getheight(font, line) + padding
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def merge_background_audio(audio: ffmpeg, reddit_id: str):
|
||||
"""Gather an audio and merge with assets/backgrounds/background.mp3
|
||||
Args:
|
||||
@@ -202,6 +260,23 @@ def make_final_video(
|
||||
|
||||
image_clips = list()
|
||||
|
||||
Path(f"assets/temp/{reddit_id}/png").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Credits to tim (beingbored)
|
||||
# get the title_template image and draw a text in the middle part of it with the title of the thread
|
||||
title_template = Image.open("assets/title_template.png")
|
||||
|
||||
title = reddit_obj["thread_title"]
|
||||
|
||||
title = name_normalize(title)
|
||||
|
||||
font_color = "#000000"
|
||||
padding = 5
|
||||
|
||||
# create_fancy_thumbnail(image, text, text_color, padding
|
||||
title_img = create_fancy_thumbnail(title_template, title, font_color, padding)
|
||||
|
||||
title_img.save(f"assets/temp/{reddit_id}/png/title.png")
|
||||
image_clips.insert(
|
||||
0,
|
||||
ffmpeg.input(f"assets/temp/{reddit_id}/png/title.png")["v"].filter(
|
||||
@@ -257,6 +332,9 @@ def make_final_video(
|
||||
)
|
||||
)
|
||||
image_overlay = image_clips[i].filter("colorchannelmixer", aa=opacity)
|
||||
assert (
|
||||
audio_clips_durations is not None
|
||||
), "Please make a GitHub issue if you see this. Ping @JasonLovesDoggo on GitHub."
|
||||
background_clip = background_clip.overlay(
|
||||
image_overlay,
|
||||
enable=f"between(t,{current_time},{current_time + audio_clips_durations[i]})",
|
||||
|
||||
@@ -4,7 +4,6 @@ from pathlib import Path
|
||||
from typing import Dict, Final
|
||||
|
||||
import translators
|
||||
from playwright.async_api import async_playwright # pylint: disable=unused-import
|
||||
from playwright.sync_api import ViewportSize, sync_playwright
|
||||
from rich.progress import track
|
||||
|
||||
@@ -12,10 +11,9 @@ from utils import settings
|
||||
from utils.console import print_step, print_substep
|
||||
from utils.imagenarator import imagemaker
|
||||
from utils.playwright import clear_cookie_by_name
|
||||
|
||||
from utils.videos import save_data
|
||||
|
||||
__all__ = ["download_screenshots_of_reddit_posts"]
|
||||
__all__ = ["get_screenshots_of_reddit_posts"]
|
||||
|
||||
|
||||
def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
@@ -60,6 +58,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
bgcolor = (255, 255, 255, 255)
|
||||
txtcolor = (0, 0, 0)
|
||||
transparent = False
|
||||
|
||||
if storymode and settings.config["settings"]["storymodemethod"] == 1:
|
||||
# for idx,item in enumerate(reddit_object["thread_post"]):
|
||||
print_substep("Generating images...")
|
||||
@@ -87,6 +86,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
color_scheme="dark",
|
||||
viewport=ViewportSize(width=W, height=H),
|
||||
device_scale_factor=dsf,
|
||||
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
|
||||
)
|
||||
cookies = json.load(cookie_file)
|
||||
cookie_file.close()
|
||||
@@ -100,9 +100,9 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
page.set_viewport_size(ViewportSize(width=1920, height=1080))
|
||||
page.wait_for_load_state()
|
||||
|
||||
page.locator('[name="username"]').fill(settings.config["reddit"]["creds"]["username"])
|
||||
page.locator('[name="password"]').fill(settings.config["reddit"]["creds"]["password"])
|
||||
page.locator("button[class$='m-full-width']").click()
|
||||
page.locator(f'input[name="username"]').fill(settings.config["reddit"]["creds"]["username"])
|
||||
page.locator(f'input[name="password"]').fill(settings.config["reddit"]["creds"]["password"])
|
||||
page.get_by_role("button", name="Log In").click()
|
||||
page.wait_for_timeout(5000)
|
||||
|
||||
login_error_div = page.locator(".AnimatedForm__errorMessage").first
|
||||
@@ -220,7 +220,7 @@ def get_screenshots_of_reddit_posts(reddit_object: dict, screenshot_num: int):
|
||||
if page.locator('[data-testid="content-gate"]').is_visible():
|
||||
page.locator('[data-testid="content-gate"] button').click()
|
||||
|
||||
page.goto(f'https://reddit.com{comment["comment_url"]}', timeout=0)
|
||||
page.goto(f"https://new.reddit.com/{comment['comment_url']}")
|
||||
|
||||
# translate code
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@ from typing import Tuple
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
from TTS.GTTS import GTTS
|
||||
from TTS.TikTok import TikTok
|
||||
from TTS.aws_polly import AWSPolly
|
||||
from TTS.engine_wrapper import TTSEngine
|
||||
from TTS.pyttsx import pyttsx
|
||||
from TTS.elevenlabs import elevenlabs
|
||||
from TTS.engine_wrapper import TTSEngine
|
||||
from TTS.GTTS import GTTS
|
||||
from TTS.pyttsx import pyttsx
|
||||
from TTS.streamlabs_polly import StreamlabsPolly
|
||||
from TTS.TikTok import TikTok
|
||||
from utils import settings
|
||||
from utils.console import print_table, print_step
|
||||
from utils.console import print_step, print_table
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
Reference in new issue
Block a user