fix cuesheets, add multiple menu pages support, add preview support, add project...
authorAndreas Frisch <andreas.frisch@multimedia-labs.de>
Wed, 3 Sep 2008 12:24:05 +0000 (12:24 +0000)
committerAndreas Frisch <andreas.frisch@multimedia-labs.de>
Wed, 3 Sep 2008 12:24:05 +0000 (12:24 +0000)
lib/python/Plugins/Extensions/DVDBurn/DVDProject.py
lib/python/Plugins/Extensions/DVDBurn/DVDTitle.py
lib/python/Plugins/Extensions/DVDBurn/Makefile.am
lib/python/Plugins/Extensions/DVDBurn/Process.py
lib/python/Plugins/Extensions/DVDBurn/TitleCutter.py
lib/python/Plugins/Extensions/DVDBurn/TitleList.py
lib/python/Plugins/Extensions/DVDBurn/plugin.py

index e7876e41e3387fdfca256be5bc7d3dc981fd8130..48a75544d98b56378ea501f5ebb9cb45bb029720 100644 (file)
@@ -1,20 +1,68 @@
+from Tools.Directories import resolveFilename, fileExists, SCOPE_FONTS, SCOPE_PLUGINS, SCOPE_SKIN
 class DVDProject:
        def __init__(self):
                self.titles = [ ]
                self.target = None
-               self.name = _("New DVD")
+               self.name = _("Dreambox DVD record")
+               self.vmgm = resolveFilename(SCOPE_PLUGINS,"Extensions/DVDBurn/dreamvmgm.mpg")
+               self.menuaudio = resolveFilename(SCOPE_PLUGINS,"Extensions/DVDBurn/silence.mp2")
+               self.menubg = resolveFilename(SCOPE_SKIN, "dreamdvd_02.jpg")
+               # tuples with R, G, B values
+               self.color_button       = ( 0x08, 0x00, 0x00 )
+               self.color_highlight    = ( 0x00, 0xC0, 0xC0 )
+               self.color_headline     = ( 0x00, 0x00, 0x80 )
+               self.font_face = resolveFilename(SCOPE_FONTS, "nmsbd.ttf")
+               # tuple with three pixel values ( headline, title, subtitle )
+               self.font_size = ( 48, 28, 16 )
+               # please supply even numbers for all dimensions
+               self.space_left = 30
+               self.space_top = 120
+               self.space_rows = 36
 
        def addService(self, service):
                import DVDTitle
-               t = DVDTitle.DVDTitle()
-               t.source = service
+               title = DVDTitle.DVDTitle()
+               title.addService(service)
+               self.titles.append(title)
+               return title
+       
+       def saveProject(self, path):
+               import xml.dom.minidom
+               from Tools.XMLTools import elementsWithTag, mergeText, stringToXML
+               list = []
+               list.append('<?xml version="1.0" encoding="utf-8" ?>\n')
+               list.append('<DreamDVDBurnerProject>\n')
+               list.append('\t<config')
+               list.append(' name="' + self.name + '"')
+               list.append(' vmgm="' + self.vmgm + '"')
+               list.append(' />\n')
+               list.append('\t<menu')
+               list.append(' bg="' + self.menubg + '"')
+               list.append(' audio="' + self.menuaudio + '"')
+               list.append(' color_button="' + str(self.color_button) + '"')
+               list.append(' color_highlight="' + str(self.color_highlight) + '"')
+               list.append(' color_headline="' + str(self.color_headline) + '"')
+               list.append(' font_face="' + self.font_face + '"')
+               list.append(' font_size="' + str(self.font_size) + '"')
+               list.append(' space_left="' + str(self.space_left) + '"')
+               list.append(' space_top="' + str(self.space_top) + '"')
+               list.append(' space_rows="' + str(self.space_rows) + '"')
+               list.append(' />\n')
+               list.append('\t<titles>\n')
+               for title in self.titles:
+                       list.append('\t\t<path>')
+                       list.append(stringToXML(title.source.getPath()))
+                       list.append('</path>\n')
+               list.append('\t</titles>\n')
+               list.append('</DreamDVDBurnerProject>\n')
 
-               from enigma import eServiceCenter, iServiceInformation
-               serviceHandler = eServiceCenter.getInstance()
-
-               info = serviceHandler.info(service)
-               descr = info and " " + info.getInfoString(service, iServiceInformation.sDescription) or ""
-               t.name = info and info.getName(service) or "Title" + descr
-
-               self.titles.append(t)
-               return t
+               i = 0
+               filename = path + "/" + self.name + ".ddvdp.xml"
+               while fileExists(filename):
+                       i = i+1
+                       filename = path + "/" + self.name + str(i).zfill(3) + ".ddvdp.xml"
+                               
+               file = open(filename, "w")
+               for x in list:
+                       file.write(x)
+               file.close()
\ No newline at end of file
index bc343e78a40d08d582a2bd61457b14c3ffb5655a..96bb1e73a762c2f8a38701360c85e774eb25bc7a 100644 (file)
@@ -1,9 +1,78 @@
 
 class DVDTitle:
        def __init__(self):
-               self.cutlist = [ ]
+               self.cuesheet = [ ]
                self.source = None
                self.name = ""
