#!/usr/bin/env python # -*- coding: utf-8 -*- """Tests the audacity pipe. Depends on Destreamer and python-dateutil Ensure you have a blank Audacity project open before use Known issues: - Audio and video slip ever so slightly out of sync - Audio gets dickered into mono >.> """ import shutil from subprocess import call import os import sys from pathlib import Path import dateutil.parser as dparser import re import time # TODO path_to_destreamer = os.path.abspath(sys.argv[1]) working_dir = os.path.abspath(sys.argv[2]) urls = sys.argv[3:] # Platform specific constants if sys.platform == 'win32': print("recording-test.py, running on windows") PIPE_TO_AUDACITY = '\\\\.\\pipe\\ToSrvPipe' PIPE_FROM_AUDACITY = '\\\\.\\pipe\\FromSrvPipe' EOL = '\r\n\0' else: print("recording-test.py, running on linux or mac") PIPE_TO_AUDACITY = '/tmp/audacity_script_pipe.to.' + str(os.getuid()) PIPE_FROM_AUDACITY = '/tmp/audacity_script_pipe.from.' + str(os.getuid()) EOL = '\n' print("Write to \"" + PIPE_TO_AUDACITY +"\"") if not os.path.exists(PIPE_TO_AUDACITY): print(""" ..does not exist. Ensure Audacity is running with mod-script-pipe.""") sys.exit() print("Read from \"" + PIPE_FROM_AUDACITY +"\"") if not os.path.exists(PIPE_FROM_AUDACITY): print(""" ..does not exist. Ensure Audacity is running with mod-script-pipe.""") sys.exit() print("-- Both pipes exist. Good.") TOPIPE = open(PIPE_TO_AUDACITY, 'w') print("-- File to write to has been opened") FROMPIPE = open(PIPE_FROM_AUDACITY, 'r') print("-- File to read from has now been opened too\r\n") def send_command(command): """Send a command to Audacity.""" print("Send: >>> "+command) TOPIPE.write(command + EOL) TOPIPE.flush() def get_response(): """Get response from Audacity.""" line = FROMPIPE.readline() result = "" while True: result += line line = FROMPIPE.readline() # print(f"Line read: [{line}]") if line == '\n': return result def do_command(command): """Do the command. Return the response.""" send_command(command) # time.sleep(0.1) # may be required on slow machines response = get_response() print("Rcvd: <<< " + response) return response def do_command(command): """Send one command, and return the response.""" send_command(command) response = get_response() print("Rcvd: <<< \n" + response) return response def mkdir_if_not_exists(directory): if not os.path.exists(directory): os.makedirs(directory) return os.path.abspath(directory) # TODO Cleanup path handling cause...ew def do(): mkdir_if_not_exists(working_dir) if working_dir: print("WARNING: MUNGING IN PROGRESS") # Setup #os.chdir(working_dir) downloaded = mkdir_if_not_exists(working_dir + "/downloaded") renamed = mkdir_if_not_exists(working_dir + "/renamed") processed_audio_dir = mkdir_if_not_exists(working_dir + "/processed_audio") final = mkdir_if_not_exists(working_dir + "/final") # Download videos print("Using destreamer.js at {}".format(path_to_destreamer)) call("node --max-http-header-size 32768 {} --skip -k -o {} -i {}".format(path_to_destreamer, downloaded, " ".join(urls)), shell=True) for entry in os.scandir(downloaded): # Normalise names # Put file extension to one side for safekeeping split = entry.name.split('.') extension = split[1] name = split[0].replace(',', '').split('#')[0] # Discard all commas, and unique id doodad head, sep, tail = name.partition(' ') # Discard leading date split2 = tail.split() date = dparser.parse(split2[-1], fuzzy=True) # Parse the date folder_path = split2[0] + split2[1] # TODO Fragile title = re.search(r'\d+-\d+\s[\d\w\s]*', tail) if re.match: title = title.group(0).strip().replace(' ', '_') # Add date back if date is not None: title += "_" + date.strftime('%Y-%m-%d') # Rename file source = entry.path filename = "{}.{}".format(title, extension) dest = os.path.abspath(renamed + "/" + filename) print ("Source: " + source) print ("Dest: " + dest) shutil.copy(source, dest) time.sleep(5) # Extract audio, process it, add it back to the video video_in = dest processed_audio = os.path.join(processed_audio_dir, filename.split(".")[0] + ".wav") final_output_name = os.path.join(final, filename) do_command("New:") do_command("Import2: Filename={}".format(video_in)) time.sleep(5) do_command("SelectAll:") do_command('Amplify: Ratio=2') time.sleep(1) do_command("SelectAll:") do_command('Popmute: thresh=10 floor=100') time.sleep(1) do_command("Export2: Filename={} NumChannels=2".format(processed_audio)) time.sleep(5) do_command("SelectAll:") do_command("RemoveTracks:") time.sleep(5) # do_command('Close:') TODO THis causes audacity to wait for a input # final_output_name = "output-" + # TODO Folderisation of output by lecture print("Combining video at {} with audio at {}".format(video_in, processed_audio)) # https://superuser.com/questions/277642/how-to-merge-audio-and-video-file-in-ffmpeg call('ffmpeg -i {} -i {} -acodec copy -vcodec copy -map 0:v:0 -map 1:a:0 {}'.format(video_in, processed_audio, final_output_name), shell=True) print("\033[92mDone! Result is at {}\e[0m".format(final_output_name)) print("Munging complete!!!") do()