Move custom MoviePy effects to their own Python file

This commit is contained in:
Chev 2026-01-25 16:15:30 -08:00
parent 7ea8df41cc
commit 85d38918f7
Signed by: chev2
GPG key ID: 0B212D6AED495EC9
2 changed files with 127 additions and 91 deletions

99
main.py
View file

@ -7,6 +7,8 @@ from os import listdir, mkdir, path
from moviepy import VideoFileClip, AudioFileClip, CompositeAudioClip, concatenate_videoclips, Effect, vfx
from moviepy.Clip import Clip
from src import custom_effects
# Progress bars
from tqdm import tqdm
@ -68,91 +70,6 @@ rng = random.Random(seed)
print("")
print(f"Found {len(videoFiles)} videos and {len(audioFiles)} sounds")
class ContinuousFlipVideo(Effect):
def apply(self, clip: Clip): #flip a video multiple times over its duration
#how many times the clip will be flipped
flip_amt = rng.randint(*continuous_flip_amount)
#random periods at which to shuffle
flip_periods = [rng.uniform(0, clip.duration) for _ in range(flip_amt)]
flip_periods.sort() #in ascending order
all_clips = []
last_period = 0
for period in flip_periods:
new_clip = clip.subclipped(last_period, period)
all_clips.append(new_clip)
last_period = period
new_clip = clip.subclipped(last_period, clip.duration)
all_clips.append(new_clip)
for i in range(len(all_clips)):
# Either flip on the X, or Y, or don't flip at all
effect_to_use = rng.choice((vfx.MirrorX(), vfx.MirrorY(), None))
if effect_to_use is not None:
all_clips[i] = all_clips[i].with_effects((effect_to_use,))
final_clip = concatenate_videoclips(all_clips)
return final_clip
class RepeatMultiple(Effect):
def apply(self, clip: Clip) -> Clip: #repeat a video multiple times
random_dur = rng.uniform(*repeat_video_amount)
repeat_amt = int((clip.duration / random_dur) * 0.5)
start_offset = rng.uniform(0, clip.duration - random_dur)
new_clip = clip.subclipped(start_offset, start_offset + random_dur)
final_clip = concatenate_videoclips([new_clip]*repeat_amt)
return final_clip
# take a clip, split it into multiple parts, shuffle those parts
class ShuffleVideo(Effect):
def apply(self, clip: Clip):
#how many times the clip will be split and shuffled
shuffle_amt = rng.randint(*shuffle_video_amount)
#random periods at which to shuffle
shuffle_periods = [rng.uniform(0, clip.duration) for _ in range(shuffle_amt)]
shuffle_periods.sort() #in ascending order
all_clips = []
last_period = 0
for period in shuffle_periods:
new_clip = clip.subclipped(last_period, period)
all_clips.append(new_clip)
last_period = period
new_clip = clip.subclipped(last_period, clip.duration)
all_clips.append(new_clip)
rng.shuffle(all_clips) #shuffle around the clips to get the final result
final_clip = concatenate_videoclips(all_clips)
return final_clip
# makes the clip "rotate" by flipping and reversing the second part of the clip
class FlipRotationVideo(Effect):
def apply(self, clip: Clip):
random_duration = rng.uniform(0.1, 0.3)
start_offset = rng.uniform(0, clip.duration - random_duration)
first_clip = clip.subclipped(start_offset, start_offset+random_duration)
# Flip horizontal, then reverse video
second_clip = first_clip.copy().with_effects((vfx.MirrorX(), vfx.TimeMirror()))
# Speed up the clips
first_clip = first_clip.with_effects((vfx.MultiplySpeed(1.5),))
second_clip = second_clip.with_effects((vfx.MultiplySpeed(1.5),))
# Number of times to do this flip-rotation
flip_rotation_count = random.randint(*flip_rotation_amount)
return concatenate_videoclips([first_clip, second_clip] * flip_rotation_count)
videoEffects = [
# Speed up or slow down
(vfx.MultiplySpeed(rng.uniform(*random_speed_amount)),),
@ -165,12 +82,12 @@ videoEffects = [
(vfx.TimeSymmetrize(), vfx.MultiplySpeed(rng.uniform(1.4, 2.3))),
# Change contrast
(vfx.LumContrast(lum=0, contrast=rng.uniform(*contrast_amount)),),
# Continuously repeat the video
(RepeatMultiple(),),
# Flip the video on the x and y axis multiple times
(ContinuousFlipVideo(),),
(ShuffleVideo(),),
(FlipRotationVideo(),)
# Custom effects we use to mimic various YTP-like effects
(custom_effects.RepeatMultiple(rng, *repeat_video_amount),),
(custom_effects.ContinuousFlipVideo(rng, *continuous_flip_amount),),
(custom_effects.ShuffleVideo(rng, *shuffle_video_amount),),
(custom_effects.FlipRotationVideo(rng, *flip_rotation_amount),)
]
videoObjects = []

119
src/custom_effects.py Normal file
View file

@ -0,0 +1,119 @@
# Standard modules
import random
from dataclasses import dataclass
# MoviePy modules
from moviepy import concatenate_videoclips, Effect, vfx
from moviepy.Clip import Clip
@dataclass
class ContinuousFlipVideo(Effect):
"""Flip a video on its X-axis or Y-axis at random."""
rng: random.Random
flip_amount_min: int = 1
flip_amount_max: int = 7
def apply(self, clip: Clip): #flip a video multiple times over its duration
#how many times the clip will be flipped
flip_amt = self.rng.randint(self.flip_amount_min, self.flip_amount_max)
#random periods at which to shuffle
flip_periods = [self.rng.uniform(0, clip.duration) for _ in range(flip_amt)]
flip_periods.sort() #in ascending order
all_clips = []
last_period = 0
for period in flip_periods:
new_clip = clip.subclipped(last_period, period)
all_clips.append(new_clip)
last_period = period
new_clip = clip.subclipped(last_period, clip.duration)
all_clips.append(new_clip)
for i in range(len(all_clips)):
# Either flip on the X, or Y, or don't flip at all
effect_to_use = self.rng.choice((vfx.MirrorX(), vfx.MirrorY(), None))
if effect_to_use is not None:
all_clips[i] = all_clips[i].with_effects((effect_to_use,))
final_clip = concatenate_videoclips(all_clips)
return final_clip
@dataclass
class RepeatMultiple(Effect):
"""Repeat a video clip multiple times in quick succession."""
rng: random.Random
repeat_video_duration_min: float = 0.01
repeat_video_duration_max: float = 2
def apply(self, clip: Clip) -> Clip:
random_dur = self.rng.uniform(self.repeat_video_duration_min, self.repeat_video_duration_max)
repeat_amt = int((clip.duration / random_dur) * 0.5)
start_offset = self.rng.uniform(0, clip.duration - random_dur)
new_clip = clip.subclipped(start_offset, start_offset + random_dur)
final_clip = concatenate_videoclips([new_clip]*repeat_amt)
return final_clip
@dataclass
class ShuffleVideo(Effect):
"""Splice a video into multiple parts and then shuffle those parts."""
rng: random.Random
shuffle_amount_min: int = 20
shuffle_amount_max: int = 50
def apply(self, clip: Clip):
#how many times the clip will be split and shuffled
shuffle_amt = self.rng.randint(self.shuffle_amount_min, self.shuffle_amount_max)
#random periods at which to shuffle
shuffle_periods = [self.rng.uniform(0, clip.duration) for _ in range(shuffle_amt)]
shuffle_periods.sort() #in ascending order
all_clips = []
last_period = 0
for period in shuffle_periods:
new_clip = clip.subclipped(last_period, period)
all_clips.append(new_clip)
last_period = period
new_clip = clip.subclipped(last_period, clip.duration)
all_clips.append(new_clip)
self.rng.shuffle(all_clips) #shuffle around the clips to get the final result
final_clip = concatenate_videoclips(all_clips)
return final_clip
@dataclass
class FlipRotationVideo(Effect):
"""Makes a clip mimic rotation by duplicating the clip, then reversing and flipping that second clip."""
rng: random.Random
flip_rotation_min: int = 1
flip_rotation_max: int = 4
def apply(self, clip: Clip):
random_duration = self.rng.uniform(0.1, 0.3)
start_offset = self.rng.uniform(0, clip.duration - random_duration)
first_clip = clip.subclipped(start_offset, start_offset+random_duration)
# Flip horizontal, then reverse video
second_clip = first_clip.copy().with_effects((vfx.MirrorX(), vfx.TimeMirror()))
# Speed up the clips
first_clip = first_clip.with_effects((vfx.MultiplySpeed(1.5),))
second_clip = second_clip.with_effects((vfx.MultiplySpeed(1.5),))
# Number of times to do this flip-rotation
flip_rotation_count = self.rng.randint(self.flip_rotation_min, self.flip_rotation_max)
return concatenate_videoclips([first_clip, second_clip] * flip_rotation_count)