+               self.descr = ""
+               self.filesize = 0
+               self.estimatedDiskspace = 0
+               self.inputfile = ""
+               self.cutlist = [ ]
+               self.chaptermarks = [ ]
+
+       def addService(self, service):
+               from os import path
+               from enigma import eServiceCenter, iServiceInformation
+               self.source = service
+               serviceHandler = eServiceCenter.getInstance()
+               info = serviceHandler.info(service)
+               self.descr = info and " " + info.getInfoString(service, iServiceInformation.sDescription) or ""
+               self.name = info and info.getName(service) or "Title" + t.descr
+               self.inputfile = service.getPath()
+               self.filesize = path.getsize(self.inputfile)
+               self.estimatedDiskspace = self.filesize
+
+       def produceFinalCuesheet(self):
+               print "[produceFinalCuesheet] >>> ", self.inputfile, self.cuesheet
+
+               CUT_TYPE_IN = 0
+               CUT_TYPE_OUT = 1
+               CUT_TYPE_MARK = 2
+               CUT_TYPE_LAST = 3
+
+               accumulated_in = 0
+               accumulated_at = 0
+               last_in = 0
+
+               self.cutlist = [ ]
+               self.chaptermarks = [ ]
+
+               # our demuxer expects *strictly* IN,OUT lists.
+               currently_in = not any(type == CUT_TYPE_IN for pts, type in self.cuesheet)
+               if currently_in:
+                       self.cutlist.append(0) # emulate "in" at first          
+
+               for (pts, type) in self.cuesheet:
+                       #print "pts=", pts, "type=", type, "accumulated_in=", accumulated_in, "accumulated_at=", accumulated_at, "last_in=", last_in
+                       if type == CUT_TYPE_IN and not currently_in:
+                               self.cutlist.append(pts)
+                               last_in = pts
+                               currently_in = True
+
+                       if type == CUT_TYPE_OUT and currently_in:
+                               self.cutlist.append(pts)
+
+                               # accumulate the segment
+                               accumulated_in += pts - last_in 
+                               accumulated_at = pts
+                               currently_in = False
+
+                       if type == CUT_TYPE_MARK and currently_in:
+                               # relocate chaptermark against "in" time. This is not 100% accurate,
+                               # as the in/out points are not.
+                               reloc_pts = pts - last_in + accumulated_in
+                               self.chaptermarks.append(reloc_pts)
+                               
+               print "cutlist =", self.cutlist, "chaptermarks =", self.chaptermarks, "accumulated_in =", accumulated_in
 
-       def estimateDiskspace(self):
-               return 0
+               if len(self.cutlist) > 1:
+                       from enigma import eServiceCenter, iServiceInformation
+                       serviceHandler = eServiceCenter.getInstance()
+                       service = self.source
+                       info = serviceHandler.info(service)
+                       lenpts = info.getLength(service) * 90000
+                       part = accumulated_in / float(lenpts)
+                       usedsize = int ( part * self.filesize )
+                       print "lenpts=", lenpts, "part=", part, "filesize=", self.filesize, "estimatedDiskspace=", usedsize
+                       self.estimatedDiskspace = usedsize
index 04659770a81e90af8a72b47a6e022433caf77a15..5906757ce7fb5ad762fd8111453aa60eb809cab5 100644 (file)
@@ -5,4 +5,4 @@ install_PYTHON =        \
        plugin.py \
        DVDProject.py DVDTitle.py TitleCutter.py TitleList.py Process.py
 
-install_DATA = keymap.xml
+install_DATA = keymap.xml silence.mp2 dreamvmgm.mpg
index 217c724cc26b2789c3ca2671ba71672a29c79dca..b9710d5ade3b727b16fb48aa0ee3cd46198557aa 100644 (file)
@@ -1,33 +1,89 @@
 from Components.Task import Task, Job, job_manager, DiskspacePrecondition, Condition
+from Screens.MessageBox import MessageBox
+
+class png2yuvTask(Task):
+       def __init__(self, job, inputfile, outputfile):
+               Task.__init__(self, job, "Creating menu video")
+               self.setTool("/usr/bin/png2yuv")
+               self.args += ["-n1", "-Ip", "-f25", "-j", inputfile]
+               self.dumpFile = outputfile
+               self.weighting = 10
+
+       def run(self, callback, task_progress_changed):
+               Task.run(self, callback, task_progress_changed)
+               self.container.dumpToFile(self.dumpFile)
+
+       def processStderr(self, data):
+               print "[png2yuvTask]", data
+
+       def processStdout(self, data):
+               pass
+
+class mpeg2encTask(Task):
+       def __init__(self, job, inputfile, outputfile):
+               Task.__init__(self, job, "Encoding menu video")
+               self.setTool("/usr/bin/mpeg2enc")
+               self.args += ["-f8", "-np", "-a2", "-o", outputfile]
+               self.inputFile = inputfile
+               self.weighting = 10
+               
+       def run(self, callback, task_progress_changed):
+               Task.run(self, callback, task_progress_changed)
+               self.container.readFromFile(self.inputFile)
+
+       def processOutputLine(self, line):
+               print "[mpeg2encTask]", line
+
+class spumuxTask(Task):
+       def __init__(self, job, xmlfile, inputfile, outputfile):
+               Task.__init__(self, job, "Muxing buttons into menu")
+               self.setTool("/usr/bin/spumux")
+               self.args += [xmlfile]
+               self.inputFile = inputfile
+               self.dumpFile = outputfile
+               self.weighting = 10
+
+       def run(self, callback, task_progress_changed):
+               Task.run(self, callback, task_progress_changed)
+               self.container.dumpToFile(self.dumpFile)
+               self.container.readFromFile(self.inputFile)
+
+       def processStderr(self, data):
+               print "[spumuxTask]", data
+
+       def processStdout(self, data):
+               pass
 
 class MakeFifoNode(Task):
        def __init__(self, job, number):
-               Task.__init__(self, job, "Make FIFO Nodes")
+               Task.__init__(self, job, "Make FIFO nodes")
                self.setTool("/bin/mknod")
                nodename = self.job.workspace + "/dvd_title_%d" % number + ".mpg"
                self.args += [nodename, "p"]
+               self.weighting = 10
 
 class LinkTS(Task):
        def __init__(self, job, sourcefile, link_name):
-               Task.__init__(self, job, "Creating Symlink for source titles")
+               Task.__init__(self, job, "Creating symlink for source titles")
                self.setTool("/bin/ln")
                self.args += ["-s", sourcefile, link_name]
+               self.weighting = 10
 
 class DemuxTask(Task):
-       def __init__(self, job, inputfile, cutlist):
+       def __init__(self, job, inputfile):
                Task.__init__(self, job, "Demux video into ES")
-
-               self.global_preconditions.append(DiskspacePrecondition(4*1024*1024))
+               title = job.project.titles[job.i]
+               self.global_preconditions.append(DiskspacePrecondition(title.estimatedDiskspace))
                self.setTool("/usr/bin/projectx")
-               self.cutfile = self.job.workspace + "/cut.Xcl"
                self.generated_files = [ ]
-               self.cutlist = cutlist
-
                self.end = 300
                self.prog_state = 0
                self.weighting = 1000
