--- mythburn.py	2020-01-17 10:33:59.000000000 +0000
+++ new_johnburn.py	2019-02-18 21:28:10.523894340 +0000
@@ -1,4 +1,4 @@
-#! /usr/bin/python2 -s
+#! /usr/bin/python2
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
@@ -17,6 +17,7 @@
 
 # paulh
 # 4 May 2006 - Added into mythtv svn
+# 17 Feb 2019 - added png-to-jpeg patch, #13306
 
 # For this script to work you need to have...
 # Python - v2.6 or later
@@ -28,12 +29,14 @@
 
 # Optional for shrink-to-fit requantisation
 # M2VRequantiser (from flexion, based on the newer code from Metakine)
+#https://launchpad.net/m2vrequantiser/trunk/1.1/+download/M2VRequantiser-v1.1.tar.gz
 
 # Optional (for Right To Left languages)
 # pyfribidi
 
 # Optional (alternate demuxer)
 # ProjectX - >=0.91
+#http://project-x.cvs.sourceforge.net/viewvc/project-x/Project-X/?view=tar
 
 # Optional (to lower the ionice level)
 # psutil
@@ -45,11 +48,16 @@
 
 # All strings in this file should be unicode, not byte string!! They get converted to utf-8 only
 
-
-
-
 # version of script - change after each update
-VERSION="0.1.20131119-1"
+#VERSION="0.1.20130423-1-jp-0.27.0-for SL6 on presv5000 nonfatal option and RPW_Ticket11758"
+#VERSION="0.1.220150712-jp-with-cutlist-option-restored-for-testing-but-still-doesn't work" 
+#VERSION="0.1.20171128-jp-with-cutlist-option-restored"
+VERSION="0.1.201902117-jp-using-image.convert_Ticket#13306"
+
+# Local setting.  Set location of generated iso image, preferably not on the arctmp spindle.
+# Haven't found a way of passing it in without a program rebuild.  Not stored in the DB.
+# It's redefined later, in this single-drive version.
+isopath="/mnt/f10store/myth/arctmp/isos/mythburn.iso" 
 
 # keep all temporary files for debugging purposes
 # set this to True before a first run through when testing
@@ -74,7 +82,8 @@
 # chapter marks will be set to the cut point end marks
 addCutlistChapters = False
 
-# change this to True to always convert any audio tracks to ac3 for better compatibility
+# by default we always convert any audio tracks to ac3 for better compatibility
+#encodetoac3 = True
 encodetoac3 = False
 
 #*********************************************************************************
@@ -94,6 +103,7 @@
 from PIL import ImageColor
 import unicodedata
 import time
+##import datetime
 import tempfile
 from fcntl import ioctl
 import CDROM
@@ -121,6 +131,7 @@
 
 #Single and dual layer recordable DVD free space in MBytes
 dvdrsize=(4482,8106)
+#dvdrsize=(400,8106)  #for requant tests
 
 frameratePAL=25
 framerateNTSC=29.97
@@ -149,7 +160,7 @@
 thumboffset = 10
 usebookmark = True
 clearArchiveTable = True
-nicelevel = 17;
+nicelevel = 18;
 drivespeed = 0;
 
 #main menu aspect ratio (4:3 or 16:9)
@@ -198,10 +209,10 @@
 MVID = MythTV.MythVideo(db=DB)
 Video = MythTV.Video
 
+# If the frontend has a LocalHostName this must be passed in config.xml
 configHostname = DB.gethostname()
 
 #############################################################
-
 # mytharchivehelper needes this locale to work correctly
 try:
    oldlocale = os.environ["LC_ALL"]
@@ -281,10 +292,14 @@
 
     sys.stdout.write((text + "\n").encode("utf-8", "replace"))
     sys.stdout.flush()
-
+ 
     if progress == True and progresslog != "":
-        progressfile.write(time.strftime("%Y-%m-%d %H:%M:%S ") + text + "\n")
-        progressfile.flush()
+      if len(text)<30 :
+         progressfile.write(time.strftime("%H:%M:%S  %Y-%m-%d ") + text + "\n")
+      else:
+         progressfile.write(time.strftime("%H:%M:%S ") + text + "\n")
+
+      progressfile.flush()
 
 #############################################################
 # Display an error message and exit
@@ -471,6 +486,7 @@
 def runCommand(command):
     checkCancelFlag()
 
+
     result = os.system(command.encode('utf-8'))
 
     if os.WIFEXITED(result):
@@ -478,6 +494,13 @@
     checkCancelFlag()
     return result
 
+#########################################################
+# Truncate to even value ( to silence 'odd y-coordinate' complaints)
+
+def even(num):
+    evennum = 2 * int(num / 2) 
+    return evennum
+
 #############################################################
 # Convert a time in seconds to a frame number
 
@@ -490,6 +513,15 @@
 
     frames=int(seconds * framespersecond)
     return frames
+#############################################################
+# Convert HH:MM:SS to seconds
+# http://stackoverflow.com/questions/6402812/how-to-convert-an-hmmss-time-string-to-seconds-in-python
+
+def to_seconds(timestr):
+    seconds = 0
+    for part in timestr.split(':') :
+       seconds = seconds * 60 + int(part)
+    return seconds
 
 #############################################################
 # Creates a short mpeg file from a jpeg image and an ac3 sound track
