#!/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()