mirror of
https://github.com/chev2/shitpost-video-generator.git
synced 2025-10-30 08:12:03 +00:00
180 lines
7.2 KiB
Python
180 lines
7.2 KiB
Python
import moviepy.audio
|
|
import random
|
|
from sys import maxsize
|
|
from os import listdir
|
|
from moviepy import editor
|
|
from moviepy.video import fx
|
|
|
|
videoSourceFolder = "VideoSources"
|
|
audioSourceFolder = "AudioSources"
|
|
|
|
videoFiles = [videoSourceFolder + "/" + vid for vid in listdir(videoSourceFolder)]
|
|
audioFiles = [audioSourceFolder + "/" + vid for vid in listdir(audioSourceFolder)]
|
|
|
|
chosenSeed = input("Video seed (or 'any' to use system time): ")
|
|
while not chosenSeed.isdecimal() and not chosenSeed in ["any", "skip", "default", "time"]:
|
|
chosenSeed = input("Video seed (or 'any' to use system time): ")
|
|
|
|
seed = int(chosenSeed) if chosenSeed.isdecimal() else random.randrange(maxsize) #get a chosen or random seed to use and reference later
|
|
|
|
print(f'Chose seed: {seed}')
|
|
|
|
rng = random.Random(seed)
|
|
|
|
print(f'Found {len(videoFiles)} videos and {len(audioFiles)} sounds')
|
|
|
|
def ContinuousFlipVideo(clip): #flip a video multiple times over its duration
|
|
flipAmount = rng.randint(1, 7) #how many times the clip will be flipped
|
|
flipPeriods = [rng.uniform(0, clip.duration) for _ in range(flipAmount)] #random periods at which to shuffle
|
|
|
|
flipPeriods.sort() #in ascending order
|
|
allClips = []
|
|
lastPeriod = 0
|
|
|
|
for period in flipPeriods:
|
|
newClip = clip.subclip(lastPeriod, period)
|
|
allClips.append(newClip)
|
|
lastPeriod = period
|
|
|
|
newClip = clip.subclip(lastPeriod, clip.duration)
|
|
allClips.append(newClip)
|
|
|
|
for i in range(len(allClips)):
|
|
clip = allClips[i]
|
|
allClips[i] = rng.choice([fx.mirror_x.mirror_x, fx.mirror_y.mirror_y, lambda v: v])(allClips[i]) #flip on the x, or y, or don't flip
|
|
|
|
finalClip = editor.concatenate_videoclips(allClips)
|
|
|
|
return finalClip
|
|
|
|
def RepeatVideo(clip): #repeat a video multiple times
|
|
randomDuration = rng.uniform(0.01, 0.2)
|
|
repeatAmount = int((clip.duration/randomDuration)*0.5)
|
|
|
|
startOffset = rng.uniform(0, clip.duration - randomDuration)
|
|
newClip = clip.subclip(startOffset, startOffset+randomDuration)
|
|
|
|
finalClip = editor.concatenate_videoclips([newClip]*repeatAmount)
|
|
return finalClip
|
|
|
|
def ShuffleVideo(clip): #take a clip, split it into multiple parts, shuffle those parts
|
|
shuffleAmount = rng.randint(20, 50) #how many times the clip will be split and shuffled
|
|
shufflePeriods = [rng.uniform(0, clip.duration) for _ in range(shuffleAmount)] #random periods at which to shuffle
|
|
|
|
shufflePeriods.sort() #in ascending order
|
|
allClips = []
|
|
lastPeriod = 0
|
|
|
|
for period in shufflePeriods:
|
|
newClip = clip.subclip(lastPeriod, period)
|
|
allClips.append(newClip)
|
|
lastPeriod = period
|
|
|
|
newClip = clip.subclip(lastPeriod, clip.duration)
|
|
allClips.append(newClip)
|
|
rng.shuffle(allClips) #shuffle around the clips to get the final result
|
|
finalClip = editor.concatenate_videoclips(allClips)
|
|
|
|
return finalClip
|
|
|
|
videoEffects = [
|
|
lambda v: fx.speedx.speedx(v, rng.uniform(0.7, 3)), #speed up/slow down
|
|
lambda v: fx.mirror_x.mirror_x(v), #mirror on the x axis
|
|
lambda v: fx.time_mirror.time_mirror(v), #reverse the video
|
|
lambda v: v.fx(fx.time_symmetrize.time_symmetrize).fx(fx.speedx.speedx, factor=rng.uniform(1.4, 2.3)), #forward + reverse with speed up
|
|
lambda v: RepeatVideo(v), #repeat the video multiple times
|
|
lambda v: ShuffleVideo(v), #shuffle up parts of the video for a glitch-like effect
|
|
lambda v: ContinuousFlipVideo(v), #flip the video on the x and y axis multiple times
|
|
lambda v: fx.lum_contrast.lum_contrast(v, lum=0, contrast=rng.uniform(0.3, 2)) #change contrast
|
|
]
|
|
|
|
videoObjects = []
|
|
audioObjects = []
|
|
|
|
videoAmount = input("Amount of videos: ")
|
|
while not videoAmount.isdecimal():
|
|
videoAmount = input("Amount of videos: ")
|
|
|
|
videoAmount = int(videoAmount)
|
|
|
|
randomVideos = rng.sample(videoFiles, min(videoAmount, len(videoFiles)))
|
|
if videoAmount > len(videoFiles): #if there is a higher chosen amount than total, re-use videos
|
|
videoAmountToAdd = videoAmount - len(videoFiles)
|
|
print(f'Chosen video amount is higher than available video amount - re-using {videoAmountToAdd} videos...')
|
|
additionalVideos = rng.choices(videoFiles, k=videoAmountToAdd)
|
|
randomVideos += additionalVideos
|
|
|
|
print(f"Compiling {videoAmount} videos...", end="")
|
|
|
|
for video in randomVideos:
|
|
print(".", end="")
|
|
|
|
newClip = editor.VideoFileClip(video).resize(height=480) #target_resolution=(512, 512)
|
|
|
|
randomDuration = rng.uniform(0.5, 3.5) #0.5, 2.6
|
|
if newClip.duration > randomDuration:
|
|
startOffset = rng.uniform(0, newClip.duration - randomDuration)
|
|
newClip = newClip.subclip(startOffset, startOffset+randomDuration)
|
|
|
|
if rng.choice([True, True, False]):
|
|
newClip = rng.choice(videoEffects)(newClip) #apply a random effect
|
|
|
|
videoObjects.append(newClip)
|
|
|
|
print("Finished compiling videos.")
|
|
|
|
finalVideo = editor.concatenate_videoclips(videoObjects, method="compose") # method="compose"
|
|
|
|
audioAmount = int(videoAmount*0.75)
|
|
|
|
randomSounds = rng.sample(audioFiles, min(audioAmount, len(audioFiles)))
|
|
|
|
if audioAmount > len(audioFiles):
|
|
audioAmountToAdd = audioAmount - len(audioFiles)
|
|
print(f'Chosen audio amount is higher than available audio amount - re-using {audioAmountToAdd} audio sources...')
|
|
additionalAudio = rng.choices(audioFiles, k=audioAmountToAdd)
|
|
randomSounds += additionalAudio
|
|
|
|
print(f"Compiling {audioAmount} sounds...", end="")
|
|
|
|
copiedSoundAmount = 0
|
|
for audio in randomSounds:
|
|
print(".", end="")
|
|
|
|
newClip = editor.AudioFileClip(audio)
|
|
newClip = moviepy.audio.fx.volumex.volumex(newClip, 0.5) # modify volume
|
|
|
|
if newClip.duration > 5: #for long clips
|
|
randomDuration = rng.uniform(0.7, 6) # crop audio duration
|
|
if newClip.duration > randomDuration: # if the audio is longer than the cropped duration, crop the audio at a random position
|
|
startOffset = rng.choice([rng.uniform(0, newClip.duration - randomDuration), 0]) #either use a random offset, or start at beginning of audio clip
|
|
newClip = newClip.subclip(startOffset, startOffset+randomDuration)
|
|
|
|
newClip = newClip.set_start(rng.uniform(0, finalVideo.duration-newClip.duration)) # move audio around video length
|
|
audioObjects.append(newClip)
|
|
else:
|
|
clipPosition = rng.uniform(0, finalVideo.duration-newClip.duration)
|
|
|
|
newClip = newClip.set_start(clipPosition) # move audio around video length
|
|
audioObjects.append(newClip)
|
|
for i in range(rng.randint(1, 5)): #add a copy of the clip near the original clip
|
|
print(".", end="")
|
|
copiedSoundAmount += 1
|
|
|
|
minimumRange = max(0, clipPosition-2)
|
|
maximumRange = min(finalVideo.duration, clipPosition+2) - newClip.duration
|
|
|
|
copiedClip = newClip.set_start(rng.uniform(minimumRange, maximumRange)) # move audio around video length
|
|
audioObjects.append(copiedClip)
|
|
|
|
print(f"Finished compiling audio. Added {copiedSoundAmount} duplicate sounds, total {audioAmount+copiedSoundAmount}.")
|
|
|
|
newAudioClip = editor.CompositeAudioClip([finalVideo.audio] + audioObjects)
|
|
|
|
finalVideo.audio = newAudioClip
|
|
finalVideo.write_videofile(f'final_result_{seed}_{videoAmount}.mp4', fps=30, audio_bitrate="96k")
|
|
|
|
for video in videoObjects:
|
|
video.close()
|
|
for audio in audioObjects:
|
|
audio.close()
|