@@ -511,7 +543,7 @@
     command = quoteCmdArg(path_mplex[0]) + " -f 8 -v 0 -o %s %s %s" % (quoteCmdArg(tempmovie), quoteCmdArg(tempvideo), quoteCmdArg(music))
     result = runCommand(command)
     if result<>0:
-        fatalError("Failed while running mplex - %s" % command)
+       nonfatalError("Failed while running mplex - %s" % command)
 
     if xmlfile != "":
         command = quoteCmdArg(path_spumux[0]) + " -m dvd -s 0 %s < %s > %s" % (quoteCmdArg(xmlfile), quoteCmdArg(tempmovie), quoteCmdArg(finaloutput))
@@ -630,7 +662,7 @@
 # of a video file from its stream info file
 
 def getVideoParams(folder):
-    """Returns the video resolution, fps and aspect ratio for the video file from the streaminfo.xml file"""
+    """Returns the video resolution, fps and aspect ratio for the video file from the streamindo.xml file"""
 
     #open the XML containing information about this file
     infoDOM = xml.dom.minidom.parse(os.path.join(folder, 'streaminfo.xml'))
@@ -737,20 +769,6 @@
     return '%02d:%02d:%02d' % (hour, mins, sec)
 
 #############################################################
-# Convert a time string of format 00:00:00 to number of seconds
-
-def timeStringToSeconds(formatedtime):
-    parts = string.split(formatedtime, ':')
-    if len(parts) != 3:
-        return 0
-
-    sec = int(parts[2])
-    mins = int(parts[1])
-    hour = int(parts[0])
-
-    return sec + (mins * 60) + (hour * 60 * 60)
-
-#############################################################
 # Creates a set of chapter points evenly spread thoughout a file
 # Optionally grabs the thumbnails from the file
 
@@ -880,6 +898,7 @@
     # create a cursor
     cursor = DB.cursor()
     # execute SQL statement
+    # see http://www.gossamer-threads.com/lists/mythtv/users/586809#586809
     cursor.execute(sqlstatement, (configHostname,))
     # get the resultset as a tuple
     result = cursor.fetchall()
@@ -898,6 +917,7 @@
 
 def saveSetting(name, data):
     host = DB.gethostname()
+    write("Saving settings: host %s, name %s, data %s " % (host, name, data))
     DB.settings[host][name] = data
 
 #############################################################
@@ -1394,10 +1414,11 @@
                 fatalError("Failed to get recording details from the DB for %s" % filename)
 
             data.chanid = rec.chanid
-            data.recordingtime = rec.starttime.isoformat()
-            data.recordingdate = rec.starttime.isoformat()
-
-            cutlist = rec.markup.getcutlist()
+            data.recordingtime = rec.starttime.utcisoformat()
+            data.recordingdate = rec.starttime.utcisoformat()
+# The cutlist code broke things in late 2014; this worked if cutting was not required.  
+# It exists in 4 places here
+            cutlist = rec.markup.getcutlist()   # = []
             if len(cutlist):
                 data.hascutlist = 'yes'
                 if file.attributes["usecutlist"].value == "0" and addCutlistChapters == True:
@@ -1428,7 +1449,7 @@
         data.chanid         = rec.chanid
         data.starttime      = rec.starttime.utcisoformat()
 
-        cutlist = rec.markup.getcutlist()
+        cutlist = rec.markup.getcutlist()  # = []
         if len(cutlist):
             data.hascutlist = 'yes'
             if file.attributes["usecutlist"].value == "0" and addCutlistChapters == True:
@@ -1509,12 +1530,14 @@
 def WriteXMLToFile(myDOM, filename):
     #Save the XML file to disk for use later on
     f=open(filename, 'w')
+    
+    # f.write(myDOM.toprettyxml(indent="    ", encoding="UTF-8")) # gives problems with python < ~2.7.3
 
     if sys.hexversion >= 0x020703F0:
         f.write(myDOM.toprettyxml(indent="    ", encoding="UTF-8"))
     else:
         f.write(myDOM.toxml(encoding="UTF-8"))
-
+    
     f.close()
 
 
@@ -1547,6 +1570,7 @@
     if doesFileExist(mediafile) == False:
         fatalError("Source file does not exist: " + mediafile)
 
+
     getStreamInformation(mediafile, os.path.join(folder, "streaminfo.xml"), 0)
     copy(os.path.join(folder, "streaminfo.xml"), os.path.join(folder, "streaminfo_orig.xml"))
 
@@ -1630,7 +1654,7 @@
     checkCancelFlag()
 
     if not doesFileExist(audio2):
-        write("Available streams - video and one audio stream")
+        write("Using video and one audio streams: %s  %s "  %  (video, audio1 ))
         result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
                     '-M',
                     '-f', '8',
@@ -1656,7 +1680,7 @@
         return result
     else:
         if result != 0:
