from subprocess import call, Popen, PIPE from os import listdir, remove from os.path import splitext from re import match from sys import argv from enum import Enum from datetime import timedelta from math import ceil class Stream(Enum): AUDIO = 1 VIDEO = 2 class File(Enum): LIST = 1 LOOP = 2 OUTPUT = 3 def getCmdStdErr(command): process = Popen(command, stderr=PIPE, stdout=PIPE) out, err = process.communicate() return err def getDuration(ffprobe_output): durationPattern = r'.*Duration:\s(.+),\sstart.*' regex = match(durationPattern, str(ffprobe_output)) duration = regex.groups()[0] if regex else None if not duration: raise ValueError('Cannot process ffprobe output!') return duration argv.append('https://coub.com/view/aeeuu') # TODO: remove debug line FILES = {Stream.AUDIO: 'audio', Stream.VIDEO: 'video', File.LIST: 'list.txt', File.LOOP: 'loop', File.OUTPUT: 'output.mp4'} OUTPUT_KEYS = [File.OUTPUT] URL = argv[1] if len(argv) > 0 else '' # youtube-dl error message will be shown if '' call(('/usr/bin/env', 'youtube-dl', '--extract-audio', '--output', '{}.%(ext)s'.format(FILES[Stream.AUDIO]), URL)) call(('/usr/bin/env', 'youtube-dl', '--output', '{}.%(ext)s'.format(FILES[Stream.VIDEO]), URL)) for file in listdir(): for filename in FILES: if match('^{}.*'.format(FILES[filename]), file): FILES[filename] = file audioData= getDuration(getCmdStdErr(('/usr/bin/env', 'ffprobe', FILES[Stream.AUDIO]))).split(':') videoData = getDuration(getCmdStdErr(('/usr/bin/env', 'ffprobe', FILES[Stream.VIDEO]))).split(':') audioLen = timedelta(hours=float(audioData[0]), minutes=float(audioData[1]), seconds=float(audioData[2])) videoLen = timedelta(hours=float(videoData[0]), minutes=float(videoData[1]), seconds=float(videoData[2])) longer = audioLen if audioLen > videoLen else videoLen shorter = audioLen if audioLen < videoLen else videoLen shorterFile = FILES[Stream.AUDIO] if audioLen < videoLen else FILES[Stream.VIDEO] FILES[File.LOOP] += splitext(shorterFile)[1] timesLoop = ceil(longer.seconds / shorter.seconds) with open(FILES[File.LIST], 'w') as f: for i in range(timesLoop): print("file '{}'".format(shorterFile), file=f) call(('/usr/bin/env', 'ffmpeg', '-f', 'concat', '-i', FILES[File.LIST], '-c', 'copy', FILES[File.LOOP])) call(('/usr/bin/env', 'ffmpeg', '-i', FILES[File.LOOP], '-i', FILES[Stream.AUDIO], '-map', '0', '-map', '1', '-c', 'copy', FILES[File.OUTPUT])) for key in FILES: if key not in OUTPUT_KEYS: remove(FILES[key])