-
-               self.args += [inputfile, "-demux", "-out", self.job.workspace, "-cut", self.job.workspace + "/" + self.cutfile ]
+               self.cutfile = self.job.workspace + "/cut_%d.Xcl" % (job.i+1)
+               self.cutlist = title.cutlist
+               self.args += [inputfile, "-demux", "-out", self.job.workspace ]
+               if len(self.cutlist) > 1:
+                       self.args += [ "-cut", self.cutfile ]
 
        def prepare(self):
                self.writeCutfile()
@@ -89,16 +145,18 @@ class DemuxTask(Task):
                                os.remove(f)
 
 class MplexTask(Task):
-       def __init__(self, job, outputfile, demux_task):
+       def __init__(self, job, outputfile, inputfiles=None, demux_task=None):
                Task.__init__(self, job, "Mux ES into PS")
-
                self.weighting = 500
                self.demux_task = demux_task
                self.setTool("/usr/bin/mplex")
                self.args += ["-f8", "-o", outputfile, "-v1"]
+               if inputfiles:
+                       self.args += inputfiles
 
        def prepare(self):
-               self.args += self.demux_task.generated_files
+               if self.demux_task:
+                       self.args += self.demux_task.generated_files
 
        def processOutputLine(self, line):
                print "[MplexTask] processOutputLine=", line
@@ -115,17 +173,19 @@ class RemoveESFiles(Task):
                self.args += [self.demux_task.cutfile]
 
 class DVDAuthorTask(Task):
-       def __init__(self, job):
+       def __init__(self, job, diskspaceNeeded):
                Task.__init__(self, job, "Authoring DVD")
 
+               self.global_preconditions.append(DiskspacePrecondition(diskspaceNeeded))
                self.weighting = 300
                self.setTool("/usr/bin/dvdauthor")
                self.CWD = self.job.workspace
                self.args += ["-x", self.job.workspace+"/dvdauthor.xml"]
+               self.menupreview = job.menupreview
 
        def processOutputLine(self, line):
                print "[DVDAuthorTask] processOutputLine=", line
-               if line.startswith("STAT: Processing"):
+               if not self.menupreview and line.startswith("STAT: Processing"):
                        self.callback(self, [], stay_resident=True)
 
 class DVDAuthorFinalTask(Task):
@@ -165,8 +225,18 @@ class BurnTask(Task):
                self.end = 120 # 100 for writing, 10 for buffer flush, 10 for closing disc
                self.postconditions.append(BurnTaskPostcondition())
                self.setTool("/bin/growisofs")
-               self.args += ["-dvd-video", "-dvd-compat", "-Z", "/dev/cdroms/cdrom0", "-V", "Dreambox_DVD", "-use-the-force-luke=dummy", self.job.workspace + "/dvd"]
+               
+               self.args += ["-dvd-video", "-dvd-compat", "-Z", "/dev/cdroms/cdrom0", "-V", self.getASCIIname(job.project.name), "-P", "Dreambox", "-use-the-force-luke=dummy", self.job.workspace + "/dvd"]
 
+       def getASCIIname(self, name):
+               ASCIIname = ""
+               for char in name.decode("utf-8").encode("ascii","replace"):
+                       if ord(char) <= 0x20 or ( ord(char) >= 0x3a and ord(char) <= 0x40 ):
+                               ASCIIname += '_'
+                       else:
+                               ASCIIname += char
+               return ASCIIname
+               
        def prepare(self):
                self.error = None
 
@@ -205,110 +275,309 @@ class RemoveDVDFolder(Task):
                self.setTool("/bin/rm")
                self.args += ["-rf", self.job.workspace]
 
-class DVDJob(Job):
-       def __init__(self, cue):
-               Job.__init__(self, "DVD Burn")
-               self.cue = cue
-               from time import strftime
-               from Tools.Directories import SCOPE_HDD, resolveFilename, createDir
-               new_workspace = resolveFilename(SCOPE_HDD) + "tmp/" + strftime("%Y%m%d%H%M%S")
-               createDir(new_workspace)
-               self.workspace = new_workspace
-               self.fromDescription(self.createDescription())
+class PreviewTask(Task):
+       def __init__(self, job):
+               Task.__init__(self, job, "Preview")
+               self.job = job
+
+       def run(self, callback, task_progress_changed):
+               self.callback = callback
+               self.task_progress_changed = task_progress_changed
+               if self.job.project.waitboxref:
+                       self.job.project.waitboxref.close()
+               if self.job.menupreview:
+                       self.waitAndOpenPlayer()
+               else:
+                       self.job.project.session.openWithCallback(self.previewCB, MessageBox, _("Do you want to preview this project before burning?"), timeout = 60, default = False)
+       
+       def previewCB(self, answer):
+               if answer == True:
+                       self.waitAndOpenPlayer()
+               else:
+                       self.closedCB(True)
+
+       def playerClosed(self):
+               if self.job.menupreview:
+                       self.closedCB(True)
+               else:
+                       self.job.project.session.openWithCallback(self.closedCB, MessageBox, _("Do you want to burn this project to DVD medium?") )
+
+       def closedCB(self, answer):
+               if answer == True:
+                       Task.processFinished(self, 0)
+               else:
+                       Task.processFinished(self, 1)
 