-            fatalError("mplex failed with result %d" % result)
+            nonfatalError("mplex failed with result %d" % result)
 
     # run spumux to add subtitles if they exist
     if os.path.exists(os.path.dirname(destination) + "/stream.d/spumux.xml"):
@@ -1692,7 +1716,7 @@
     result = runCommand(command)
 
     if result <> 0:
-        fatalError("Failed while running mytharchivehelper to get stream information.\n"
+        nonfatalError("Failed while running mytharchivehelper to get stream information.\n"
                    "Result: %d, Command was %s" % (result, command))
 
     # print out the streaminfo.xml file to the log
@@ -1731,9 +1755,11 @@
 
     try:
         rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
-        cutlist = rec.markup.getcutlist()
+        starttime = rec.starttime.utcisoformat()
+        cutlist = rec.markup.getcutlist()  # = []
     except StopIteration:
         cutlist = []
+ 
 
     cutlist_s = ""
     if usecutlist and len(cutlist):
@@ -1744,6 +1770,7 @@
         write("Using cutlist: %s" % cutlist_s)
 
     if (localfile != ""):
+#        localfile = quoteFilename(localfile)  # out Apr2013
         if usecutlist == True:
             command = "mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s, quoteCmdArg(localfile), quoteCmdArg(destination))
         else:
@@ -1771,8 +1798,7 @@
     """generate cutlist_x.txt for ProjectX"""
 
     rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
-    starttime = rec.starttime.utcisoformat()
-    cutlist = rec.markup.getcutlist()
+    cutlist = rec.markup.getcutlist()   # = []
 
     if len(cutlist):
         with codecs.open(os.path.join(folder, "cutlist_x.txt"), 'w', 'utf-8') as cutlist_f:
@@ -1814,7 +1840,8 @@
         write("Error: input file doesn't exist on local filesystem")
         return False
 
-    command = quoteCmdArg(path_projectx[0]) + " %s -id '%s' -set ExternPanel.appendPidToFileName=1 -out %s -name stream" % (quoteCmdArg(file), getStreamList(folder), quoteCmdArg(folder))
+    command = "ionice -c3 java -jar "
+    command += quoteCmdArg(path_projectx[0]) + " %s -id '%s' -set ExternPanel.appendPidToFileName=1 -out %s -name stream" % (quoteCmdArg(file), getStreamList(folder), quoteCmdArg(folder))
     if usecutlist == True:
         command += " -cut %s" % quoteCmdArg(os.path.join(folder, "cutlist_x.txt"))
     write(command)
@@ -1980,7 +2007,7 @@
         command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (quoteCmdArg(source), seconds, quoteCmdArg(destination))
         result = runCommand(command)
         if result <> 0:
-            fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
+            nonfatalError("Failed while running mytharchivehelper to get thumbnails.\n"
                        "Result: %d, Command was %s" % (result, command))
     try:
         myimage=Image.open(destination,"r")
@@ -2004,7 +2031,7 @@
     write(command)
     result = runCommand(command)
     if result <> 0:
-        fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
+      nonfatalError("Failed while running mytharchivehelper to get thumbnails.\n"
                    "Result: %d, Command was %s" % (result, command))
 
 #############################################################
@@ -2068,6 +2095,7 @@
             if name == "-acodec" or name == "-ar" or name == "-b:a" or name == "-ac":
                     command += " " + name + " " + value
 
+
     #make sure we get the correct stream(s) that we want
     command += " -map 0:%d -map 0:%d " % (video[VIDEO_INDEX], audio1[AUDIO_INDEX])
     if audio2[AUDIO_ID] != -1:
@@ -2129,7 +2157,10 @@
     outaudiosamplerate = 48000
     outaudiocodec = "ac3"
     deinterlace = 0
-    filter = ""
+    croptop = 0
+    cropright = 0
+    cropbottom = 0
+    cropleft = 0
     qmin = 5
     qmax = 31
     qdiff = 31
@@ -2153,8 +2184,14 @@
             outvideores = value
         if name == "-deinterlace":
             deinterlace = 1
-        if name == "-filter:v":
-            filter = " -filter:v " + quoteCmdArg(value) + " "
+        if name == "-croptop":
+            croptop = value
+        if name == "-cropright":
+            cropright = value
+        if name == "-cropbottom":
+            cropbottom = value
+        if name == "-cropleft":
+           cropleft = value
         if name == "-qmin":
            qmin = value
         if name == "-qmax":
@@ -2204,7 +2241,7 @@
     command += "-aspect %s -r %s " % (aspectratio, fps)
     if (deinterlace == 1):
         command += "-deinterlace "
-    command += "%s" % filter
+    command += "-croptop %s -cropright %s -cropbottom %s -cropleft %s " % (croptop, cropright, cropbottom, cropleft)
     command += "-s %s -b %s -vcodec mpeg2video " % (outvideores, outvideobitrate)
     command += "-qmin %s -qmax %s -qdiff %s " % (qmin, qmax, qdiff)
     command += "-ab %s -ar %s -acodec %s " % (outaudiobitrate, outaudiosamplerate, outaudiocodec)
@@ -2234,9 +2271,19 @@
 def runDVDAuthor():
     write( "Starting dvdauthor")
     checkCancelFlag()
-    result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],'-x',os.path.join(getTempPath(),'dvdauthor.xml'))
+    tpath = os.path.join(getTempPath()) + "/dvdauthor.xml"
+    command = "ionice -c3 "
+    command += path_dvdauthor[0] + ' -x ' + os.path.join(getTempPath(),'dvdauthor.xml')
+#    command += ("os.spawnlp(os.P_WAIT, %s %s -x %s )" % (path_dvdauthor[0], path_dvdauthor[1], tpath))
+    write(command)
+#    result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],'-x', tpath)
+    result = runCommand(command)
+
+#    write("os.spawnlp(os.P_WAIT, %s %s -x %s )" % (path_dvdauthor[0], path_dvdauthor[1], tpath))
+#    result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],'-x', tpath)
+
     if result<>0:
