diff --git a/curb_your_enthusiasm.lua b/curb_your_enthusiasm.lua new file mode 100644 index 0000000..987a4a7 --- /dev/null +++ b/curb_your_enthusiasm.lua @@ -0,0 +1,126 @@ + +local TMP_FOLDER = '/tmp/memebot/' + +local internet = require 'internet' + +-------------------------------------------------------------------------------- + +local function ensure_tmp_folder_exists () + os.execute(('mkdir --parents "%s"'):format(TMP_FOLDER)) +end + +local function video_length (video_filename) + assert(type(video_filename) == 'string') + local f = io.popen(('ffprobe -i "%s" -show_entries format=duration -v quiet -of csv="p=0"'):format(video_filename), 'r') + local str = f:read '*all' + local len = tonumber(str) + assert(type(len) == 'number') + f:close() + return len +end + +local function video_silences (video_filename, decibel, duration) + assert(type(video_filename) == 'string') + assert(type(decibel) == 'number') + assert(type(duration) == 'number') + -- + local log_filename = os.tmpname() + os.execute(('ffmpeg -i "%s" -af silencedetect=n=%sdB:d=%s -f null - 1> /dev/null 2> %s'):format(video_filename, decibel, duration, log_filename)) + local f = io.open(log_filename) + local silences = {} + for line in f:lines() do + local silence_end, duration = line:gsub('\027%[.-;', ''):match '^%[silencedetect @ 0x%x+%]%s*silence_end:%s*([%d.]+)%s*|%s*silence_duration:%s*([%d.]+)$' + if silence_end then + local silence_end, duration = tonumber(silence_end), tonumber(duration) + silences[#silences+1] = { + start = silence_end - duration, + stop = silence_end, + duration = duration + } + end + end + f:close() + return silences +end + +local function video_silence_at_end (video_filename, ...) + assert(type(video_filename) == 'string') + -- + local silences = video_silences(video_filename, ...) + local duration = video_length(video_filename) + -- + for _, silence in ipairs(silences) do + if math.abs(silence.stop - duration) < 0.1 then + return silence + end + end + -- + return nil +end + +local function paste_audio_onto_video (video_filename, audio_filename, timestamp) + timestamp = timestamp or 0 + assert(type(timestamp) == 'number') + assert(type(video_filename) == 'string') + assert(type(audio_filename) == 'string') + print('Hah!', timestamp) + + -- Generate silence + local silence_filename = TMP_FOLDER..'silence.mp3' + os.execute(('ffmpeg -y -f lavfi -i anullsrc=channel_layout=5.1:sample_rate=48000 -t %s %s &> /dev/null'):format(timestamp, silence_filename)) + + -- Paste audio onto video + local output_filename = TMP_FOLDER..'output.webm' + local cmd = (('ffmpeg -y -i "%s" -i "concat:%s|%s" -filter_complex "[0:a:0][1:a:0]amerge=inputs=2[a]" -map 0:v:0 -map "[a]" -c:v copy -c:a libvorbis -ac 2 -shortest %s &> /dev/null'):format(video_filename, silence_filename, audio_filename, output_filename)) + os.execute(cmd) + + return output_filename +end + +-------------------------------------------------------------------------------- + +local CURB_YOUR_ENTHUSIASM_THEME_FILENAME = './sound/curb_your_enthusiasm_theme.mp3' +local DEFAULT_THEME_LENGTH = 10 + +local function determine_timestamp_for_curb_your_video (video_filename) + assert(type(video_filename) == 'string') + -- + local silence_start + local silence = video_silence_at_end(video_filename, -18, 1) + local len = video_length(video_filename) + local silence_end = len + local silence_start = silence and silence.start or (len - 5) + local silence_diff = silence_end - silence_start + + silence_end = math.max(len/2, silence_end - math.min(5, silence_diff)) + local silence_diff = silence_end - silence_start + silence_start = math.max(len/2, silence_start + math.min(3, silence_diff)) + + assert(len/2 <= silence_start and silence_start <= len) + assert(len/2 <= silence_end and silence_end <= len) + return (silence_start + silence_end) / 2 +end + +local function curb_your_video (video_url, timestamp) + assert(type(video_url) == 'string') + assert(type(timestamp) == 'number' or timestamp == nil) + -- Download video + ensure_tmp_folder_exists() + local video_filename = internet.download_video(video_url) + -- Figure out timestamp to start theme + if timestamp == nil then + timestamp = determine_timestamp_for_curb_your_video(video_filename) + assert(type(timestamp) == 'number') + assert(timestamp < video_length(video_filename)) + elseif timestamp < 0 then + timestamp = video_length(video_filename) + timestamp + end + -- Paste audio + print(timestamp) + return paste_audio_onto_video(video_filename, CURB_YOUR_ENTHUSIASM_THEME_FILENAME, timestamp) +end + +-------------------------------------------------------------------------------- + +return curb_your_video + diff --git a/internet.lua b/internet.lua index a26945e..28fc952 100644 --- a/internet.lua +++ b/internet.lua @@ -263,6 +263,13 @@ function internet.download_file (url, filename) f:close() end +function internet.download_video (url) + assert(type(url) == 'string') + local video_filename = os.tmpname() + os.execute(('youtube-dl "%s" -o "%s" &> /dev/null'):format(url, video_filename)) + return video_filename..'.mkv' +end + -------------------------------------------------------------------------------- return internet diff --git a/memes.lua b/memes.lua index d00c652..59ef9ae 100644 --- a/memes.lua +++ b/memes.lua @@ -41,16 +41,22 @@ local function copy_remotely (origin_server, origin_path, target_server, target_ os.execute('scp '..origin..' '..target..' > /dev/null') end -local function save_to_cloud (img) +local function save_file_to_dcav (filename) + assert(type(filename) == 'string') + -- Upload to dcav + local ext = filename:match '%.(%a+)$' + local remote_name = 'otmemes_'..os.time()..'.'..ext + copy_remotely('localhost', filename, CONFIG.STORAGE_SERVER, CONFIG.STORAGE_SERVER_PATH..remote_name) + return CONFIG.STORAGE_DIR_URL..remote_name +end + +local function save_img_to_cloud (img) assert(img) -- - local MEME_OUTPUT = CONFIG.IMGGEN_PATH_OUTPUT..'meme.png' - img:save (MEME_OUTPUT) + local filename = CONFIG.IMGGEN_PATH_OUTPUT..'meme.png' + img:save (filename) img:free() - -- Upload to dcav - local img_name = 'otmemes_'..os.time()..'.png' - copy_remotely('localhost', MEME_OUTPUT, CONFIG.STORAGE_SERVER, CONFIG.STORAGE_SERVER_PATH..img_name) - return CONFIG.STORAGE_DIR_URL..img_name + return save_file_to_dcav(filename) end -------------------------------------------------------------------------------- @@ -351,7 +357,7 @@ local function generate_comparison_meme_generator (positions) base_img = draw_droste_effect(base_img, droste_positions_from_topics(topics, rand_positions)) -- - return save_to_cloud(base_img) + return save_img_to_cloud(base_img) end end @@ -429,11 +435,9 @@ local function generate_brain_explosion_image (topics) base_img = draw_droste_effect(base_img, droste_positions_from_topics(topics, BRAIN_DROSTE_POS)) -- Save - return save_to_cloud(base_img) + return save_img_to_cloud(base_img) end - - local function is_comparison_message (message) local leq, gep = message:match '<', message:match '>' return leq and not gep and '<' or not leq and gep and '>' @@ -499,8 +503,11 @@ local function generate_bait_link() return 'https://dcav.pw/jbait' end +local curb_your_video = require 'curb_your_enthusiasm' + -------------------------------------------------------------------------------- + function memes.generate_for_message (user, message) -- Bait msg @@ -513,6 +520,17 @@ function memes.generate_for_message (user, message) return 'https://www.youtube.com/watch?v=wl-LeTFM8zo', 'MACHINE' end + do + local url = message:lower():match '^curb%s+your%s+(.+)$' + local url2, timestamp = message:match '^(..-)%s+at%s+(-?[%d.]+)$' + if url2 then url = url2 end + timestamp = timestamp and tonumber(timestamp) or nil + assert(type(timestamp) == 'number' or timestamp == nil) + local video_filename = curb_your_video(url, timestamp) + local video_url = save_file_to_dcav(video_filename) + return video_url, 'CURB' + end + -- Vælter min skorsten do local problem_text = message:lower():match 'vælter%s+min%s+skorsten%s*(.+)$' @@ -535,7 +553,6 @@ function memes.generate_for_message (user, message) -- Create image based on match if problem_text then - print(problem_text) local topic = fill_in_topics_information { problem_text } local img_link = generate_into_the_trash(topic) return img_link, 'TRASH' diff --git a/sound/curb_your_enthusiasm_theme.mp3 b/sound/curb_your_enthusiasm_theme.mp3 new file mode 100644 index 0000000..b2125fd Binary files /dev/null and b/sound/curb_your_enthusiasm_theme.mp3 differ diff --git a/sound/curb_your_enthusiasm_theme.opus b/sound/curb_your_enthusiasm_theme.opus new file mode 100644 index 0000000..8aca8c0 Binary files /dev/null and b/sound/curb_your_enthusiasm_theme.opus differ