-       def fromDescription(self, description):
-               nr_titles = int(description["nr_titles"])
-               authorxml = """
+       def waitAndOpenPlayer(self):
+               from enigma import eTimer
+               self.delayTimer = eTimer()
+               self.delayTimer.callback.append(self.previewProject)
+               self.delayTimer.start(10,1)
+               
+       def previewProject(self):
+               from Plugins.Extensions.DVDPlayer.plugin import DVDPlayer
+               self.job.project.session.openWithCallback(self.playerClosed, DVDPlayer, dvd_filelist= [ self.job.project.workspace + "/dvd/VIDEO_TS/" ])
+
+def getTitlesPerMenu(nr_titles):
+       if nr_titles < 6:
+               titles_per_menu = 5
+       else:
+               titles_per_menu = 4
+       return titles_per_menu
+
+def CreateMenus(job):
+       import os, Image, ImageDraw, ImageFont, re
+       imgwidth = 720
+       imgheight = 576
+       
+       im_bg_orig = Image.open(job.project.menubg)
+       if im_bg_orig.size != (imgwidth, imgheight):
+               im_bg_orig = im_bg_orig.resize((720, 576))
+
+       font0 = ImageFont.truetype(job.project.font_face, job.project.font_size[0])
+       font1 = ImageFont.truetype(job.project.font_face, job.project.font_size[1])
+       font2 = ImageFont.truetype(job.project.font_face, job.project.font_size[2])
+       spu_palette = [ 0x60, 0x60, 0x60 ] + list(job.project.color_highlight)
+
+       nr_titles = len(job.project.titles)
+       titles_per_menu = getTitlesPerMenu(nr_titles)
+       job.nr_menus = ((nr_titles+titles_per_menu-1)/titles_per_menu)
+
+       #a new menu_count every 5 titles (1,2,3,4,5->1 ; 6,7,8,9,10->2 etc.)
+       for menu_count in range(1 , job.nr_menus+1):
+               im_bg = im_bg_orig.copy()
+               im_high = Image.new("P", (imgwidth, imgheight), 0)
+               im_high.putpalette(spu_palette)
+               draw_bg = ImageDraw.Draw(im_bg)
+               draw_high = ImageDraw.Draw(im_high)
+
+               if menu_count == 1:
+                       headline = job.project.name.decode("utf-8")
+                       textsize = draw_bg.textsize(headline, font=font0)
+                       if textsize[0] > imgwidth:
+                               offset = (0 , 20)
+                       else:
+                               offset = (((imgwidth-textsize[0]) / 2) , 20)
+                       draw_bg.text(offset, headline, fill=job.project.color_headline, font=font0)
+               
+               menubgpngfilename = job.workspace+"/dvd_menubg"+str(menu_count)+".png"
+               highlightpngfilename = job.workspace+"/dvd_highlight"+str(menu_count)+".png"
+               spuxml = """<?xml version="1.0" encoding="utf-8"?>
+       <subpictures>
+       <stream>
+       <spu 
+       highlight="%s"
+       transparent="%02x%02x%02x"
+       start="00:00:00.00"
+       force="yes" >""" % (highlightpngfilename, spu_palette[0], spu_palette[1], spu_palette[2])
+
+               rowheight = (job.project.font_size[1]+job.project.font_size[2]+job.project.space_rows)
+               menu_start_title = (menu_count-1)*titles_per_menu + 1
+               menu_end_title = (menu_count)*titles_per_menu + 1
+               if menu_end_title > nr_titles:
+                       menu_end_title = nr_titles+1
+               menu_i = 0
+               for title_no in range( menu_start_title , menu_end_title ):
+                       i = title_no-1
+                       top = job.project.space_top + ( menu_i * rowheight )
+                       menu_i += 1
+                       title = job.project.titles[i]
+                       titlename = title.name.decode("utf-8")
+                       menuitem = "%d. %s" % (title_no, titlename)
+                       draw_bg.text((job.project.space_left,top), menuitem, fill=job.project.color_button, font=font1)
+                       draw_high.text((job.project.space_left,top), menuitem, fill=1, font=font1)
+                       res = re.search("(?:/.*?).*/(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2}).(?P<hour>\d{2})(?P<minute>\d{2}).-.*.?.ts", title.inputfile)
+                       subtitle = ""
+                       if res:
+                               subtitle = "%s-%s-%s, %s:%s. " % (res.group("year"),res.group("month"),res.group("day"),res.group("hour"),res.group("minute"))
+                       if len(title.descr) > 1:
+                               subtitle += title.descr.decode("utf-8") + ". "
+                       if len(title.chaptermarks) > 1:
+                               subtitle += (" (%d %s)" % (len(title.chaptermarks)+1, _("chapters")))
+                       draw_bg.text((job.project.space_left,top+36), subtitle, fill=job.project.color_button, font=font2)
+       
+                       bottom = top+rowheight
+                       if bottom > imgheight:
+                               bottom = imgheight
+                       spuxml += """
+       <button name="button%s" x0="%d" x1="%d" y0="%d" y1="%d"/>""" % (str(title_no).zfill(2),job.project.space_left,imgwidth,top,bottom )
+               if menu_count > 1:
+                       prev_page_text = "<<<"
+                       textsize = draw_bg.textsize(prev_page_text, font=font1)
+                       offset = ( 2*job.project.space_left, job.project.space_top + ( titles_per_menu * rowheight ) )
+                       draw_bg.text(offset, prev_page_text, fill=job.project.color_button, font=font1)
+                       draw_high.text(offset, prev_page_text, fill=1, font=font1)
+                       spuxml += """
+       <button name="button_prev" x0="%d" x1="%d" y0="%d" y1="%d"/>""" % (offset[0],offset[0]+textsize[0],offset[1],offset[1]+textsize[1])
+
+               if menu_count < job.nr_menus:
+                       next_page_text = ">>>"
+                       textsize = draw_bg.textsize(next_page_text, font=font1)
+                       offset = ( imgwidth-textsize[0]-2*job.project.space_left, job.project.space_top + ( titles_per_menu * rowheight ) )
+                       draw_bg.text(offset, next_page_text, fill=job.project.color_button, font=font1)
+                       draw_high.text(offset, next_page_text, fill=1, font=font1)
+                       spuxml += """
+       <button name="button_next" x0="%d" x1="%d" y0="%d" y1="%d"/>""" % (offset[0],offset[0]+textsize[0],offset[1],offset[1]+textsize[1])
+                               
+               del draw_bg
+               del draw_high
+               fd=open(menubgpngfilename,"w")
+               im_bg.save(fd,"PNG")
+               fd.close()
+               fd=open(highlightpngfilename,"w")
+               im_high.save(fd,"PNG")
+               fd.close()
+       
+               png2yuvTask(job, menubgpngfilename, job.workspace+"/dvdmenubg"+str(menu_count)+".yuv")
+               menubgm2vfilename = job.workspace+"/dvdmenubg"+str(menu_count)+".mv2"
+               mpeg2encTask(job, job.workspace+"/dvdmenubg"+str(menu_count)+".yuv", menubgm2vfilename)
+               menubgmpgfilename = job.workspace+"/dvdmenubg"+str(menu_count)+".mpg"
+               MplexTask(job, outputfile=menubgmpgfilename, inputfiles = [menubgm2vfilename, job.project.menuaudio])
+       
+               spuxml += """
+       </spu>
+       </stream>
+       </subpictures>"""
+               spuxmlfilename = job.workspace+"/spumux"+str(menu_count)+".xml"
+               f = open(spuxmlfilename, "w")
+               f.write(spuxml)
+               f.close()
+               
+               menuoutputfilename = job.workspace+"/dvdmenu"+str(menu_count)+".mpg"
+               spumuxTask(job, spuxmlfilename, menubgmpgfilename, menuoutputfilename)
+               
+def CreateAuthoringXML(job):
+       nr_titles = len(job.project.titles)
+       titles_per_menu = getTitlesPerMenu(nr_titles)
+       authorxml = """<?xml version="1.0" encoding="utf-8"?>
 <dvdauthor dest="%s">
    <vmgm>
       <menus>
          <pgc>
