#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#################################################################
# This block contains all the functions to convert a video file #
# into an MPEG2-PS DVD-compliant file #
#################################################################
import time
import select
import signal
import subprocess
import sys
import os
import re
import locale
import gettext
import shutil
import glob
import posixpath
import cairo
if sys.platform=='win32':
import win32_helper
import win32api
import win32con
import win32process
import thread
from devede_other import *
from devede_gtk_helper import *
locale.setlocale(locale.LC_ALL,"")
gettext.textdomain('devede')
_ = gettext.gettext
def return_time(seconds,empty):
""" cuts a time in seconds into seconds, minutes and hours """
seconds2=int(seconds)
hours=str(seconds2/3600)
if empty:
if len(hours)==1:
hours="0"+hours
else:
if hours=="0":
hours=""
if hours!="":
hours+=":"
minutes=str((seconds2/60)%60)
if empty or (hours!=""):
if len(minutes)==1:
minutes="0"+minutes
elif (minutes=="0") and (hours==""):
minutes=""
if minutes!="":
minutes+=":"
secs=str(seconds2%60)
if (len(secs)==1) and (minutes!=""):
secs="0"+secs
return hours+minutes+secs
def erase_all_files(filefolder,filename,global_vars):
""" Erases the files that have the same global name than the selected, to
avoid collissions when doing the soft links or other problems """
newfilename=addbarr(filefolder+filename)
print "filename: ", filename
newfilename=addbarr(filefolder+filename)
print "newfilename: ", newfilename
try:
os.remove(newfilename+"_menu.xml")
except OSError:
print newfilename.strip()+"_menu.xml not found"
try:
os.remove(newfilename+"_menu2.xml")
except OSError:
print newfilename.strip()+"_menu2.xml not found"
try:
os.remove(newfilename+"_menu.mpg")
except OSError:
print newfilename.strip()+"_menu.mpg not found"
try:
os.remove(newfilename+"_menu2.mpg")
except OSError:
print newfilename.strip()+"_menu2.mpg not found"
try:
os.remove(newfilename+"_menu_bg.png")
except OSError:
print newfilename.strip()+"_menu_bg.png not found"
try:
os.remove(newfilename+".xml")
except OSError:
print newfilename.strip()+".xml not found"
try:
os.remove(newfilename+"_sub.xml")
except OSError:
print newfilename.strip()+"_sub.xml not found"
if (global_vars["disctocreate"]=="dvd") or (global_vars["disctocreate"]=="divx"):
try:
os.remove(newfilename.strip()+".iso")
except OSError:
print newfilename+".iso not found"
else:
try:
os.remove(newfilename+".bin")
except OSError:
print newfilename+".bin not found"
try:
os.remove(newfilename+".cue")
except OSError:
print newfilename+".cue not found"
try:
z=glob.glob(newfilename+"_[0-9][0-9]_[0-9][0-9]"+".mpg")
for x in z:
try:
os.remove(x)
except OSError:
print str(x)+" not found to remove"
except OSError:
print newfilename+"._??_?? not found"
try:
os.remove(newfilename)
except OSError:
print newfilename+" not found"
try:
shutil.rmtree(newfilename)
except OSError:
print newfilename+" directory not found"
def create_filename(filename,title,file):
currentfile=filename+"_"
if title<10:
currentfile+="0"
currentfile+=str(title)+"_"
if file<10:
currentfile+="0"
currentfile+=str(file)+'.mpg'
return currentfile
def add_subtitle(arbol,global_vars,afile,filefolder,filename,cfiles,titles,files,total,erase_temporary_files):
""" Adds the subtitles to a movie """
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
label.set_text(_("Adding subtitles to")+"\n"+afile["filename"])
percent1=((100*(cfiles+.5))/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
ppartial.set_fraction(0.10)
ppartial.pulse()
refresh_screen()
refresh_screen()
currentfile=create_filename(filefolder+filename,titles,files)
global_vars["cancel_prog"]=False
#first delete the file with the same name (just in case...)
newfilename=addbarr(currentfile)
# generate the XML file
try:
fichero=open(filefolder+filename+"_sub.xml","w")
fichero.write('\n\t')
fichero.write('\n\t\t')
fichero.write("\n\t\n")
fichero.close()
except IOError:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Failed to write to the destination directory.\nCheck that you have privileges and free space there."),arbol)
return True
comando=""
if sys.platform=='win32':
comando="spumux.exe -m "
else:
comando="spumux -m "
if global_vars["disctocreate"]=="vcd":
comando+="svcd"
else:
comando+=global_vars["disctocreate"]
comando+=' "'+filefolder+filename+'_sub.xml" < "'+currentfile+'" > "'+currentfile+'.sub"'
print "Launch: "+comando
handle=subprocess.Popen(comando,shell=True,bufsize=32767, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while (None==handle.poll()):
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handler)
except Exception:
break
else:
v1,v2,v3=select.select([handle.stderr,handle.stdout],[],[],0)
for elem in v1:
#if sys.platform=="win32":
# temporal=elem
#else:
# temporal=elem.readline(80)
## might what to try: temporal=handle.stdout
temporal=elem.readline(80)
print temporal,
ppartial.pulse()
position=temporal.find("STAT: ")
if (position!=-1):
position2=temporal.find(".",position+6)
if position2!=-1:
ppartial.set_text(temporal[position:position2])
refresh_screen()
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handle._handle), -1)
except Exception , err:
print "Error: ", err
else:
handle2=subprocess.Popen("pkill -P "+str(handle.pid),bufsize=8192,shell=True)
break
error_ret=handle.wait()
if global_vars["cancel_prog"]:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
w=arbol.get_widget("w_aborted")
w.show()
return True
if error_ret!=0:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Conversion failed.\nIt seems a bug of SPUMUX."),arbol)
return True
#TODO
if erase_temporary_files:
try:
os.remove(filefolder+filename+"_sub.xml")
except OSError:
print "Error removing ", filefolder+filename+"_sub.xml"
shutil.move(currentfile+".sub", currentfile)
return False
def convert_file(arbol,global_vars,afile,filefolder,filename,cfiles,titles,files,total,erase_temporary_files,seconds=0):
""" Converts a video file to an MPEG1-PS or MPEG2-PS file, compliant with DVD players.
TITLES is the current title number; FILES is the current file number into that tile;
CFILES is the current file in total, and TOTAL is the number of steps needed to do
the job """
print "\nafile is: ", afile , "\n"
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
if afile["subtitles"]=="":
has_subtitles=False
else:
has_subtitles=True
if afile["ismpeg"]: # if the file hasn't to be converted, we simply copy it
if seconds==0:
texto=_("Copying the file")+"\n"
ptotal.show()
else:
texto=_("Creating preview")+"\n"
ptotal.hide()
label.set_text(texto+afile["filename"])
percent1=((100*cfiles)/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
ppartial.set_fraction(0)
ppartial.set_text("0%")
ppartial.set_pulse_step(0.1)
refresh_screen()
refresh_screen()
currentfile=create_filename(filefolder+filename,titles,files)
if global_vars["disctocreate"]=="divx":
currentfile=currentfile[:-4]+".avi"
global_vars["cancel_prog"]=False
print "\ncurrentfile is: ", currentfile , "\n"
#first delete the file with the same name (just in case...)
newfilename=addbarr(currentfile)
try:
os.remove(newfilename)
except OSError:
print "Error removing ", newfilename
#TODO
print "ln -s \""+afile["path"]+"\" \""+currentfile+"\""
handle=''
command=[]
if afile["subtitles"]=="":
ln=""
if sys.platform=="win32":
command.append("ln.exe")
else:
command.append("ln")
command.append("-s")
command.append(afile["path"])
command.append(currentfile)
handle=launch_program(command)
else:
if sys.platform=="win32":
#command.append("xcopy.exe")
handle=subprocess.Popen("copy \""+afile["path"] +"\" \""+ currentfile+"\"", shell=True)
else:
#command.append("cp")
handle=subprocess.Popen("cp \""+afile["path"]+"\" \""+currentfile+"\"",bufsize=8192,shell=True)
#command.append(afile["path"])
#command.append(currentfile)
#handle=launch_program(command)
ppartial.set_text("")
while (None==handle.poll()):
refresh_screen()
time.sleep(1)
ppartial.pulse()
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handle._handle), -1)
except Exception , err:
print "Error: ", err
else:
os.kill(handle.pid,signal.SIGKILL)
break
handle.wait()
retorno=handle.returncode
if global_vars["cancel_prog"]:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
w=arbol.get_widget("w_aborted")
w.show()
return True
if retorno!=0:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("File copy failed\nMaybe you ran out of disk space?"),arbol)
return True
if afile["subtitles"]!="":
return add_subtitle(arbol,global_vars,afile,filefolder,filename,cfiles,titles,files,total,erase_temporary_files)
return False
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
if global_vars["cancel_prog"]:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
w=arbol.get_widget("w_aborted")
w.show()
return True
addbars=False
framerate=int(afile["ofps"])
videorate=int(afile["vrate"])
audiorate=int(afile["arate"])
audio_final_rate=int(afile["arateunc"])
audiodelay=float(afile["adelay"])
final_framerate=float(afile["fps"])
aspect_ratio_original=afile["oaspect"]
aspect_ratio_final=afile["aspect"]
if aspect_ratio_original<1.3:
aspect_ratio_original=float(afile["owidth"])/(float(afile["oheight"]))
if aspect_ratio_original<1.33333333:
aspect_ratio_original=1.33333333
max_videorate=int(videorate*1.5)
if global_vars["disctocreate"]=="vcd":
max_videorate=1152
elif (global_vars["disctocreate"]=="svcd") or (global_vars["disctocreate"]=="cvd"):
if (max_videorate+audiorate)>2550:
max_videorate=2550-audiorate
elif (global_vars["disctocreate"]=="dvd") or (global_vars["disctocreate"]=="divx"):
if (max_videorate+audiorate)>8700:
max_videorate=8700-audiorate
else:
print ("Error, disc format is not DVD, DIVX, VCD, SVCD or CVD. Contact with the author")
print global_vars["disctocreate"]
sys.exit(1)
resx_final=afile["width"]
resy_final=afile["height"]
resx_original=afile["owidth"]
resy_original=afile["oheight"]
if afile["blackbars"]==0: # check if has to add black bars
addbars=True
if (resx_original%2)==1:
resx_original+=1
if (resy_original%2)==1:
resy_original+=1
resx_inter=resx_original
resy_inter=int((resy_original*aspect_ratio_original)/aspect_ratio_final)
if (resy_inter%2)==1:
resy_inter+=1
if ((resy_interresy_inter)):
addbars=False # due to a bug in MENCODER, we put bars only up and down, never left and right
# and we don't scale it if we have to add only 4 or less lines, because is too much work for little profit
if addbars==False:
resx_inter=resx_original
resy_inter=resy_original
else:
addx=0
addy=int((resy_inter-resy_original)/2)
# TODO
command_var=[]
if not sys.platform=='win32':
command_var=["mencoder"]
else:
command_var=["mencoder.exe"]
if (global_vars["disctocreate"]=="dvd") or (global_vars["disctocreate"]=="divx"):
audio_desired_final_rate=48000
else:
audio_desired_final_rate=44100
if audio_final_rate!=audio_desired_final_rate:
command_var.append("-srate")
command_var.append(str(audio_desired_final_rate))
command_var.append("-af")
command_var.append("lavcresample="+str(audio_desired_final_rate))
command_var.append("-oac")
if (global_vars["disctocreate"]=="divx"):
command_var.append("mp3lame")
else:
command_var.append("lavc")
command_var.append("-ovc")
command_var.append("lavc")
if (global_vars["disctocreate"]!="divx"):
command_var.append("-of")
command_var.append("mpeg")
command_var.append("-mpegopts")
if global_vars["disctocreate"]=="dvd":
command_var.append("format=dvd:tsaf")
elif global_vars["disctocreate"]=="vcd":
command_var.append("format=xvcd")
elif (global_vars["disctocreate"]=="svcd") or (global_vars["disctocreate"]=="cvd"):
command_var.append("format=xsvcd")
else:
print "Error, disc format incorrect. Talk with the creator."
sys.exit(1)
halffile=False
if seconds!=0:
command_var.append("-endpos")
command_var.append(str(seconds))
else:
if afile["cutting"]==1: # first half only
command_var.append("-endpos")
command_var.append(str(afile["olength"]/2))
halffile=True
elif afile["cutting"]==2: # second half only
command_var.append("-ss")
command_var.append(str((afile["olength"]/2)-5)) # start 5 seconds before
halffile=True
if audiodelay!=0.0:
command_var.append("-delay")
command_var.append(str(audiodelay))
if final_framerate==30:
if (framerate==24) and ((global_vars["disctocreate"]=="dvd") or (global_vars["disctocreate"]=="divx")):
str_final_framerate="24000/1001"
else:
str_final_framerate="30000/1001"
keyintv=18
else:
str_final_framerate=str(int(final_framerate))
keyintv=15
command_var.append("-ofps")
command_var.append(str_final_framerate)
if global_vars["disctocreate"]=="divx":
command_var.append("-ffourcc")
command_var.append("DX50")
lineatemp=""
acoma=False;
if afile["deinterlace"]!="none":
lineatemp+="pp="+afile["deinterlace"]
acoma=True
if addbars and ((resx_inter!=resx_original) or (resy_inter!=resy_original)):
if acoma:
lineatemp+=","
lineatemp+="expand="+str(resx_inter)+":"+str(resy_inter)+":"+str(addx)+":"+str(addy)
acoma=True
if (resx_inter!=resx_final) or (resy_inter!=resy_final):
if acoma:
lineatemp+=","
lineatemp+="scale="+str(resx_final)+":"+str(resy_final)
acoma=True
if global_vars["disctocreate"]!="divx":
if acoma:
lineatemp+=","
lineatemp+="harddup"
if (lineatemp!=""):
command_var.append("-vf")
command_var.append(lineatemp)
command_var.append("-lavcopts")
lavcopts="vcodec="
if global_vars["disctocreate"]=="vcd":
lavcopts+="mpeg1video"
elif global_vars["disctocreate"]=="divx":
lavcopts+="mpeg4"
else:
lavcopts+="mpeg2video"
if afile["trellis"]:
lavcopts+=":trell"
if afile["mbd"]==0:
lavcopts+=":mbd=0"
elif afile["mbd"]==1:
lavcopts+=":mbd=1"
elif afile["mbd"]==2:
lavcopts+=":mbd=2"
if global_vars["disctocreate"]!="divx":
lavcopts+=":vstrict=0:vrc_maxrate="+str(max_videorate)
lavcopts+=":vrc_buf_size="
if (global_vars["disctocreate"]=="divx"):
lavcopts+="1835"
elif (global_vars["disctocreate"]=="vcd"):
lavcopts+="327:vrc_minrate=1152"
elif (global_vars["disctocreate"]=="svcd") or (global_vars["disctocreate"]=="cvd"):
lavcopts+="917:vrc_minrate=600"
elif (global_vars["disctocreate"]=="dvd"):
lavcopts+="1835"
lavcopts+=":vbitrate="+str(videorate)
if global_vars["disctocreate"]!="divx":
lavcopts+=":keyint="+str(keyintv)+":acodec=mp2"
lavcopts+=":abitrate="+str(audiorate)
if aspect_ratio_final>1.4:
lavcopts+=":aspect=16/9"
else:
lavcopts+=":aspect=4/3"
command_var.append(lavcopts)
if global_vars["disctocreate"]=="divx":
lameopts="abr:br="+str(audiorate)
command_var.append("-lameopts")
command_var.append(lameopts)
currentfile=create_filename(filefolder+filename,titles,files)
if global_vars["disctocreate"]=="divx":
currentfile=currentfile[:-4]+".avi"
newfilename=addbarr(currentfile)
try:
os.remove(newfilename)
except OSError:
print "Error removing ", newfilename
command_var.append("-o")
command_var.append(currentfile)
command_var.append(afile["path"])
extra_params=afile["params"] # take the extra params
while (extra_params!=""):
extra_params,new_param=get_new_param(extra_params)
if new_param!="":
command_var.append(new_param)
percent2=120
refresh=False
busqueda=re.compile("Pos:[0-9 ]*\.[0-9]s")
if seconds==0:
divide=float(afile["olength"])
ptotal.show()
else:
divide=float(seconds)
ptotal.hide()
if divide==0:
divide=1
espera=False
salta=False
handler=launch_program(command_var)
linea="\n"
first_time=time.time()
#if sys.platform=='win32':
# v1=win32subprocess.recv_some(handler)
v1=""
while (handler.poll()==None):
#if handler.poll() != None:
# break
#v1,v2,v3=select.select([handler.stderr,handler.stdout],[],[],0)
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handler)
except Exception:
break
else:
v1,v2,v3=select.select([handler.stderr,handler.stdout],[],[],0)
if (len(v1)==0):
if espera:
refresh_screen()
time.sleep(.1)
salta=False
first_time=time.time()
continue
else:
new_time=time.time()
if (new_time>(2.0+first_time)): # ensure a screen refresh each two seconds at least
refresh_screen()
refresh_screen()
first_time=new_time
for elem in v1:
if elem==handler.stderr:
linea=handler.stderr.readline(80)
else:
refresh=False
linea=handler.stdout.readline(2400)
if global_vars["cancel_prog"]:
break
if linea=="":
continue
if linea[-1]=="\n":
break
if salta:
break
salta=True
pos=linea.find("Pos:")
if pos==-1:
break
espera=True
while(pos+10)>len(linea):
linea+=handler.stdout.read(2)
elemento=busqueda.findall(linea)
if len(elemento)==0:
break
valuetemp=float(elemento[0][4:-1])
if (halffile):
valuetemp*=2
value=(100*valuetemp)/divide
if (value!=percent2) or (percent2==120):
percent1=((100*cfiles)/total)
if has_subtitles:
percent1+=(value/(total*2))
else:
percent1+=(value/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
if seconds==0:
texto=_("Converting files from title")
label.set_text(texto+" "+str(titles)+"\n\n"+afile["filename"])
else:
texto=_("Creating preview")
label.set_text(texto+"\n"+afile["filename"])
if (value)>100:
value=100
ppartial.set_fraction(value/100)
percent2=value
ppartial.set_text(str(int(percent2))+"%")
refresh=True
if global_vars["cancel_prog"]:
break
if linea[-1]=="\n":
continue
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handler._handle), -1)
except Exception , err:
print "Error: ", err
else:
os.kill(handler.pid,signal.SIGKILL)
handler.wait()
retcode=handler.returncode
if (retcode!=0) or global_vars["cancel_prog"]:
print "Deleting "+currentfile+" due to error or aborting."
try:
os.remove(currentfile)
except OSError:
print currentfile+" didn't exists"
if global_vars["cancel_prog"]:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
w=arbol.get_widget("w_aborted")
w.show()
return True
else:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
if percent2==120: # still hadn't take a value, so it seems it failed (core dump)
show_error2(_("Conversion failed.\nIt seems a bug of Mencoder."),arbol)
else:
show_error2(_("Conversion failed\nMaybe you ran out of disk space?"),arbol)
return True
if afile["subtitles"]!="":
return add_subtitle(arbol,global_vars,afile,filefolder,filename,cfiles,titles,files,total,erase_temporary_files)
return False
def check_free_space(arbol,filefolder,structure,actions,erase_temporary_files):
""" Returns TRUE if the free space in FILEFOLDER is insuficient to generate
the disk STRUCTURE """
estado=''
freespace=''
if not sys.platform=='win32':
estado=os.statvfs(filefolder) # eg. f="C:\Documents and Settings\User Name\Desktop"
freespace=95*estado.f_bsize*estado.f_bavail/100000
else:
try:
spc, bps, fc, tc = win32api.GetDiskFreeSpace(filefolder)
freespace=fc * spc * bps
except ImportError:
pass
print "Free space in "+str(filefolder)+": "+str(freespace)
print "estatus ", estado, "\n"
total=calcula_tamano_total(structure)
print "Libre: "+str(freespace)
print "Necesario: "+str(total)
if (actions!=3):
total*=actions # if we only create the MPEG files or the DVD structure...
else:
if erase_temporary_files: # or if we create the ISO image
total*=2
else:
total*=3
total*=1.1 # a safe margin of 10%
if (freespace\n')
fichero.write("\n")
fichero.write("\n")
titles=0
total_t=len(structure)
fichero.write("\n")
if global_vars["do_menu"]:
fichero.write("\n")
fichero.write('\n')
fichero.write('\n')
fichero.write('\n')
contador=0
for elemento in structure:
fichero.write('\n')
contador+=1
fichero.write('\n\n')
fichero.write("\n")
for elemento in structure:
action=elemento[0]["jumpto"]
titles+=1
fichero.write("\n")
if len(elemento)>1:
files=0
for elemento2 in elemento[1:]:
files+=1
currentfile=create_filename(filefolder+filename,titles,files)
fichero.write('5):
if (elemento2["lchapters"]!=0): # add chapters
toadd=int(elemento2["lchapters"])
seconds=toadd*60
while seconds<(elemento2["olength"]-4):
thetime=return_time(seconds,False)
fichero.write(","+thetime)
seconds+=(toadd*60)
fichero.write(','+return_time((elemento2["olength"]-2),False))
fichero.write('" />\n')
if action=="menu":
if global_vars["do_menu"]:
fichero.write("call menu;\n")
elif action=="first":
fichero.write("jump title 1;\n")
elif action=="prev":
if titles==1:
prev_t=total_t
else:
prev_t=titles-1
fichero.write("jump title "+str(prev_t)+";\n")
elif action=="loop":
fichero.write("jump title "+str(titles)+";\n")
elif action=="next":
if titles==total_t:
next_t=1
else:
next_t=titles+1
fichero.write("jump title "+str(next_t)+";\n")
elif action=="last":
fichero.write("jump title "+str(total_t)+";\n")
fichero.write("\n")
fichero.write("\n\n")
fichero.write("")
fichero.close()
return False
except IOError:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Failed to write to the destination directory.\nCheck that you have privileges and free space there."),arbol)
return True
def create_dvd_structure(arbol,global_vars,filefolder,filename,total,erase_temporary_files):
""" Uses DVDAuthor to create the DVD structure in disk """
global_vars["cancel_prog"]=False
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
wprogress=arbol.get_widget("wprogress")
label.set_text(_("Creating DVD tree structure"))
total2=0
total_films=total-1
percent1=float((100*(total-2))/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
ppartial.set_text("")
command=""
if sys.platform=='win32':
command="dvdauthor.exe"
else:
command="dvdauthor"
handler=launch_program([command,"-x",filefolder+filename+".xml"])
refresh_screen()
temporal=""
#if sys.platform=='win32':
# v1=win32subprocess.recv_some(handler)
v1=""
contador=0
chars_to_read=80
while (handler.poll()==None):
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handler)
except Exception:
break
else:
v1,v2,v3=select.select([handler.stderr,handler.stdout],[],[],0)
if len(v1)!=0:
for elem in v1:
temporal=elem.readline(chars_to_read)
print temporal,
ppartial.pulse()
if temporal=="":
continue
if temporal.find("INFO: Video")!=-1:
total2+=1
percent2=float((100*total2)/total_films)
percent1=float((100*(total-2))/total)+(percent2/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
else:
position=temporal.find("STAT: VOBU ")
if position!=-1:
ppartial.set_text("VOBU "+temporal[position+11:temporal.find(" ",position+11)])
else:
position=temporal.find("STAT: fixing VOBU at ")
if (position!=-1):
position2=temporal.find("%",position+21)
if (position2!=-1):
cadena=temporal[position2-2:position2]
ppartial.set_text(cadena+"%")
ppartial.set_fraction((float(cadena))/100.0)
chars_to_read=200
contador+=1
if contador==50:
refresh_screen() # if there's always lines, we refresh each 50 lines
else:
if chars_to_read==80:
time.sleep(.2) # as soon as there are no lines, we wait 1/5 of second
else:
time.sleep(1) # or one second if we are with percentages
refresh_screen() # and refresh the screen
if (global_vars["cancel_prog"]):
break
cause=0
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handler._handle), -1)
except Exception , err:
print "Error: ", err
else:
os.kill(handler.pid,signal.SIGKILL)
handler.wait()
retcode=handler.returncode
if (retcode!=0) and (retcode!=-9):
cause=1
global_vars["cancel_prog"]=True
if global_vars["cancel_prog"]:
wprogress.hide()
if cause==0:
w=arbol.get_widget("w_aborted")
w.show()
return True
if cause==1:
show_error2(_("Failed to create the DVD tree\nMaybe you ran out of disk space"),arbol)
return True
if erase_temporary_files:
# TODO rm
print "\nDeleting temporary files: "+filename+"_??_??.mpg and .xml"
newfilename=filefolder+filename
newfile2=newfilename+"_[0-9][0-9]_[0-9][0-9].mpg"
for thefile in glob.glob(newfile2):
print "removing file: " , thefile
try:
os.remove(thefile)
except OSError:
print str(thefile)+" not removed because it doesn't exists"
try:
print newfilename+".xml"
os.remove(newfilename+".xml")
except OSError:
print newfilename+".xml not found. Cannot delete"
try:
print newfilename+"_menu.xml"
os.remove(newfilename+"_menu.xml")
except OSError:
print newfilename+"_menu.xml not found. Cannot delete"
try:
print newfilename+"_menu2.xml"
os.remove(newfilename+"_menu2.xml")
except OSError:
print newfilename+"_menu2.xml not found. Cannot delete"
try:
print newfilename+"_menu.mpg"
os.remove(newfilename+"_menu.mpg")
except OSError:
print newfilename+"_menu.mpg not found. Cannot delete"
try:
print newfilename+"_menu2.mpg"
os.remove(newfilename+"_menu2.mpg")
except OSError:
print newfilename+"_menu2.mpg not found. Cannot delete"
try:
print newfilename+"_menu_bg.png"
os.remove(newfilename+"_menu_bg.png")
except OSError:
print newfilename+"_menu_bg.png not found. Cannot delete"
return False
def create_vcd_structure(arbol,structure,global_vars,filefolder,filename,erase_temporary_files):
""" Uses VCDImager to create the ISO file """
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
wprogress=arbol.get_widget("wprogress")
print "Convirtiendo xCD"
label.set_text(_("Creating BIN/CUE files"))
cantidad=len(structure[0])-1
if sys.platform!='win32':
lista=["vcdimager","-c",filefolder+filename+".cue","-b",filefolder+filename+".bin","-t"]
else:
lista=["vcdimager.exe","-c",filefolder+filename+".cue","-b",filefolder+filename+".bin","-t"]
if global_vars["disctocreate"]=="vcd":
lista.append("vcd2")
else:
lista.append("svcd")
for variable in range(cantidad):
currentfile=create_filename(filefolder+filename,1,variable+1)
lista.append(currentfile)
ppartial.set_fraction(0)
cantidad2=float(cantidad)
fraccion=cantidad2/(cantidad2+1)
ptotal.set_fraction(fraccion)
ptotal.set_text(str(int(fraccion*100))+"%")
cause=0
global_vars["cancel_prog"]=False
refresh_screen()
handler=launch_program(lista,False)
while (None==handler.poll()):
refresh_screen()
time.sleep(1)
ppartial.pulse()
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handler._handle), -1)
except Exception , err:
print "Error: ", err
else:
os.kill(handler.pid,signal.SIGKILL)
break
handler.wait()
retcode=handler.returncode
print "Retorno: "+str(retcode)
if (retcode!=0) and (retcode!=-9):
cause=1
global_vars["cancel_prog"]=True
if global_vars["cancel_prog"]:
wprogress.hide()
if cause==0:
w=arbol.get_widget("w_aborted")
w.show()
return True
if cause==1:
show_error2(_("Failed to create the BIN/CUE files\nMaybe you ran out of disk space"),arbol)
return True
if erase_temporary_files:
print "Deleting temporary files: "+filename+"_01_??.mpg and .xml"
newfilename=""
if sys.platform=='win32':
newfilename=filefolder+filename
else:
newfilename=addbarr(filefolder+filename)
# TODO
for file in glob.glob(newfilename+"_[0-9][0-9]_[0-9][0-9]"+".mpg"):
print "removing file: " , newfilename
try:
os.remove(file)
except OSError:
print "not removed because it doesn't exists"
#handle=subprocess.Popen("rm "+newfilename+".xml",bufsize=8192,shell=True)
#handle.wait()
try:
os.remove(newfilename+".xml")
except OSError:
print "not removed because it doesn't exists"
return False
def create_iso(arbol,global_vars,total,filefolder,filename,erase_temporary_files):
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
wprogress=arbol.get_widget("wprogress")
label.set_text(_("Creating ISO file"))
percent1=float((100*(total-1))/total)
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
ppartial.set_fraction(0)
ppartial.set_text("0%")
command=""
if sys.platform=='win32':
command="mkisofs.exe"
else:
command="mkisofs"
volume="DVD-VIDEO"
handler=launch_program([command,"-dvd-video","-V",volume,"-v","-o",filefolder+filename+".iso",filefolder+filename])
refresh_screen()
temporal=''
v1=""
while (handler.poll()==None):
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handler)
except Exception:
break
else:
v1,v2,v3=select.select([handler.stderr,handler.stdout],[],[],0)
for elem in v1:
temporal=elem.readline(80)
if temporal=="":
continue
punto=temporal.find("done, estimate")
if (punto!=-1):
if ((temporal[2].isdigit()) and ((temporal[1].isdigit()) or (temporal[1]==" "))):
percent2=float(temporal[1:3])
percent1=float(((100*(total-1))/total)+(percent2/total))
ptotal.set_fraction(percent1/100)
ptotal.set_text(str(int(percent1))+"%")
ppartial.set_fraction(percent2/100)
ppartial.set_text(str(int(percent2))+"%")
refresh_screen()
if (global_vars["cancel_prog"]):
break
cause=0
if global_vars["cancel_prog"]:
if sys.platform=='win32':
try:
win32api.TerminateProcess(int(handler._handle), -1)
except Exception , err:
print "Error: ", err
else:
os.kill(handler.pid,signal.SIGKILL)
handler.wait()
retcode=handler.returncode
if retcode!=0:
cause=1
global_vars["cancel_prog"]=True
if global_vars["cancel_prog"]:
wprogress.hide()
if cause==0:
w=arbol.get_widget("w_aborted")
w.show()
return True
if cause==1:
show_error2(_("Failed to create the ISO image\nMaybe you ran out of disk space"),arbol)
return True
if erase_temporary_files:
print "erasing DVD tree folder"
# TODO
#handle=subprocess.Popen("rm -rf \""+filefolder+filename+"\"",bufsize=8192,shell=True)
#handle.wait()
shutil.rmtree(filefolder+filename)
return False
def create_menu_stream(arbol,filefolder,filename,structure,global_vars):
""" Creates the menu stream """
cantidad=len(structure)
if global_vars["menu_PAL"]:
formato="pal"
else:
formato="ntsc"
if global_vars["menu_widescreen"]:
menu_wide="_wide"
else:
menu_wide=""
try:
fichero=open(filefolder+filename+"_menu.xml","w")
fichero.write('\n\n\n')
if global_vars["menu_PAL"]:
coord_y=[(53,90),(92,129),(130,167),(168,205),(207,244),(245,282),(283,320),(322,359),(360,397),(398,435),(437,474),(475,512)]
else:
coord_y=[(44,75),(76,107),(108,139),(140,171),(172,203),(204,235),(236,267),(268,299),(300,331),(332,363),(364,395),(396,427)]
for contador in range(cantidad):
fichero.write('\n')
fichero.write("\n\n\n")
fichero.close()
return False
except IOError:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Failed to write to the destination directory.\nCheck that you have privileges and free space there."),arbol)
return True
def menu_set_text(cr,y,texto,widescreen,myfontname="Sans",myfontstyle=cairo.FONT_WEIGHT_BOLD,myfontslant=cairo.FONT_SLANT_NORMAL,myfontsize=12):
if widescreen:
x=0
else:
x=0.125
radius=0.0375
#fontsize=0.048
border=0.0048
linea=0.0024
fontsize2=myfontsize*0.00315
cr.set_line_width(linea)
#cr.set_font_size(fontsize)
cr.select_font_face(myfontname,myfontslant,myfontstyle)
# I created the button image for this size, so I must respect it :(
#xb,yb,width,height,cx,cy=cr.text_extents("TÃtulo 1")
height=0.0391604010025
cr.set_font_size(fontsize2)
xb,y2,width,h2,cx,cy2=cr.text_extents(texto)
cr.set_source_rgba(0,0,0,.75)
cr.move_to(x,y-border)
cr.line_to(1-x,y-border)
cr.curve_to(1-x+radius,y-border,1-x+radius,y+height+border,1-x,y+height+border)
cr.line_to(x,y+height+border)
cr.curve_to(x-radius,y+height+border,x-radius,y-border,x,y-border)
cr.fill()
cr.set_source_rgb(1,1,1)
cr.move_to(.5-width/2-xb,y-y2+(height-h2)/2)
cr.show_text(texto)
def create_menu_bg(arbol,filefolder,filename,structure,global_vars,extcr=None):
wide=False#global_vars["menu_widescreen"]
try:
sf_base=cairo.ImageSurface.create_from_png(global_vars["menu_bg"])
except:
return None
if global_vars["menu_PAL"]:
y=576.0
else:
y=480.0
sf=cairo.ImageSurface(cairo.FORMAT_ARGB32,720,int(y))
wbase=float(sf_base.get_width())
hbase=float(sf_base.get_height())
cr=cairo.Context(sf)
cr.identity_matrix()
cr.scale(720.0/wbase,y/hbase)
cr.set_source_surface(sf_base)
cr.paint()
cr.identity_matrix()
if wide:
cr.scale(0.75*sf.get_width(),1.33*sf.get_height()) # picture gets from 0 to 1 in X and from 0 to 0.75 in Y
cr.translate(0.166666666,0)
else:
cr.scale(sf.get_width(),1.33*sf.get_height()) # picture gets from 0 to 1 in X and from 0 to 0.75 in Y
pos_y=0.075
font_elements=[]
font_temp=global_vars["fontname"]
while True:
pos=font_temp.find(" ")
if pos==-1:
font_elements.append(font_temp) # add the last element
break
font_elements.append(font_temp[:pos])
longitud=len(font_temp)
if pos+1==longitud: # a missed blank space at the end
break
font_temp=font_temp[pos+1:]
if (len(font_elements))<2:
fontname="Sans"
fontstyle=cairo.FONT_WEIGHT_NORMAL
fontslant=cairo.FONT_SLANT_NORMAL
fontsize=12
else:
fontname=""
fontstyle=cairo.FONT_WEIGHT_NORMAL
fontslant=cairo.FONT_SLANT_NORMAL
for counter in range(len(font_elements)-1):
if font_elements[counter]=="Bold":
fontstyle=cairo.FONT_WEIGHT_BOLD
elif font_elements[counter]=="Italic":
fontslant=cairo.FONT_SLANT_ITALIC
else:
fontname+=" "+font_elements[counter]
if fontname!="":
fontname=fontname[1:]
else:
fontname="Sans"
try:
fontsize=float(font_elements[-1])
except:
fontsize=12
for entrada in structure:
menu_set_text(cr,pos_y,entrada[0]["nombre"],wide,fontname,fontstyle,fontslant,fontsize)
pos_y+=0.05
if extcr==None:
sf.write_to_png(filefolder+filename+"_menu_bg.png")
return sf
def create_menu_mpg(arbol,filefolder,filename,structure,global_vars):
print "Creating menus"
command_var=[]
if not sys.platform=='win32':
command_var=["mencoder"]
else:
command_var=["mencoder.exe"]
currentfile=filefolder+filename+"_menu.mpg"
command_var.append("-srate")
command_var.append("48000")
command_var.append("-af")
command_var.append("lavcresample=48000")
command_var.append("-oac")
command_var.append("lavc")
command_var.append("-ovc")
command_var.append("lavc")
command_var.append("-of")
command_var.append("mpeg")
command_var.append("-mpegopts")
command_var.append("format=dvd:tsaf")
command_var.append("-ofps")
audio=global_vars["path"]+"silence.wav"
if global_vars["menu_PAL"]:
command_var.append("25")
key="15"
else:
command_var.append("30000/1001")
key="18"
if global_vars["menu_widescreen"]:
wide="16/9"
else:
wide="4/3"
command_var.append("-vf")
if global_vars["menu_PAL"]:
command_var.append("scale=720:576,harddup")
else:
command_var.append("scale=720:480,harddup")
command_var.append("-lavcopts")
command_var.append("vcodec=mpeg2video:trell:mbd=2:vstrict=0:vrc_maxrate=7501:vrc_buf_size=1835:vbitrate=5001:keyint="+key+":acodec=mp2:abitrate=224:aspect="+wide)
command_var.append("-o")
command_var.append(currentfile)
command_var.append("-audiofile")
command_var.append(audio)
command_var.append("-mf")
command_var.append("type=png:fps=1")
origDir=""
if sys.platform=="win32":
temp=os.path.split(filefolder+filename+"_menu_bg.png")
picDir=temp[0]
picName=temp[1]
command_var.append("mf://"+picName)
os.chdir(picDir)
else:
command_var.append("mf://"+filefolder+filename+"_menu_bg.png")
print "Lanzo "+str(command_var)
handler=launch_program(command_var)
if sys.platform=="win32":
wd=sys.path[-1:]
os.chdir(wd[0])
print "In: ", os.getcwd()
linea="\n"
while (handler.poll()==None):
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handler)
except Exception:
break
else:
v1,v2,v3=select.select([handler.stderr,handler.stdout],[],[],0)
if (len(v1)==0):
continue
for elem in v1:
if elem==handler.stderr:
linea=handler.stderr.read(80)
elif elem==handler.stdout:
linea=handler.stdout.read(2400)
print linea
handler.wait()
retcode=handler.returncode
if (retcode!=0):
print "Deleting "+currentfile+" due to error or aborting."
try:
os.remove(currentfile)
except OSError:
print currentfile+" didn't exists"
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Menu generation failed."),arbol)
return True
return False
def menu_mplex_buttons(arbol,filefolder,filename,structure,global_vars,erase_temporary_files):
print "Multiplexing menus"
comando=""
wd=sys.path[-1:] # to work with py2exe
if sys.platform=='win32':
b=os.path.join(wd[0], "bin")
comando='"' + os.path.join(b, "spumux.exe") + '" '
else:
comando="spumux "
handle=""
if sys.platform=='win32':
comando+='"' + filefolder+filename+"_menu.xml" + '"' + ' < "' + filefolder+filename+"_menu.mpg" + '" > "'+filefolder+filename+"_menu2.mpg" + '"'
f=open(os.path.join(wd[0],"menu.bat"),"w")
f.write(comando)
f.close()
handle=subprocess.Popen("menu.bat",shell=True,bufsize=32767, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#handle=launch_program("runme.bat")
else:
comando+='"'+filefolder+filename+'_menu.xml" < "'+filefolder+filename+'_menu.mpg" > "'+filefolder+filename+'_menu2.mpg"'
handle=subprocess.Popen(comando,shell=True,bufsize=32767, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print "Launch: "+comando
while (None==handle.poll()):
if sys.platform=='win32':
try:
v1=win32_helper.recv_some(handle)
except Exception:
break
else:
v1,v2,v3=select.select([handle.stderr,handle.stdout],[],[],0)
for elem in v1:
temporal=elem.read(80)
print temporal,
error_ret=handle.wait()
if error_ret!=0:
wprogress=arbol.get_widget("wprogress")
wprogress.hide()
show_error2(_("Can't add the buttons to the menus.\nIt seems a bug of SPUMUX."),arbol)
return True
#TODO
if erase_temporary_files:
try:
os.remove(filefolder+filename+"_menu_bg.png")
except OSError:
print "Error removing ", filefolder+filename+"_menu_bg.png"
try:
os.remove(filefolder+filename+"_menu.xml")
except OSError:
print "Error removing ", filefolder+filename+"_menu.xml"
try:
os.remove(filefolder+filename+"_menu.mpg")
except OSError:
print "Error removing ", filefolder+filename+"_menu.mpg"
return False
def create_dvd3(args,arbol,structure,global_vars):
""" Takes the CD/DVD structure, converts the files, creates the filesystem
and puts all into an ISO image if needed """
wmain=arbol.get_widget("wmain")
wmain.hide()
wprogress=arbol.get_widget("wprogress")
tiempo=time.time()
w=arbol.get_widget("erase_files")
erase_temporary_files=w.get_active()
w=arbol.get_widget("wfolder")
w.hide()
w=arbol.get_widget("directorio_final")
filefolder=w.get_filename()
actions=get_actions(arbol,global_vars)
# check if there's suficient free space in the final directory
if check_free_space(arbol,filefolder,structure,actions,erase_temporary_files):
return
# remove the blank spaces in the generic name, changing them with underscores
filename=get_filename_with_underscores(arbol)
if filefolder[-1]!=os.sep:
filefolder+=os.sep
global_vars["cancel_prog"]=False
erase_all_files(filefolder,filename,global_vars)
# less priority to allow to use the computer without speed penalty while compressing
# removed because the conversion was slower, and with current processors it doesn't matter
#if sys.platform=='win32':
# handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, win32api.GetCurrentProcessId())
# win32process.SetPriorityClass(handle, win32process.BELOW_NORMAL_PRIORITY_CLASS)
#else:
# os.nice(1)
# show the progress window, but clear it before
ppartial=arbol.get_widget("progresspartial")
ptotal=arbol.get_widget("progress_total")
label=arbol.get_widget("lcreating")
ptotal.set_fraction(0)
ptotal.set_text("0%")
ppartial.set_fraction(0)
ppartial.set_text("0%")
label.set_text("")
wprogress.show()
refresh_screen()
refresh_screen()
# calculate the number of operations to do
total=0
for elemento in structure:
total+=((len(elemento))-1)
total+=(actions-1)
# create the XML file (even with VCD, SVCD or CVD, to check if we have write permissions)
if create_xml(arbol,filefolder,filename,structure,global_vars):
return
# if we want menu, we create here the MPEG stream
if global_vars["do_menu"]:
if create_menu_stream(arbol,filefolder,filename,structure,global_vars):
return
if None==create_menu_bg(arbol,filefolder,filename,structure,global_vars):
show_error2(_("Can't find the menu background.\nCheck the menu options."),arbol)
return
if create_menu_mpg(arbol,filefolder,filename,structure,global_vars):
return
if menu_mplex_buttons(arbol,filefolder,filename,structure,global_vars,erase_temporary_files):
return
print "filefolder 4:", filefolder
resx_inter=0
resy_inter=0
addx=0
addy=0
titles=0
cfiles=0.0
percent1=0
counter=0
cause=0
mplayer_error=False
# convert to MPEG1-PS or MPEG2-PS each file
print "structure: ", structure
for title in structure:
if global_vars["cancel_prog"]:
break
titles+=1
if len(title)>1:
files=0
for afile in title[1:]:
files+=1
if False==convert_file(arbol,global_vars,afile,filefolder,filename,cfiles,titles,files,total,erase_temporary_files):
cfiles+=1.0
else:
mplayer_error=True
break
# if the conversion fails, check why and show the message
if global_vars["cancel_prog"] or mplayer_error:
return
# if user is creating a DVD and wanted to do the DVD structure:
if (actions>1) and (global_vars["disctocreate"]=="dvd"):
if create_dvd_structure(arbol,global_vars,filefolder,filename,total,erase_temporary_files):
return # if returns True, there was an error
# but if user is creating a VCD, SVCD or CVD and wants to create the BIN/CUE files
if (actions>1) and (global_vars["disctocreate"]!="dvd"):
if create_vcd_structure(arbol,structure,global_vars,filefolder,filename,erase_temporary_files):
return # if returns True, there was an error
# and now, we create the ISO file if the user wanted to create a DVD
if actions>2:
if create_iso(arbol,global_vars,total,filefolder,filename,erase_temporary_files):
return
wprogress.hide()
tiempo2=return_time(time.time()-tiempo,True)
print (tiempo2)
w=arbol.get_widget("elapsed")
w.set_text((_("Elapsed time: "))+tiempo2)
w=arbol.get_widget("w_end")
w.show()