-        fatalError("Failed while running dvdauthor. Result: %d" % result)
+        nonfatalError("Failed while running dvdauthor. Result: %d" % result)
     write( "Finished  dvdauthor")
 
 #############################################################
@@ -2245,23 +2292,36 @@
 def CreateDVDISO(title):
     write("Creating ISO image")
     checkCancelFlag()
-    command = quoteCmdArg(path_mkisofs[0]) + ' -dvd-video '
+    # This is the 'standard' definition of isopath for presv5000. 
+    # The gbox version defines it earlier, on another spindle.
+    isopath = os.path.join(getTempPath(), 'mythburn.iso')
+    command = "ionice -c3 "
+    command += quoteCmdArg(path_mkisofs[0]) + ' -dvd-video '
     command += ' -V ' + quoteCmdArg(title)
-    command += ' -o ' + quoteCmdArg(os.path.join(getTempPath(), 'mythburn.iso'))
+    command += ' -o ' + quoteCmdArg(isopath)
     command += " " + quoteCmdArg(os.path.join(getTempPath(),'dvd'))
-
+  
+    write("Command is %s " % command)
     result = runCommand(command)
+    if result<>0:
+        fatalError("Failed in: %s" % command)
+    vobsize1= os.path.getsize(isopath)/(1024.0*1024.0)
 
+    # Implant a checksum in the file
+    command = " ionice -c3 implantisomd5 " + quoteCmdArg(isopath)
+    write("Command is %s " % command)
+    result = runCommand(command)
     if result<>0:
-        fatalError("Failed while running mkisofs.\n"
-                   "Command was %s" % command)
+        fatalError("Failed in: %s" % command)
+
+    vobsize2= os.path.getsize(isopath)/(1024.0*1024.0)
+    write("%s created, %.2f Mb raw, %.2f Mb with checksum. " % (isopath, float(vobsize1), float(vobsize2)))
+    write("DVD capacities are %s, %s Mb " % ( dvdrsize[0], dvdrsize[1]) )
 
-    write("Finished creating ISO image")
 
 #############################################################
 # Burns the contents of a directory to create a DVD 
 
-
 def BurnDVDISO(title):
     write( "Burning ISO image to %s" % dvddrivepath)
 
@@ -2279,8 +2339,10 @@
           write("Please insert an empty double-layer disc (DVD+R DL or DVD-R DL).")
         if mediatype == DVD_RW:
           write("Please insert a rewritable disc (DVD+RW or DVD-RW).")
+
     def drive(action, value=0):
         waitForDrive()
+
         # workaround as some distros have problems to eject the DVD
         # 'sudo sysctl -w dev.cdrom.autoclose=0' should help, but we don't have the privliges to do this
         if action == CDROM.CDROMEJECT:
@@ -2319,7 +2381,7 @@
     def waitForDrive():
         tries = 0
         while drivestatus() == CDROM.CDS_DRIVE_NOT_READY:
-            checkCancelFlag()
+	    checkCancelFlag()
             write("Waiting for drive")
             time.sleep(5)
             runCommand("pumount " + quoteCmdArg(dvddrivepath))
@@ -2331,7 +2393,6 @@
                 tries = 0
 
 
-
     ####################
     # start working here
 
@@ -2350,7 +2411,6 @@
             # growisofs will fail to burn it, so try to pumount it first...
             runCommand("pumount " + quoteCmdArg(dvddrivepath));
 
-
             command = quoteCmdArg(path_growisofs[0]) + " -input-charset=UTF-8 -dvd-compat"
             if drivespeed != 0:
                 command += " -speed=%d" % drivespeed
@@ -2363,7 +2423,7 @@
             result = runCommand(command)
             if result == 0:
                 finished = True
-                
+
                 # Wait till the drive is not busy any longer
                 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
                 busy = True
@@ -2378,6 +2438,7 @@
                     time.sleep(5)
                     waitForDrive()
                 os.close(f)
+
             else:
                 if result == 252:
                     write("-"*60)
@@ -2745,6 +2806,7 @@
 
         #Pick the correct intro movie based on video format ntsc/pal
         vob = dvddom.createElement("vob")
+        vob.setAttribute("pause","")
         vob.setAttribute("file",os.path.join(getThemeFile(themeName, videomode + '_' + introFile)))
         pgc.appendChild(vob)
         del vob