-            <post> jump title 1; </post>
+            <vob file="%s" />
+            <post> jump titleset 1 menu; </post>
          </pgc>
       </menus>
    </vmgm>
    <titleset>
-      <titles>""" % (self.workspace+"/dvd")
-               for i in range(nr_titles):
-                       chapterlist_entries = description["chapterlist%d_entries" % i]
-                       chapterlist = [ ]
-                       print str(chapterlist_entries)
-                       for j in range(chapterlist_entries):
-                               chapterlist.append(int(description["chapterlist%d_%d" % (i, j)]))
-                       print str(chapterlist)
-                       chapters = ','.join(["%d:%02d:%02d.%03d," % (p / (90000 * 3600), p % (90000 * 3600) / (90000 * 60), p % (90000 * 60) / 90000, (p % 90000) / 90) for p in chapterlist])
-
-                       title_no = i+1
-                       MakeFifoNode(self, title_no)
-                       vob_tag = """file="%s/dvd_title_%d.mpg" chapters="%s" />""" % (self.workspace, title_no, chapters)
-                                               
-                       if title_no < nr_titles:
-                               post_tag = "> jump title %d;</post>" % ( title_no+1 )
-                       else:
-                               post_tag = " />"
+      <menus>
+         <video aspect="4:3"/>"""% (job.workspace+"/dvd", job.project.vmgm)
+       for menu_count in range(1 , job.nr_menus+1):
+               if menu_count == 1:
+                       authorxml += """
+         <pgc entry="root">"""
+               else:
                        authorxml += """
+         <pgc>"""
+               menu_start_title = (menu_count-1)*titles_per_menu + 1
+               menu_end_title = (menu_count)*titles_per_menu + 1
+               if menu_end_title > nr_titles:
+                       menu_end_title = nr_titles+1
+               for i in range( menu_start_title , menu_end_title ):
+                       authorxml += """
+            <button name="button%s">jump title %d;</button>""" % (str(i).zfill(2), i)
+               
+               if menu_count > 1:
+                       authorxml += """
+            <button name="button_prev">jump menu %d;</button>""" % (menu_count-1)
+                       
+               if menu_count < job.nr_menus:
+                       authorxml += """
+            <button name="button_next">jump menu %d;</button>""" % (menu_count+1)
+
+               menuoutputfilename = job.workspace+"/dvdmenu"+str(menu_count)+".mpg"
+               authorxml += """
+            <vob file="%s" pause="inf"/>
+        </pgc>""" % menuoutputfilename
+       authorxml += """
+      </menus>
+      <titles>"""
+       for i in range( nr_titles ):
+               chapters = ','.join(["%d:%02d:%02d.%03d" % (p / (90000 * 3600), p % (90000 * 3600) / (90000 * 60), p % (90000 * 60) / 90000, (p % 90000) / 90) for p in job.project.titles[i].chaptermarks])
+
+               title_no = i+1
+               title_filename = job.workspace + "/dvd_title_%d.mpg" % (title_no)
+               
+               if job.menupreview:
+                       LinkTS(job, job.project.vmgm, title_filename)
+               else:
+                       MakeFifoNode(job, title_no)
+               
+               vob_tag = """file="%s" chapters="%s" />""" % (title_filename, chapters)
+                                       
+               if title_no < nr_titles:
+                       post_tag = "jump title %d;" % ( title_no+1 )
+               else:
+                       post_tag = "call vmgm menu 1;"
+               authorxml += """
          <pgc>
             <vob %s
-            <post%s
+            <post> %s </post>
          </pgc>""" % (vob_tag, post_tag)
