From 37b261c668e300a8620a44b2378fb431a2554d8f Mon Sep 17 00:00:00 2001 From: Chev Date: Sun, 16 Jul 2023 21:51:11 -0700 Subject: [PATCH] Major changes - Update .gitignore - Rename input and output folders to be lowercase - Add some basic configuration capability - Rename a lot of variables --- .gitignore | 35 ++- ShitpostGenerator.py | 188 -------------- .../BOOM.mp3 | Bin .../Bruh Sound Effect #2.mp3 | Bin .../Damn Son.mp3 | Bin .../DOOR STUCK! DOOR STUCK!.mp4 | Bin .../FUS RO DAH!!!.mp4 | Bin .../Me at the zoo.mp4 | Bin main.py | 243 ++++++++++++++++++ 9 files changed, 268 insertions(+), 198 deletions(-) delete mode 100644 ShitpostGenerator.py rename {AudioSources => input_audio_sources}/BOOM.mp3 (100%) rename {AudioSources => input_audio_sources}/Bruh Sound Effect #2.mp3 (100%) rename {AudioSources => input_audio_sources}/Damn Son.mp3 (100%) rename {VideoSources => input_video_sources}/DOOR STUCK! DOOR STUCK!.mp4 (100%) rename {VideoSources => input_video_sources}/FUS RO DAH!!!.mp4 (100%) rename {VideoSources => input_video_sources}/Me at the zoo.mp4 (100%) create mode 100644 main.py diff --git a/.gitignore b/.gitignore index fd77386..1bbae9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,37 @@ # Repository-specific -VideoSources/*.mp4 -AudioSources/*.mp3 -VideoToBeConverted/*.mp4 -RecodeVideoFiles.py +recodevideofiles.py +*.7z +# Video file formats *.mp4 +*.webm +*.mkv +*.mov + +# Audio file formats +*.mp3 +*.ogg +*.wav +*.flac # Repository-specific - only allow these video and audio sources -!VideoSources/DOOR STUCK! DOOR STUCK!.mp4 -!VideoSources/FUS RO DAH!!!.mp4 -!VideoSources/Me at the zoo.mp4 -!AudioSources/BOOM.mp3 -!AudioSources/Bruh Sound Effect #2.mp3 -!AudioSources/Damn Son.mp3 +!input_video_sources/DOOR STUCK! DOOR STUCK!.mp4 +!input_video_sources/FUS RO DAH!!!.mp4 +!input_video_sources/Me at the zoo.mp4 +!input_audio_sources/BOOM.mp3 +!input_audio_sources/Bruh Sound Effect #2.mp3 +!input_audio_sources/Damn Son.mp3 + +# Linux +.directory # Visual Studio Code *.code-workspace +# +# GitHub Python .gitignore +# + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/ShitpostGenerator.py b/ShitpostGenerator.py deleted file mode 100644 index 8f14d49..0000000 --- a/ShitpostGenerator.py +++ /dev/null @@ -1,188 +0,0 @@ -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) - -shouldUseEffects = input("Apply video effects? (y/n): ") -while not shouldUseEffects in ["y", "yes", "true", "n", "no", "false"]: - shouldUseEffects = input("Apply video effects? (y/n): ") - -shouldUseEffects = True if shouldUseEffects in ["y", "yes", "true"] else False - -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]) and shouldUseEffects: - 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, 13) # 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) - -finalVideoFilename = f'final_result_{seed}_{videoAmount}{"_effects" if shouldUseEffects else ""}.mp4' - -finalVideo.audio = newAudioClip -finalVideo.write_videofile(finalVideoFilename, fps=30, audio_bitrate="96k") - -for video in videoObjects: - video.close() -for audio in audioObjects: - audio.close() diff --git a/AudioSources/BOOM.mp3 b/input_audio_sources/BOOM.mp3 similarity index 100% rename from AudioSources/BOOM.mp3 rename to input_audio_sources/BOOM.mp3 diff --git a/AudioSources/Bruh Sound Effect #2.mp3 b/input_audio_sources/Bruh Sound Effect #2.mp3 similarity index 100% rename from AudioSources/Bruh Sound Effect #2.mp3 rename to input_audio_sources/Bruh Sound Effect #2.mp3 diff --git a/AudioSources/Damn Son.mp3 b/input_audio_sources/Damn Son.mp3 similarity index 100% rename from AudioSources/Damn Son.mp3 rename to input_audio_sources/Damn Son.mp3 diff --git a/VideoSources/DOOR STUCK! DOOR STUCK!.mp4 b/input_video_sources/DOOR STUCK! DOOR STUCK!.mp4 similarity index 100% rename from VideoSources/DOOR STUCK! DOOR STUCK!.mp4 rename to input_video_sources/DOOR STUCK! DOOR STUCK!.mp4 diff --git a/VideoSources/FUS RO DAH!!!.mp4 b/input_video_sources/FUS RO DAH!!!.mp4 similarity index 100% rename from VideoSources/FUS RO DAH!!!.mp4 rename to input_video_sources/FUS RO DAH!!!.mp4 diff --git a/VideoSources/Me at the zoo.mp4 b/input_video_sources/Me at the zoo.mp4 similarity index 100% rename from VideoSources/Me at the zoo.mp4 rename to input_video_sources/Me at the zoo.mp4 diff --git a/main.py b/main.py new file mode 100644 index 0000000..a617831 --- /dev/null +++ b/main.py @@ -0,0 +1,243 @@ +import moviepy.audio +import random +from sys import maxsize +from os import listdir, mkdir, path +from moviepy import editor +from moviepy.video import fx + +''' + TODO: + flash random images in short bursts at long intervals + try to overlap videos more and distort them + spread out audio duplication a bit, so they don't end up directly next to one another + +''' + +videoSourceFolder = "input_video_sources" +audioSourceFolder = "input_audio_sources" + +videoFiles = [videoSourceFolder + "/" + vid for vid in listdir(videoSourceFolder)] +audioFiles = [audioSourceFolder + "/" + vid for vid in listdir(audioSourceFolder)] + +video_clip_times = (1.0, 2.5) #default: 0.5, 3.5. chaos: 0.3, 1.2 +audio_clip_times = (0.7, 3) #default: 0.7, 13. chaos: 0.7, 3.0 + +audio_multiplier = 1.5 #audio amount multiplier (based off the amount of videos), e.g. 60 videos with a multiplier of 0.75 means 45 audio cues. default: 0.75. chaos: 1.5 + +#(min, max) random values range, inclusive +continuous_flip_amount = (7, 14) #integer. default: 1, 7 +repeat_video_amount = (0.01, 0.2) #float. default: 0.01, 0.2 +shuffle_video_amount = (20, 50) #integer. default: 20, 50 +flip_rotation_amount = (1, 4) #integer. default: 1, 4 +random_speed_amount = (0.7, 3) #float. default: 0.7, 3 +contrast_amount = (0.3, 2) #float. default: 0.3, 2 + +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') + +# Returns a progress bar string, useful for measuring progress in command-line +def ProgressBar(current_index, max_index, progress_bar_len:int = 20, include_percent:bool = True, percent_digits:int = 2, + symbol_middle:str = "█", symbol_begin:str = "|", symbol_end:str = "|"): + # Used for the progress bar - gets progress 0-1 range, + # then multiplies it by the progress bar length + percent_done = int(current_index / max_index * progress_bar_len) + + percentage = f" {round((current_index / max_index) * 100, percent_digits)}%" if include_percent else "" + + return symbol_begin + (symbol_middle * percent_done + " " * (progress_bar_len - percent_done)) + symbol_end + percentage + +def ContinuousFlipVideo(clip): #flip a video multiple times over its duration + flip_amt = rng.randint(*continuous_flip_amount) #how many times the clip will be flipped + flip_periods = [rng.uniform(0, clip.duration) for _ in range(flip_amt)] #random periods at which to shuffle + + flip_periods.sort() #in ascending order + all_clips = [] + last_period = 0 + + for period in flip_periods: + new_clip = clip.subclip(last_period, period) + all_clips.append(new_clip) + last_period = period + + new_clip = clip.subclip(last_period, clip.duration) + all_clips.append(new_clip) + + for i in range(len(all_clips)): + clip = all_clips[i] + all_clips[i] = rng.choice([fx.mirror_x.mirror_x, fx.mirror_y.mirror_y, lambda v: v])(all_clips[i]) #flip on the x, or y, or don't flip + + final_clip = editor.concatenate_videoclips(all_clips) + + return final_clip + +def RepeatVideo(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.subclip(start_offset, start_offset+random_dur) + + final_clip = editor.concatenate_videoclips([new_clip]*repeat_amt) + return final_clip + +def ShuffleVideo(clip): #take a clip, split it into multiple parts, shuffle those parts + shuffle_amt = rng.randint(*shuffle_video_amount) #how many times the clip will be split and shuffled + shuffle_periods = [rng.uniform(0, clip.duration) for _ in range(shuffle_amt)] #random periods at which to shuffle + + shuffle_periods.sort() #in ascending order + all_clips = [] + last_period = 0 + + for period in shuffle_periods: + new_clip = clip.subclip(last_period, period) + all_clips.append(new_clip) + last_period = period + + new_clip = clip.subclip(last_period, clip.duration) + all_clips.append(new_clip) + rng.shuffle(all_clips) #shuffle around the clips to get the final result + final_clip = editor.concatenate_videoclips(all_clips) + + return final_clip + +def FlipRotationVideo(clip): #makes the clip "rotate" by flipping and reversing the second part of the clip + random_duration = rng.uniform(0.1, 0.3) + + start_offset = rng.uniform(0, clip.duration - random_duration) + first_clip = clip.subclip(start_offset, start_offset+random_duration) + + second_clip = fx.time_mirror.time_mirror(fx.mirror_x.mirror_x(first_clip.copy())) #flip horizontal, then reverse video + + both_clips = [fx.speedx.speedx(first_clip, 1.5), fx.speedx.speedx(second_clip, 1.5)] + + return editor.concatenate_videoclips(both_clips*random.randint(*flip_rotation_amount)) + +videoEffects = [ + lambda v: fx.speedx.speedx(v, rng.uniform(*random_speed_amount)), #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: FlipRotationVideo(v), + lambda v: fx.lum_contrast.lum_contrast(v, lum=0, contrast=rng.uniform(*contrast_amount)) #change contrast +] + +videoObjects = [] +audioObjects = [] + +videoAmount = input("Amount of videos: ") +while not videoAmount.isdecimal(): + videoAmount = input("Amount of videos: ") + +videoAmount = int(videoAmount) + +shouldUseEffects = input("Apply video effects? (y/n): ") +while not shouldUseEffects.lower() in ["y", "yes", "true", "n", "no", "false"]: + shouldUseEffects = input("Apply video effects? (y/n): ") + +shouldUseEffects = True if shouldUseEffects.lower() in ["y", "yes", "true"] else False + +randomVideos = rng.sample(videoFiles, min(videoAmount, len(videoFiles))) +#randomVideos = rng.choices(videoFiles, k=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="\r") + +for index, video in enumerate(randomVideos): + print(f"Compiling {videoAmount} videos... {ProgressBar(index, len(randomVideos), progress_bar_len=40)}", end="\r") + + newClip = editor.VideoFileClip(video).resize(height=480) #target_resolution=(512, 512) + + randomDuration = rng.uniform(*video_clip_times) + if newClip.duration > randomDuration: + startOffset = rng.uniform(0, newClip.duration - randomDuration) + newClip = newClip.subclip(startOffset, startOffset+randomDuration) + + if rng.choice([True, True, False]) and shouldUseEffects: + newClip = rng.choice(videoEffects)(newClip) #apply a random effect + + videoObjects.append(newClip) + +print(f"Compiling {videoAmount} videos... {ProgressBar(1, 1, progress_bar_len=40)}") +print("Finished compiling videos.") + +finalVideo = editor.concatenate_videoclips(videoObjects, method="compose") # method="compose" + +audioAmount = int(videoAmount*audio_multiplier) + +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="\r") + +copiedSoundAmount = 0 +for index, audio in enumerate(randomSounds): + print(f"Compiling {audioAmount} sounds... {ProgressBar(index, len(randomSounds), progress_bar_len=40)}", end="\r") + + newClip = editor.AudioFileClip(audio) + newClip = moviepy.audio.fx.volumex.volumex(newClip, 0.8) # modify volume + + if newClip.duration > 5: #for long clips + randomDuration = rng.uniform(*audio_clip_times) # 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: + # Place to position the audio clip - could be anywhere from the final video's start all the way to its full duration + clipPosition = rng.uniform(0, finalVideo.duration-newClip.duration) + + newClip = newClip.set_start(clipPosition) # move audio around video length + audioObjects.append(newClip) + + # Add duplicates of this audio clip + for i in range(rng.randint(1, 5)): + copiedSoundAmount += 1 + + # Max 0 and clip position - 2 so it doesn't go into negative clip position (if near beginning of video) + minimumRange = max(0, clipPosition - 2) + # Minimum between final video duration and clip position + 2 so it doesn't go over video length (if near end of video) + 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"Compiling {audioAmount} sounds... {ProgressBar(1, 1, progress_bar_len=40)}") +print(f"Finished compiling audio. Added {copiedSoundAmount} duplicate sounds, total {audioAmount+copiedSoundAmount}.") + +# The video's filename +finalVideoFilename = f'output/result_seed-{seed}_{videoAmount}{"_effects" if shouldUseEffects else ""}.mp4' + +# Create output directory if it doesn't exist +if not path.exists("output"): mkdir("output") + +finalVideo.audio = editor.CompositeAudioClip([finalVideo.audio] + audioObjects) +finalVideo.write_videofile(finalVideoFilename, fps=30, audio_bitrate="96k") + +# Close all file streams +for video in videoObjects: + video.close() +for audio in audioObjects: + audio.close()