@@ -2755,12 +2817,12 @@
         post .appendChild(dvddom.createTextNode("{g3=1;g2=1;jump menu 2;}"))
         pgc.appendChild(post)
         del post
-    else:
-        # If there's no intro, we need to jump to the next menu
-        post = dvddom.createElement("post")
-        post .appendChild(dvddom.createTextNode("{g3=1;g2=1;jump menu 2;}"))
-        pgc.appendChild(post)
-        del post
+    else: 
+	# If there's no intro, we need to jump to the next menu # See Ticket #11942
+        post = dvddom.createElement("post") 
+        post .appendChild(dvddom.createTextNode("{g3=1;g2=1;jump menu 2;}")) 
+        pgc.appendChild(post) 
+        del post 
 
     while itemnum <= numberofitems:
         write( "Menu page %s" % page)
@@ -2768,6 +2830,7 @@
         #For each menu page we need to create a new PGC structure
         menupgc = dvddom.createElement("pgc")
         menus_element.appendChild(menupgc)
+        menupgc.setAttribute("pause","inf")
 
         menupgc.appendChild( dvddom.createComment("Menu Page %s" % page) )
 
@@ -2779,7 +2842,7 @@
 
         vob = dvddom.createElement("vob")
         vob.setAttribute("file",os.path.join(getTempPath(),"menu-%s.mpg" % page))
-        menupgc.appendChild(vob)
+        menupgc.appendChild(vob)    
 
         #Loop menu forever
         post = dvddom.createElement("post")
@@ -2846,6 +2909,7 @@
             if wantChapterMenu:
                 mymenupgc = dvddom.createElement("pgc")
                 menus.appendChild(mymenupgc)
+                mymenupgc.setAttribute("pause","inf")
 
                 pre = dvddom.createElement("pre")
                 mymenupgc.appendChild(pre)
@@ -2867,14 +2931,16 @@
                 # throws of the chapter selection - so make sure we add it if needed so we
                 # can compensate for it in the chapter selection menu 
                 firstChapter = 0
-                thumblist = createVideoChapters(itemnum, chapters, getLengthOfVideo(itemnum), False)
-                chapterlist = string.split(thumblist, ",")
-                if chapterlist[0] != '00:00:00':
-                    firstChapter = 1
-                x = 1
-                while x <= chapters:
+                thumbNode = infoDOM.getElementsByTagName("thumblist")
+                if thumbNode.length > 0:
+                    thumblist = getText(thumbNode[0])
+                    chapterlist = string.split(thumblist, ",")
+                    if chapterlist[0] != '00:00:00':
+                        firstChapter = 1
+                x=1
+                while x<=chapters:
                     #Add this recording to this page's menu...
-                    button = dvddom.createElement("button")
+                    button=dvddom.createElement("button")
                     button.setAttribute("name","%s" % x)
                     if wantDetailsPage: 
                         button.appendChild(dvddom.createTextNode("jump title %s chapter %s;" % (1, firstChapter + x + 1)))
@@ -2883,7 +2949,7 @@
 
                     mymenupgc.appendChild(button)
                     del button
-                    x += 1
+                    x+=1
 
                 #add the titlemenu button if required
                 submenunode = themeDOM.getElementsByTagName("submenu")
@@ -2923,6 +2989,7 @@
 
             pgc = dvddom.createElement("pgc")
             titles.appendChild(pgc)
+            #pgc.setAttribute("pause","inf")
 
             if wantDetailsPage:
                 #add the detail page intro for this item
@@ -2932,11 +2999,11 @@
 
             vob = dvddom.createElement("vob")
             if wantChapterMenu:
-                thumblist = createVideoChapters(itemnum, chapters, getLengthOfVideo(itemnum), False)
-                chapterlist = string.split(thumblist, ",")
-                if chapterlist[0] != '00:00:00':
-                    thumblist = '00:00:00,' + thumblist
-                vob.setAttribute("chapters", thumblist)
+                vob.setAttribute("chapters",
+                    createVideoChapters(itemnum,
+                                        chapters,
+                                        getLengthOfVideo(itemnum),
+                                        False))
             else:
                 vob.setAttribute("chapters", 
                     createVideoChaptersFixedLength(itemnum,
@@ -3118,6 +3185,7 @@
 
     # create menu 2 - dummy menu that allows us to jump to each titleset in sequence
     menu_pgc = dvddom.createElement("pgc")
+    menu_pgc.setAttribute("pause", "0")
 
     preText = "if (g1==0) g1=1;"
     for i in range(numberofitems):
@@ -3144,6 +3212,7 @@
         menu = dvddom.createElement("menus")
         menupgc = dvddom.createElement("pgc")
         menu.appendChild(menupgc)
+        menupgc.setAttribute("pause","0")
         titleset.appendChild(menu)
 
         if wantDetailsPage:
@@ -3254,6 +3323,7 @@
                 frames = int(secondsToFrames(menulength))
 
                 command = "mytharchivehelper -q -q --createthumbnail --infile  %s --thumblist '%s' --outfile %s --framecount %d" % (quoteCmdArg(inputfile), starttime, quoteCmdArg(outputfile), frames)
+                write(command)
                 result = runCommand(command)
                 if (result != 0):
                     write( "mytharchivehelper failed with code %d. Command = %s" % (result, command) )
@@ -3365,11 +3435,11 @@
                 button = spumuxdom.createElement("button")
                 button.setAttribute("name","previous")
                 button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
-                button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
+                button.setAttribute("y0","%s" % even(getScaledAttribute(node, "y")))
                 button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
                                                 getScaledAttribute(node, "w")))