-               authorxml += """
-      </titles>
+        
+       authorxml += """
+     </titles>
    </titleset>
 </dvdauthor>
 """
-               f = open(self.workspace+"/dvdauthor.xml", "w")
-               f.write(authorxml)
-               f.close()
+       f = open(job.workspace+"/dvdauthor.xml", "w")
+       f.write(authorxml)
+       f.close()
 
-               DVDAuthorTask(self)
-
-               for i in range(nr_titles):
-                       inputfile = description["inputfile%d" % i]
-                       cutlist_entries = description["cutlist%d_entries" % i]
-                       cutlist = [ ]
-                       for j in range(cutlist_entries):
-                               cutlist.append(int(description["cutlist%d_%d" % (i, j)]))
-
-                       link_name =  self.workspace + "/source_title_%d.ts" % (i+1)
-                       LinkTS(self, inputfile, link_name)
-                       demux = DemuxTask(self, inputfile = link_name, cutlist = cutlist)
-                       title_filename =  self.workspace + "/dvd_title_%d.mpg" % (i+1)
-                       MplexTask(self, title_filename, demux)
-                       RemoveESFiles(self, demux)
-                       
-                       #RemovePSFile(self, title_filename)
-               #DVDAuthorFinalTask(self)
-               WaitForResidentTasks(self)
-               BurnTask(self)
+class DVDJob(Job):
+       def __init__(self, project, menupreview=False):
+               Job.__init__(self, "DVD Burn")
+               self.project = project
+               from time import strftime
+               from Tools.Directories import SCOPE_HDD, resolveFilename, createDir
+               new_workspace = resolveFilename(SCOPE_HDD) + "tmp/" + strftime("%Y%m%d%H%M%S")
+               createDir(new_workspace)
+               self.workspace = new_workspace
+               self.project.workspace = self.workspace
+               self.menupreview = menupreview
+               self.conduct()
+
+       def conduct(self):
+               CreateMenus(self)
+               CreateAuthoringXML(self)
+
+               totalsize = 50*1024*1024 # require an extra safety 50 MB
+               maxsize = 0
+               for title in self.project.titles:
+                       titlesize = title.estimatedDiskspace
+                       if titlesize > maxsize: maxsize = titlesize
+                       totalsize += titlesize
+               diskSpaceNeeded = totalsize + maxsize
+               print "diskSpaceNeeded:", diskSpaceNeeded
+
+               DVDAuthorTask(self, diskSpaceNeeded)
+               
+               nr_titles = len(self.project.titles)
+               
+               if self.menupreview:
+                       PreviewTask(self)
+               else:
+                       for self.i in range(nr_titles):
+                               title = self.project.titles[self.i]
+                               link_name =  self.workspace + "/source_title_%d.ts" % (self.i+1)
+                               title_filename = self.workspace + "/dvd_title_%d.mpg" % (self.i+1)
+                               LinkTS(self, title.inputfile, link_name)
+                               demux = DemuxTask(self, link_name)
+                               MplexTask(self, outputfile=title_filename, demux_task=demux)
+                               RemoveESFiles(self, demux)
+                       WaitForResidentTasks(self)
+                       PreviewTask(self)
+                       BurnTask(self)
                #RemoveDVDFolder(self)
 
-       def createDescription(self):
-               # self.cue is a list of titles, with 
-               #   each title being a tuple of 
-               #     inputfile,
-               #     a list of cutpoints (in,out)
-               #     a list of chaptermarks
-               # we turn this into a flat dict with
-               # nr_titles = the number of titles,
-               # cutlist%d_entries = the number of cutlist entries for title i,
-               # cutlist%d_%d = cutlist entry j for title i,
-               # chapterlist%d_entries = the number of chapters for title i,
-               # chapterlist%d_%d = chapter j for title i
-               res = { "nr_titles": len(self.cue) }
-               for i in range(len(self.cue)):
-                       c = self.cue[i]
-                       res["inputfile%d" % i] = c[0]
-                       res["cutlist%d_entries" % i] = len(c[1])
-                       for j in range(len(c[1])):
-                               res["cutlist%d_%d" % (i,j)] = c[1][j]
-
-                       res["chapterlist%d_entries" % i] = len(c[2])
-                       for j in range(len(c[2])):
-                               res["chapterlist%d_%d" % (i,j)] = c[2][j]
-               return res
-
-def Burn(session, cue):
+def Burn(session, project):
        print "burning cuesheet!"
-       j = DVDJob(cue)
+       j = DVDJob(project)
+       job_manager.AddJob(j)
+       return j
+
+def PreviewMenu(session, project):
+       print "preview DVD menu!"
+       j = DVDJob(project, menupreview=True)
        job_manager.AddJob(j)
        return j
index 3cba54af34366433ff06cfbb322494a3ac063036..290b2d839f5b760a7b2f15f6ebfd4228737b1951 100644 (file)
@@ -1,5 +1,6 @@
 from Plugins.Extensions.CutListEditor.plugin import CutListEditor
 
+
 class TitleCutter(CutListEditor):
        def __init__(self, session, title):
                CutListEditor.__init__(self, session, title.source)
@@ -8,3 +9,10 @@ class TitleCutter(CutListEditor):
        def exit(self):
                self.session.nav.stopService()
                self.close(self.cut_list[:])
+
+class CutlistReader(TitleCutter):
+       def __init__(self, session, title):
+               TitleCutter.__init__(self, session, title)
+               self.tutorial_seen = True
+               self.session.nav.stopService()
+               self.close(self.cut_list[:])
index 1b289322b2e46bd24d692652a0316ab82a1da90d..2cbdf0b2887cc5fe557ac5f93cbc761771dc4d6e 100644 (file)
@@ -1,13 +1,67 @@
 import DVDProject, TitleList, TitleCutter
 
 from Screens.Screen import Screen
+from Screens.ChoiceBox import ChoiceBox
+from Screens.InputBox import InputBox
+from Screens.MessageBox import MessageBox
 from Components.ActionMap import HelpableActionMap, ActionMap
 from Components.Sources.List import List
 from Components.Sources.StaticText import StaticText
+from Components.Sources.Progress import Progress
+from Components.FileList import FileList
 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT
 
-class TitleList(Screen):
+class WaitBox(MessageBox):
+       def __init__(self, session, callback):
+               MessageBox.__init__(self, session, text=_("Preparing... Please wait"), type = MessageBox.TYPE_INFO)
+               self.skinName = "MessageBox"
+               self.CB = callback
+               self.onShown.append(self.runCB)
+       
+       def ok(self):
+               pass
+
+       def runCB(self):
+               from enigma import eTimer
+               self.delayTimer = eTimer()
+               self.delayTimer.callback.append(self.CB)
+               self.delayTimer.start(10,1)
+
+class FileBrowser(Screen):
+       skin = """
+       <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
+               <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
+       </screen>"""
+       def __init__(self, session, currDir = None, projectBrowser = False):
+               Screen.__init__(self, session)
+               self.projectBrowser = projectBrowser
+               if not currDir:
+                       currDir = "/"
+
+               if projectBrowser:
+                       self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(ddvdp\.xml)")
+               else:
+                       self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(jpeg|jpg|jpe|png|bmp)")
+               self["filelist"] = self.filelist
+
+               self["FilelistActions"] = ActionMap(["OkCancelActions"],
+                       {
+                               "ok": self.ok,
+                               "cancel": self.exit
+                       })
+
+       def ok(self):
+               if self.filelist.canDescent():
+                       self.filelist.descent()
+               else:
+                       ret = self["filelist"].getCurrentDirectory() + '/' + self["filelist"].getFilename()
+                       self.close(ret,self.projectBrowser)
+
+       def exit(self):
+               self.close(None)
 
+
+class TitleList(Screen):
        skin = """
                <screen position="90,83" size="560,445" title="DVD Tool" >
                    <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
