Main script + update README

This commit is contained in:
Chev 2020-09-18 20:13:06 -07:00
parent a801a18130
commit 65a2dc82a9
2 changed files with 186 additions and 1 deletions

View file

@ -5,7 +5,7 @@ Generates an output video with overlayed audio and effects using a list of audio
Here's how it works:
1. Gets all video & audio sources in the `VideoSources` and `AudioSources` folders.
2. Gets a seed for the random module, which can be used if a user wants to re-generate the same video again.
3. Chooses _n_ random videos where _n_ is the number of videos the user wants to merge into the final results (e.g. if you want to merge 40 different videos, it chooses 40 random videos). The max amount of random videos is capped to the number of video files in the `VideoSources` folder.
3. Chooses _n_ random videos where _n_ is the number of videos the user wants to merge into the final results (e.g. if you want to merge 40 different videos, it chooses 40 random videos). The script will first to attempt to avoid duplicate videos. If the chosen video amount is higher than the available videos, then the script will add duplicate videos to meet that amount.
4. Applies a bunch of random effects to the video files, which include trimming the video to be a random short length, mirroring the video, speeding it up or slowing it down, reversing the video, as well as other effects.
5. Merges all the now effect-applied videos into one big video.
6. Applies effects to the audio files, which include trimming the audio to be a random short length. The script will also attemt to repeat audio clips less than 5 seconds to give a repetitive-like nature to the end result.

185
ShitpostGenerator.py Normal file
View file

@ -0,0 +1,185 @@
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
def BadQuality(clip):
w, h = clip.size
return clip.resize((rng.randint(32, w), rng.randint(32, h))).resize((w, h))
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
lambda v: BadQuality(v)
]
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()