-                button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
-                                                getScaledAttribute(node, "h")))
+                button.setAttribute("y1","%s" % even((getScaledAttribute(node, "y") +
+                                                getScaledAttribute(node, "h"))))
                 spunode.appendChild(button)
 
                 write( "Added previous page button")
@@ -3389,11 +3459,11 @@
                 button = spumuxdom.createElement("button")
                 button.setAttribute("name","next")
                 button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
-                button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
+                button.setAttribute("y0","%s" % even(getScaledAttribute(node, "y")))
                 button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
                                                  getScaledAttribute(node, "w")))
-                button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") + 
-                                                 getScaledAttribute(node, "h")))
+                button.setAttribute("y1","%s" % even((getScaledAttribute(node, "y") + 
+                                                 getScaledAttribute(node, "h"))))
                 spunode.appendChild(button)
 
                 write("Added next page button")
@@ -3410,11 +3480,11 @@
             button = spumuxdom.createElement("button")
             button.setAttribute("name","playall")
             button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
-            button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
+            button.setAttribute("y0","%s" % even(getScaledAttribute(node, "y")))
             button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
                                              getScaledAttribute(node, "w")))
-            button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
-                                             getScaledAttribute(node, "h")))
+            button.setAttribute("y1","%s" % even((getScaledAttribute(node, "y") +
+                                             getScaledAttribute(node, "h"))))
             spunode.appendChild(button)
 
             write("Added playall button")
@@ -3433,11 +3503,11 @@
                 button = spumuxdom.createElement("button")
                 button.setAttribute("name","titlemenu")
                 button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
-                button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
+                button.setAttribute("y0","%s" % even(getScaledAttribute(node, "y")))
                 button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") +
                                                 getScaledAttribute(node, "w")))
-                button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
-                                                getScaledAttribute(node, "h")))
+                button.setAttribute("y1","%s" % even((getScaledAttribute(node, "y") +
+                                                getScaledAttribute(node, "h"))))
                 spunode.appendChild(button)
 
                 write( "Added titlemenu button")
@@ -3468,11 +3538,12 @@
     #Draw the selection mask for this item
     if wantHighlightBox == True:
         # Make the boundary box bigger than the content to avoid over writing it
-        boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
+        # reduce [2] because increasing it causes warnings during menu display - jp
+        boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]-1,boundarybox[3]+1
         drawmask.rectangle(boundarybox,outline=highlightcolor)
 
         # Draw another line to make the box thicker - PIL does not support linewidth
-        boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
+        boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]-1,boundarybox[3]+1
         drawmask.rectangle(boundarybox,outline=highlightcolor)
 
     node = spumuxdom.createElement("button")
@@ -3482,9 +3553,9 @@
     else:
         node.setAttribute("name","%s" % itemnum)
     node.setAttribute("x0","%d" % int(boundarybox[0]))
-    node.setAttribute("y0","%d" % int(boundarybox[1]))
+    node.setAttribute("y0","%d" % even(int(boundarybox[1])))
     node.setAttribute("x1","%d" % int(boundarybox[2] + 1))
-    node.setAttribute("y1","%d" % int(boundarybox[3] + 1))
+    node.setAttribute("y1","%d" % even(int(boundarybox[3] + 1)))
     spunode.appendChild(node)
 
 #############################################################
@@ -3520,9 +3591,10 @@
         highlightcolor = menunode.attributes["highlightcolor"].value
 
     #Get menu music
-    menumusic = "menumusic.ac3"
-    if menunode.hasAttribute("music"):
-        menumusic = menunode.attributes["music"].value
+    menumusic = "menumusic.mp2"
+#    menumusic = "menumusic.ac3"
+#    if menunode.hasAttribute("music"):
+#        menumusic = menunode.attributes["music"].value
 
     #Get menu length
     menulength = 15
@@ -3616,7 +3688,9 @@
         bgimage.paste(overlayimage, (0,0), overlayimage)
 
         #Save this menu image and its mask
-        bgimage.save(os.path.join(getTempPath(),"background-%s.jpg" % page),"JPEG", quality=99)
+        rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python
+        rgb_bgimage.save(os.path.join(getTempPath(),"background-%s.jpg" % page),"JPEG", quality=99)
+        del rgb_bgimage
         bgimagemask.save(os.path.join(getTempPath(),"backgroundmask-%s.png" % page),"PNG",quality=99,optimize=0,dpi=screendpi)
 
         #now that the base background has been made and all the previews generated
@@ -3654,7 +3728,9 @@
                             del picture
                     previewitem+=1
                 #bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.png" % (page, framenum)),"PNG",quality=100,optimize=0,dpi=screendpi)
