Created
November 11, 2012 22:07
-
-
Save kellerkind/4056431 to your computer and use it in GitHub Desktop.
Script to split files via mencoder or encode to avi from mpg4/mkv.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
''' | |
author: nochn_kellerkind | |
some magic from mencoder done in this script. | |
Examples of whats possible: http://www.wiki.csoft.at/index.php/MEncoder_Scripts | |
''' | |
import sys | |
import os | |
import subprocess | |
import fcntl | |
import time | |
import re | |
from fnmatch import fnmatch | |
import getopt | |
from decimal import * | |
''' estimated filesize ''' | |
DEF_EST_SIZE=2048 | |
estimated_size = None | |
path = None | |
files = [] | |
dry_run = False | |
convert = False | |
ext_opts = None | |
default_tasks = [ 'convert', 'split' ] | |
def get_diskspace_avail(path): | |
s = os.statvfs(path) | |
return s.f_bsize * s.f_bavail / 1024 / 1024 | |
def get_length(path,file): | |
proc = subprocess.Popen( ['mplayer', '-frames', '0', '-identify', os.path.join(path,file)], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) | |
for length in (l.split('=')[1] for l in proc.stdout.read().split("\n") if 'ID_LENGTH' in l): | |
return length | |
def mencoder_cmd(c, file): | |
global dry_run | |
if ext_opts: | |
c.append(ext_opts) | |
if not dry_run: | |
proc = subprocess.Popen( c, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True ) | |
''' unblock file descriptor ''' | |
fcntl.fcntl( | |
proc.stdout.fileno(), | |
fcntl.F_SETFL, | |
fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK, | |
) | |
while True: | |
lines = None | |
time.sleep(1) | |
proc.poll() | |
try: | |
lines = proc.stdout.read().split("\n") | |
except IOError as err: | |
continue | |
if proc.returncode != None: | |
for l in (l for l in lines if proc.returncode > 0): | |
print l | |
sys.stdout.write("\n") | |
break | |
for line in lines: | |
match = re.search('([0-9]{1,3}%)', line) | |
if not match: | |
continue | |
sys.stdout.write("\rTask: \033[0;32m%s\033[0m File: \033[0;32m%s\033[0m Dest: \033[0;32m%s\033[0m Est. Size: \033[0;32m%sMB\033[0m Progress: \033[0;32m%s\033[0m" % | |
( file['task'], file['name'], file['dst'], file['nsize'], match.group(1) ) ) | |
sys.stdout.flush() | |
else: | |
c.insert(0,'echo') | |
proc = subprocess.Popen( c, shell=False ) | |
def prepare_files(path, files): | |
global default_tasks | |
if not os.path.isfile('/usr/bin/mencoder'): | |
print("mencoder is not installed!") | |
quit() | |
for file in files: | |
name = file['name'] | |
length = file['length'] = get_length( path, name ) | |
size = file['size'] = os.path.getsize( os.path.join( path, name ) ) / 1024 / 1024 | |
file['tasks'] = default_tasks | |
if int(size) <= int(estimated_size): | |
del( file['tasks'][file['tasks'].index('split')] ) | |
if not os.path.splitext(file['name'])[1][1:] in [ 'mkv', 'mp4' ] or not convert: | |
del( file['tasks'][file['tasks'].index('convert')] ) | |
''' avi 1 1/5 size of a mkv ''' | |
if len(file['tasks']) == 0: | |
print "No tasks for file %s" % file['name'] | |
for task in file['tasks']: | |
file['task'] = task | |
if task == 'split': | |
split_files(file) | |
if task == 'convert': | |
mencoder_to_avi(file) | |
def split_files(file): | |
name = file['name'] | |
size = file['size'] | |
length = file['length'] | |
if get_diskspace_avail(path) < file['size']: | |
print "Not enough space available, at least %sMB required!" % (file['size']) | |
quit() | |
(src,sfx) = os.path.splitext( file['name'] ) | |
''' create count of splitted files calculated from estimated_size ''' | |
file['parts'] = ( size // estimated_size + ( (size // estimated_size) // (size // estimated_size) ) ) | |
print file['parts'] | |
for part in range( file['parts'] ): | |
duration = Decimal( length ) / Decimal( file['parts'] ) | |
file['task'] = "split" | |
file['nsize'] = ( Decimal(duration) / Decimal(length) ) * size | |
mencoder_create_file( file, part, duration ) | |
def mencoder_to_avi(file): | |
(src, _) = os.path.splitext(file['name']) | |
sfx = "avi" | |
file['dst'] = "%s.%s" % (src, sfx ) | |
file['nsize'] = file['size'] * 1.5 | |
# mencoder "Original.mkv" -ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=6000 -oac mp3lame -lameopts vbr=3 -o "New.avi" | |
''' @todo: check if -ovc copy -oac copy is possible ''' | |
c = [ 'mencoder', '-o', os.path.join(path, file['dst']), '-ovc', 'lavc', '-lavcopts', 'aspect=16/9,vcodec=mpeg4:vhq:vbitrate=6000', | |
'-oac', 'mp3lame', '-lameopts', 'vbr=3', '-mc', '0', '-noskip', os.path.join(path, file['name']) ] | |
proc = mencoder_cmd(c, file) | |
def mencoder_create_file( file, part , duration ): | |
(src,sfx) = os.path.splitext( file['name'] ) | |
file['dst'] = "%s_%i%s" % (src, part + 1, sfx) | |
cmd = [ 'mencoder', '-mc', '0', '-ss', str(duration * part), '-o', os.path.join(path, file['dst']), '-ovc', 'copy', '-oac', 'copy', os.path.join(path, file['name']) ] | |
max_duration = duration * part + duration | |
if ( Decimal( max_duration ) < Decimal( file['length'] ) ): | |
cmd.extend( ['-endpos', str(duration)] ) | |
proc = mencoder_cmd(cmd, file) | |
def usage(): | |
print "Usage:\n\t%s -i <path to infile> [-s <size in MB>] [-d|--dry-run]" % (sys.argv[0]) | |
quit() | |
def main(): | |
global estimated_size | |
global path | |
global dry_run | |
global convert | |
global ext_opts | |
optlist = None | |
try: | |
optlist, args = getopt.getopt( sys.argv[1:], "hi:s:dce:", [ "help", "infile=", "size=", "dry-run", "extra-opts" ] ) | |
except getopt.GetoptError as err: | |
print "Error: %s" % ( str(err) ) | |
usage() | |
for opt, arg in optlist: | |
if opt in ("-h", "--help"): | |
usage() | |
if opt in ("-i", "--infile"): | |
if not os.path.exists(arg): | |
usage() | |
else: | |
path = arg | |
if opt in ("-s", "--size"): | |
estimated_size = int(arg) | |
if opt in ("-d", "--dry-run"): | |
dry_run = True | |
if opt in ("-c", "--convert"): | |
convert = True | |
if opt in ("-e", "--extra-opts"): | |
ext_opts = arg | |
if not path: | |
usage() | |
if not estimated_size: | |
estimated_size = DEF_EST_SIZE | |
files.append( { 'name': os.path.basename(path) } ) | |
path = os.path.dirname( os.path.abspath(path) ) | |
filter = re.sub('[0-9]{1,2}', '?', files[0]['name']) | |
for file in os.listdir(path): | |
if not fnmatch( file, filter ): | |
continue | |
if file in ( f['name'] for f in files): | |
continue | |
msg = "Further file found: %s. Add to list? [y|n]:" % (file) | |
if raw_input(msg).lower() in ['y','yes']: | |
files.append( { 'name': file } ) | |
prepare_files(path, files) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment