Skip to content

Instantly share code, notes, and snippets.

@kellerkind
Created November 11, 2012 22:07
Show Gist options
  • Save kellerkind/4056431 to your computer and use it in GitHub Desktop.
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.
#!/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