-                bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
+                rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python
+                rgb_bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
+                del rgb_bgimage
                 framenum+=1
 
         spumuxdom.documentElement.firstChild.firstChild.setAttribute("select",os.path.join(getTempPath(),"backgroundmask-%s.png" % page))
@@ -3732,9 +3808,10 @@
         highlightcolor = menunode.attributes["highlightcolor"].value
 
     #Get menu music
-    menumusic = "menumusic.ac3"
-    if menunode.hasAttribute("music"):
-        menumusic = menunode.attributes["music"].value
+    menumusic = "menumusic.mp2"
+#    menumusic = "menumusic.ac3"
+#    if menunode.hasAttribute("music"):
+#        menumusic = menunode.attributes["music"].value
 
     #Get menu length
     menulength = 15
@@ -3770,6 +3847,7 @@
         #Extract the thumbnails
         chapterlist=createVideoChapters(page,itemsperpage,getLengthOfVideo(page),True)
         chapterlist=string.split(chapterlist,",")
+        write("chapterlist: %s " % chapterlist)
 
         #now need to preprocess the menu to see if any preview videos are required
         #This must be done on an individual basis since we do the resize as the
@@ -3780,7 +3858,7 @@
 
         haspreview = False
 
-        previewtime = 0
+#        previewsegment=int(getLengthOfVideo(page) / itemsperpage)
         previewchapter = 0
         previewx = []
         previewy = []
@@ -3789,11 +3867,10 @@
         previewmask = []
 
         while previewchapter < itemsperpage:
-            menuitem=menuitems[ previewchapter ]
-
-            previewtime = timeStringToSeconds(chapterlist[previewchapter])
+            menuitem = menuitems[ previewchapter ]
 
             #generate the preview if required (px=9999 means not required)
+            previewtime = to_seconds(chapterlist[ previewchapter ])
             px, py, pw, ph, maskimage = generateVideoPreview(page, previewchapter, menuitem, previewtime, menulength, previewfolder)
             previewx.append(px)
             previewy.append(py)
@@ -3821,7 +3898,9 @@
         #Save this menu image and its mask
         bgimage=Image.open(backgroundfilename,"r").resize(screensize)
         bgimage.paste(overlayimage, (0,0), overlayimage)
-        bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s.jpg" % page),"JPEG", quality=99)
+        rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python
+        rgb_bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s.jpg" % page),"JPEG", quality=99)
+        del rgb_bgimage
 
         bgimagemask.save(os.path.join(getTempPath(),"chaptermenumask-%s.png" % page),"PNG",quality=90,optimize=0)
 
@@ -3850,7 +3929,9 @@
                                 bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]))
                             del picture
                     previewchapter+=1
-                bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
+                rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python
+                rgb_bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
+                del rgb_bgimage
                 framenum+=1
 
         spumuxdom.documentElement.firstChild.firstChild.setAttribute("select",os.path.join(getTempPath(),"chaptermenumask-%s.png" % page))
@@ -3927,9 +4008,10 @@
         fatalError("Background image not found (%s)" % backgroundfilename)
 
     #Get menu music
-    menumusic = "menumusic.ac3"
-    if detailnode.hasAttribute("music"):
-        menumusic = detailnode.attributes["music"].value
+    menumusic= "menumusic.mp2"
+#    menumusic = "menumusic.ac3"
+#    if detailnode.hasAttribute("music"):
+#        menumusic = detailnode.attributes["music"].value
 
     #Get menu length
     menulength = 15
@@ -3971,7 +4053,9 @@
         #Save this details image
         bgimage=Image.open(backgroundfilename,"r").resize(screensize)
         bgimage.paste(overlayimage, (0,0), overlayimage)
-        bgimage.save(os.path.join(getTempPath(),"details-%s.jpg" % itemnum),"JPEG", quality=99)
+        rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python
+        rgb_bgimage.save(os.path.join(getTempPath(),"details-%s.jpg" % itemnum),"JPEG", quality=99)
+        del rgb_bgimage
 
         if haspreview == True:
             numframes=secondsToFrames(menulength)
@@ -3994,7 +4078,9 @@
                         else:
                             bgimage.paste(picture, (previewx, previewy))
                         del picture
-                bgimage.save(os.path.join(getTempPath(),"details-%s-f%06d.jpg" % (itemnum, framenum)),"JPEG",quality=99)
+                rgb_bgimage=bgimage.convert('RGB')  # https://stackoverflow.com/questions/43258461/convert-png-to-jpeg-using-pillow-in-python    
+                rgb_bgimage.save(os.path.join(getTempPath(),"details-%s-f%06d.jpg" % (itemnum, framenum)),"JPEG",quality=99)
+                del rgb_bgimage
                 framenum+=1
 
 
@@ -4413,8 +4499,10 @@
 
 def isFileOkayForDVD(file, folder):
     """return true if the file is dvd compliant"""
-
-    if not string.lower(getVideoCodec(folder)).startswith("mpeg2video"):
+    VidCodec = string.lower(getVideoCodec(folder))
+    if VidCodec != "mpeg2video (main)":
+#    if not VidCodec.startswith("mpeg2video") :
+        write("VideoCodec is %s" % VidCodec)
         return False
 
 #    if string.lower(getAudioCodec(folder)) != "ac3" and encodeToAC3:
@@ -4494,7 +4582,7 @@
         #can only use mythtranscode to cut commercials on mpeg2 files
         write("File type is '%s'" % getFileType(folder))
         write("Video codec is '%s'" % getVideoCodec(folder))
-        if string.lower(getVideoCodec(folder)).startswith("mpeg2video"):
+        if string.lower(getVideoCodec(folder)).startswith("mpeg2video"): 
             if file.attributes["usecutlist"].value == "1" and getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes":
                 # Run from local file?
                 if file.hasAttribute("localfilename"):
@@ -4531,7 +4619,7 @@
         write("File type is '%s'" % getFileType(folder))
         write("Video codec is '%s'" % getVideoCodec(folder))
 
-        if (alwaysRunMythtranscode == True and
+        if (alwaysRunMythtranscode == True and 
                 string.lower(getVideoCodec(folder)).startswith("mpeg2video") and
                 isFileOkayForDVD(file, folder)):
             if file.hasAttribute("localfilename"):
@@ -4847,7 +4935,7 @@
         #If User wants to, copy remote files to a tmp dir
         if res == 2 and copyremoteFiles==True:
             # file is on a remote filesystem so copy it to a local file
-            write("Copying file from " + tmpfile)
+            write("Copying file from remote filesystem " + tmpfile)
             write("to " + os.path.join(localTmpPath, filename))
 
             # Copy file
@@ -4858,7 +4946,7 @@
             node.setAttribute("localfilename", os.path.join(localTmpPath, filename))
         elif res == 3:
             # file is on a remote myth backend so copy it to a local file
-            write("Copying file from " + tmpfile)
+            write("Copying file from remote mythbackend " + tmpfile)
             localfile = os.path.join(localTmpPath, filename)
             write("to " + localfile)
 
@@ -4931,6 +5019,8 @@
             if debug_secondrunthrough==False:
                 #Delete all the temporary files that currently exist
                 deleteEverythingInFolder(getTempPath())
+
+
                 localCopyFolder=os.path.join(getTempPath(),"localcopy")
                 os.makedirs(localCopyFolder)
             files=copyRemote(files,getTempPath())
@@ -5030,6 +5120,7 @@
             if infoDOM.documentElement.tagName != "fileinfo":
                 fatalError("The info.xml file (%s) doesn't look right" % os.path.join(folder,"info.xml"))
             title = expandItemText(infoDOM,"%title",1,0,0,0,0)
+
             # replace all non-ascii-characters
             title = title.encode('ascii', 'replace').decode('ascii', 'replace')
             title = title.strip()
@@ -5043,9 +5134,7 @@
                 else:
                     title_new += '_'
                 index = index + 1
-
             title = title_new.upper()
-
             if len(title) < 1:
                 title = 'UNNAMED'
 
@@ -5171,6 +5260,7 @@
     logpath = os.path.join(defaultsettings["MythArchiveTempDir"], "logs")
     write("temppath: " + temppath)
     write("logpath:  " + logpath)
+#    sys.exit(1)    # to check these paths after the LocalHostName problem
     dvddrivepath = defaultsettings["MythArchiveDVDLocation"]
     dbVersion = defaultsettings["DBSchemaVer"]
     preferredlang1 = defaultsettings["ISO639Language0"]
@@ -5210,7 +5300,7 @@
     elif nicelevel == '2':
         nicelevel = 0
     else:
-        nicelevel = 17
+        nicelevel = 18
 
     nicelevel = os.nice(nicelevel)
     write( "Setting process priority to %s" % nicelevel)
@@ -5222,7 +5312,7 @@
     else:
         write( "Setting ionice level to idle")
         p = psutil.Process(os.getpid())
-        p.set_ionice(psutil.IOPRIO_CLASS_IDLE)
+        p.ionice(psutil.IOPRIO_CLASS_IDLE)
 
     import errno
 
@@ -5277,12 +5367,21 @@
             saveSetting("MythArchiveLastRunStatus", "Success")
             saveSetting("MythArchiveLastRunEnd", time.strftime("%Y-%m-%d %H:%M:%S "))
             write("Finished processing jobs!!!")
+            # Show bigger end marker.  Display and editor font widths differ.
+            write(" ")
+            write("    OO      K        K")
+            write("  O     O   K    K")
+            write("  O     O   K K")
+            write("  O     O   K    K")
+            write("    OO      K        K")
+            write(" ")
         finally:
             # remove our lock file
             os.remove(lckpath)
 
             # make sure the files we created are read/writable by all 
-            os.system("chmod -R a+rw-x+X %s" % defaultsettings["MythArchiveTempDir"])
+            # commented out here because it's unsafe if directory isn't correct
+#            os.system("chmod -R a+rw-x+X %s" % defaultsettings["MythArchiveTempDir"])
     except SystemExit:
         write("Terminated")
     except:
@@ -5298,3 +5397,7 @@
     main()
 
 os.putenv("LC_ALL", oldlocale)
+
+
+
+