@@ -18,28 +72,29 @@ class TitleList(Screen):
                    <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
                    <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
                    <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
-                   <widget source="title_label" render="Label" position="6,48" size="436,24" font="Regular;18" />
-                   <widget source="titles" render="Listbox" scrollbarMode="showOnDemand" position="6,72" size="540,350">
+                   <widget source="title_label" render="Label" position="6,48" size="540,38" font="Regular;18" />
+                   <widget source="titles" render="Listbox" scrollbarMode="showOnDemand" position="10,86" size="540,312">
                        <convert type="StaticMultiList" />
                    </widget>
-                   <widget source="statusbar" render="Label" position="6,422" size="548,24" font="Regular;18" halign="left" />
+                   <widget source="space_bar" render="Progress" position="10,410" size="540,26" borderWidth="1" backgroundColor="#254f7497" />
+                   <widget source="space_label" render="Label" position="40,414" size="480,22" zPosition="2" font="Regular;18" halign="center" transparent="1" foregroundColor="#000000" />
                </screen>"""
 
        def __init__(self, session, project = None):
                Screen.__init__(self, session)
-
-               if project is not None:
-                       self.project = project
-               else:
-                       self.newProject()
-
+               
                self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
                        {
-                               "addTitle": (self.addTitle, _("Add a new title"), _("Add title...")),
-                               "editTitle": (self.editTitle, _("Edit current title"), _("Edit title...")),
+                               "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
+                               "editTitle": (self.editTitle, _("Edit chapters of current title"), _("Edit title")),
                                "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
-                               "saveProject": (self.saveProject, _("Save current project to disk"), _("Save...")),
-                               "burnProject": (self.burnProject, _("Burn DVD"), _("Burn")),
+                               "saveProject": (self.saveProject, _("Save current project to disk"), _("Save")),
+                               "burnProject": (self.burnProject, _("Burn DVD"), _("Burn DVD")),
+                       })
+
+               self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
+                       {
+                               "contextMenu": (self.showMenu, _("menu")),
                        })
 
                self["key_red"] = StaticText(_("Add title"))
@@ -47,8 +102,9 @@ class TitleList(Screen):
                self["key_yellow"] = StaticText(_("Remove title"))
                self["key_blue"] = StaticText(_("Save"))
 
-               self["title_label"] = StaticText(_("Table of content to be burned to DVD:"))
-               self["statusbar"] = StaticText(_("When complete, press record key to burn the collection!"))
+               self["title_label"] = StaticText()
+               self["space_label"] = StaticText()
+               self["space_bar"] = Progress()
 
                self["actions"] = ActionMap(["OkCancelActions"],
                        {
@@ -56,30 +112,92 @@ class TitleList(Screen):
                        })
 
                #Action("addTitle", self.addTitle)
+               
+               if project is not None:
+                       self.project = project
+               else:
+                       self.newProject()
 
                self["titles"] = List(list = [ ], enableWrapAround = True, item_height=30, fonts = [gFont("Regular", 20)])
                self.updateTitleList()
-
+               self.updateCollectionName()
+                               
                #self["addTitle"] = ActionButton("titleactions", "addTitle")
                #self["editTitle"] = ActionButton("titleactions", "editTitle")
                #self["removeCurrentTitle"] = ActionButton("titleactions", "removeCurrentTitle")
                #self["saveProject"] = ActionButton("titleactions", "saveProject")
                #self["burnProject"] = ActionButton("titleactions", "burnProject")
+               
+       def showMenu(self):
+               menu = []
+               menu.append((_("Add a new title"), "addtitle"));
+               menu.append((_("Remove title"), "removetitle"));
+               menu.append((_("Edit chapters of current title"), "edittitle"));
+               menu.append((_("Set collection name"), "setname"));
+               menu.append((_("Set menu background"), "setbackground"));
+               menu.append((_("Save current project to disk"), "save"));
+               menu.append((_("Load saved project from disk"), "load"));
+               menu.append((_("Preview menu"), "previewMenu"));
+               menu.append((_("Burn DVD"), "burn"));
+               self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
+
+       def menuCallback(self, choice):
+               if choice is None:
+                       return
+
+               if choice[1] == "removetitle":
+                       self.removeCurrentTitle()
+               elif choice[1] == "addtitle":
+                       self.addTitle()
+               elif choice[1] == "edittitle":
+                       self.editTitle()
+               elif choice[1] == "setname":
+                       self.setName()
+               elif choice[1] == "setbackground":
+                       self.showFileBrowser(False)
+               elif choice[1] == "save":
+                       self.saveProject()
+               elif choice[1] == "load":
+                       self.showFileBrowser(True)
+               elif choice[1] == "previewMenu":
+                       self.previewMenu()
+               elif choice[1] == "burn":
+                       self.burnProject()
+
+       def setName(self):
+               self.session.openWithCallback(self.setNameCallback, InputBox, title=_("Set collection name"), text=self.project.name, maxSize=False, visible_width = 56)
+               
+       def setNameCallback(self, name):
+               if name is not None:
+                       self.project.name = name
+                       self.updateCollectionName()
 
        def newProject(self):
                self.project = DVDProject.DVDProject()
                self.project.titles = [ ]
+               self.project.session = self.session
+               self.updateCollectionName()
+
+       def updateCollectionName(self):
+               self["title_label"].text = _("Table of content for collection") + " \"" + self.project.name + "\":"
 
        def addTitle(self):
                from Screens.MovieSelection import MovieSelection
-               self.session.openWithCallback(self.selectedSource, MovieSelection)
+               class MovieSelectionNoMenu(MovieSelection):
+                       def __init__(self, session):
+                               MovieSelection.__init__(self, session)
+                               self.skinName = "MovieSelection"
+
+                       def doContext(self):
+                               print "context menu forbidden inside DVDBurn to prevent calling multiple instances"
+                               
+               self.session.openWithCallback(self.selectedSource, MovieSelectionNoMenu)
 
        def selectedSource(self, source):
                if source is None:
                        return None
                t = self.project.addService(source)
-               self.updateTitleList()
-               #self.editTitle(t)
+               self.editTitle(t, readOnly=True)
 
        def removeCurrentTitle(self):
                title = self.getCurrentTitle()
@@ -88,92 +206,86 @@ class TitleList(Screen):
                        self.updateTitleList()
 
        def saveProject(self):
-               pass
+               self.project.saveProject("/testProgs/dvd/")
 
        def burnProject(self):
-               print "producing final cue sheet:"
-               cue = self.produceFinalCuesheet()
-               print str(cue)
+               self.project.waitboxref = self.project.session.open(WaitBox,self.burnProjectCB)
+
+       def burnProjectCB(self):
                import Process
-               job = Process.Burn(self.session, cue)
-               print cue
+               job = Process.Burn(self.session, self.project)
                from Screens.TaskView import JobView
                self.session.open(JobView, job)
 
+       def previewMenu(self):
+               self.project.waitboxref = self.project.session.open(WaitBox,self.previewMenuCB)
+               
+       def previewMenuCB(self):
+               import Process
+               job = Process.PreviewMenu(self.session, self.project)
+
        def updateTitleList(self):
                res = [ ]
+               totalsize = 0
                for title in self.project.titles:
-                       a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 10, 400, 50, 0, RT_HALIGN_LEFT, title.name)  ]
+                       a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 10, 500, 50, 0, RT_HALIGN_LEFT, title.name)  ]
                        res.append(a)
-
+                       totalsize += title.estimatedDiskspace
                self["titles"].list = res
+               self.updateSize(totalsize)
+               
+       def updateSize(self, totalsize):
+               size = int((totalsize/1024)/1024)
+               max_SL = 4370
+               max_DL = 7950
+               if size > max_DL:
+                       percent = 100 * size / float(max_DL)
+                       self["space_label"].text = "%d MB - " % size + _("exceeds dual layer medium!") + " (%.2f%% " % (100-percent) + _("free") + ")"
+                       self["space_bar"].value = int(percent)
+               elif size > max_SL:
+                       percent = 100 * size / float(max_DL)
+                       self["space_label"].text = "%d MB  " % size + _("of a DUAL layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
+                       self["space_bar"].value = int(percent)
+               elif size < max_SL:
+                       percent = 100 * size / float(max_SL)
+                       self["space_label"].text = "%d MB " % size + _("of a SINGLE layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
+                       self["space_bar"].value = int(percent)
 
        def getCurrentTitle(self):
                t = self["titles"].getCurrent()
                return t and t[0]
 
-       def editTitle(self, title = None):
+       def editTitle(self, title = None, readOnly = False):
                t = title or self.getCurrentTitle()
                if t is not None:
                        self.current_edit_title = t
-                       self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
+                       if readOnly:
+                               self.session.openWithCallback(self.titleEditDone, TitleCutter.CutlistReader, t)
+                       else:
+                               self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
 
        def titleEditDone(self, cutlist):
                t = self.current_edit_title
-               t.cutlist = cutlist
-               print "title edit of %s done, resulting cutlist:" % (t.source.toString()), t.cutlist
+               t.cuesheet = cutlist
+               t.produceFinalCuesheet()
+               print "title edit of %s done, resulting cutlist:" % (t.source.toString()), t.cutlist, "chaptermarks:", t.chaptermarks
+               self.updateTitleList()
 
        def leave(self):
                self.close()
 
-       def produceFinalCuesheet(self):
-               res = [ ]
-               for title in self.project.titles:
-                       path = title.source.getPath()
-                       print ">>> path:", path
-                       cutlist = title.cutlist
-
-                       # our demuxer expects *stricly* IN,OUT lists.
-                       first = True
-                       currently_in = False
-                       CUT_TYPE_IN = 0
-                       CUT_TYPE_OUT = 1
-                       CUT_TYPE_MARK = 2
-                       CUT_TYPE_LAST = 3
-
-                       accumulated_in = 0
-                       accumulated_at = 0
-                       last_in = 0
-
-                       res_cutlist = [ ]
-
-                       res_chaptermarks = [0]
-
-                       for (pts, type) in cutlist:
-                               if first and type == CUT_TYPE_OUT: # first mark is "out"
-                                       res_cutlist.append(0) # emulate "in" at first
-                                       currently_in = True
-
-                               first = False
-
-                               if type == CUT_TYPE_IN and not currently_in:
-                                       res_cutlist.append(pts)
-                                       last_in = pts
-                                       currently_in = True
-
-                               if type == CUT_TYPE_OUT and currently_in:
-                                       res_cutlist.append(pts)
-
-                                       # accumulate the segment
-                                       accumulated_in += pts - last_in 
-                                       accumulated_at = pts
-                                       currently_in = False
-
-                               if type == CUT_TYPE_MARK and currently_in:
-                                       # relocate chaptermark against "in" time. This is not 100% accurate,
-                                       # as the in/out points are not.
-                                       res_chaptermarks.append(pts - accumulated_at + accumulated_in)
-
-                       res.append( (path, res_cutlist, res_chaptermarks) )
-
-               return res
+       def showFileBrowser(self, projectBrowser=False):
+               if projectBrowser:
+                       currDir = "/home/root"
+               else:
+                       currDir = self.project.menubg
+                       if len(currDir) > 1:
+                               currDir = (currDir.rstrip("/").rsplit("/",1))[0]
+               self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, currDir, projectBrowser)
+       
+       def FileBrowserClosed(self, path, projectBrowser=False):
+               print "FileBrowserClosed", path, projectBrowser
+               if projectBrowser:
+                       print "would load project", path
+               else:
+                       self.project.menubg = path
index 66fe96d55f1c4620f068fa5931a57a578bda54a9..8e0d74333caf3d4d4c6871e8f4599d40a7068555 100644 (file)
@@ -3,9 +3,11 @@ from Plugins.Plugin import PluginDescriptor
 def main(session, service, **kwargs):
        import TitleList
        import DVDProject
-       project = DVDProject.DVDProject()
-       project.addService(service)
-       session.open(TitleList.TitleList, project)
+       #project = DVDProject.DVDProject()
+       #project.addService(service)
+       burner = session.open(TitleList.TitleList)
+       burner.selectedSource(service)
+       
 
 def Plugins(**kwargs):
-       return PluginDescriptor(name="DVD Tool", description=_("Burn To DVD..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
+       return PluginDescriptor(name="DVD Tool", description=_("Burn to DVD..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)