from subprocess import call, Popen, PIPE from os import listdir, remove 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 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'} 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])) print(audioLen) print(videoLen) 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] timesLoop = ceil(longer.seconds / shorter.seconds) with open('list.txt', 'w') as f: for i in range(timesLoop): print("file '{}'".format(shorterFile), file=f) call(('/usr/bin/env', 'ffmpeg', '-f', 'concat', '-i', 'list.txt', '-c', 'copy', 'loopedvideo.mp4')) call(('/usr/bin/env', 'ffmpeg', '-i', 'loopedvideo.mp4', '-i', FILES[Stream.AUDIO], '-map', '0', '-map', '1', '-c', 'copy', 'output.mp4')) remove(FILES[Stream.AUDIO]) remove(FILES[Stream.VIDEO]) remove('list.txt') remove('loopedvideo.mp4')