Ticket #13562: mytharchive_python3_compatibility-V3.patch

File mytharchive_python3_compatibility-V3.patch, 64.5 KB (added by rcrdnalor, 7 years ago)

Version 3 of a patch using the configured python version and updates compatibility of mythburn.py to python2 and python3 as well, needs #13565 and implements #13306.

  • mythplugins/mytharchive/mytharchive/mythburn.cpp

    diff --git a/mythplugins/mytharchive/mytharchive/mythburn.cpp b/mythplugins/mytharchive/mytharchive/mythburn.cpp
    index 5ef8122904..fadbb2db94 100644
    a b  
    2929#include <mythsystemlegacy.h>
    3030#include <mythmiscutil.h>
    3131#include <exitcodes.h>
     32#include <mythconfig.h>
    3233
    3334// mytharchive
    3435#include "archiveutil.h"
    void MythBurn::runScript()  
    909910        QFile::remove(logDir + "/mythburncancel.lck");
    910911
    911912    createConfigFile(configDir + "/mydata.xml");
    912     commandline = "python " + GetShareDir() + "mytharchive/scripts/mythburn.py";
     913    commandline = PYTHON_EXE;
     914    commandline += " " + GetShareDir() + "mytharchive/scripts/mythburn.py";
    913915    commandline += " -j " + configDir + "/mydata.xml";          // job file
    914916    commandline += " -l " + logDir + "/progress.log";           // progress log
    915917    commandline += " > "  + logDir + "/mythburn.log 2>&1 &";    // Logs
  • mythplugins/mytharchive/mythburn/scripts/mythburn.py

    diff --git a/mythplugins/mytharchive/mythburn/scripts/mythburn.py b/mythplugins/mytharchive/mythburn/scripts/mythburn.py
    index 4f5a96d7ab..90a12d0b41 100755
    a b  
    22# -*- coding: utf-8 -*-
    33from __future__ import unicode_literals
    44
     5# python 3 doesn't have a unicode type
     6try:
     7    unicode
     8except:
     9    unicode = str
     10
     11# python 3 doesn't have a long type
     12try:
     13    long
     14except:
     15    long = int
     16
     17
    518# mythburn.py
    619# The ported MythBurn scripts which feature:
    720
    from __future__ import unicode_literals  
    4962
    5063
    5164# version of script - change after each update
    52 VERSION="0.1.20131119-1"
     65VERSION="0.2.20200122-1"
    5366
    5467# keep all temporary files for debugging purposes
    5568# set this to True before a first run through when testing
    import unicodedata  
    96109import time
    97110import tempfile
    98111from fcntl import ioctl
    99 import CDROM
     112
     113try:
     114    import CDROM
     115except:
     116    # Some hardcoded values for ioctl calls,
     117    # not available on python > 3.5, see include/linux/cdrom.h
     118    class CDROM(object):
     119        CDS_NO_INFO = 0
     120        CDS_NO_DISC = 1
     121        CDS_TRAY_OPEN = 2
     122        CDS_DRIVE_NOT_READY = 3
     123        CDS_DISC_OK = 4
     124        CDROMEJECT = 0x5309
     125        CDROMRESET = 0x5312
     126        CDROM_DRIVE_STATUS = 0x5326
     127        CDROM_LOCKDOOR = 0x5329
     128
    100129from shutil import copy
    101130
    102131import MythTV
    drivespeed = 0;  
    155184#main menu aspect ratio (4:3 or 16:9)
    156185mainmenuAspectRatio = "16:9"
    157186
    158 #chapter menu aspect ratio (4:3, 16:9 or Video) 
     187#chapter menu aspect ratio (4:3, 16:9 or Video)
    159188#video means same aspect ratio as the video title
    160189chaptermenuAspectRatio = "Video"
    161190
    class FontDef(object):  
    279308def write(text, progress=True):
    280309    """Simple place to channel all text output through"""
    281310
    282     sys.stdout.write((text + "\n").encode("utf-8", "replace"))
     311    if sys.version_info == 2:
     312        sys.stdout.write((text + "\n").encode("utf-8", "replace"))
     313    else:
     314        sys.stdout.write(text + "\n")
    283315    sys.stdout.flush()
    284316
    285317    if progress == True and progresslog != "":
    def encodeMenu(background, tempvideo, music, musiclength, tempmovie, xmlfile, fi  
    505537    command = quoteCmdArg(path_jpeg2yuv[0]) + " -n %s -v0 -I p -f %s -j %s | %s -b 5000 -a %s -v 1 -f 8 -o %s" \
    506538              % (totalframes, framespersecond, quoteCmdArg(background), quoteCmdArg(path_mpeg2enc[0]), aspectratio, quoteCmdArg(tempvideo))
    507539    result = runCommand(command)
    508     if result<>0:
     540    if result!=0:
    509541        fatalError("Failed while running jpeg2yuv - %s" % command)
    510542
    511543    command = quoteCmdArg(path_mplex[0]) + " -f 8 -v 0 -o %s %s %s" % (quoteCmdArg(tempmovie), quoteCmdArg(tempvideo), quoteCmdArg(music))
    512544    result = runCommand(command)
    513     if result<>0:
     545    if result!=0:
    514546        fatalError("Failed while running mplex - %s" % command)
    515547
    516548    if xmlfile != "":
    517549        command = quoteCmdArg(path_spumux[0]) + " -m dvd -s 0 %s < %s > %s" % (quoteCmdArg(xmlfile), quoteCmdArg(tempmovie), quoteCmdArg(finaloutput))
    518550        result = runCommand(command)
    519         if result<>0:
     551        if result!=0:
    520552            fatalError("Failed while running spumux - %s" % command)
    521553    else:
    522554        os.rename(tempmovie, finaloutput)
    def encodeMenu(background, tempvideo, music, musiclength, tempmovie, xmlfile, fi  
    527559            os.remove(tempmovie)
    528560
    529561#############################################################
    530 # Return an xml node from a re-encoding profile xml file for 
     562# Return an xml node from a re-encoding profile xml file for
    531563# a given profile name
    532564
    533565def findEncodingProfile(profile):
    def getLengthOfVideo(index):  
    606638    return duration
    607639
    608640#############################################################
    609 # Gets the audio sample rate and number of channels of a video file 
     641# Gets the audio sample rate and number of channels of a video file
    610642# from its stream info file
    611643
    612644def getAudioParams(folder):
    def getVideoParams(folder):  
    643675    if video.attributes["aspectratio"].value != 'N/A':
    644676        aspect_ratio = video.attributes["aspectratio"].value
    645677    else:
    646         aspect_ratio = "1.77778" 
     678        aspect_ratio = "1.77778"
    647679
    648680    videores = video.attributes["width"].value + 'x' + video.attributes["height"].value
    649681    fps = video.attributes["fps"].value
    def getFormatedLengthOfVideo(index):  
    729761def frameToTime(frame, fps):
    730762    sec = int(frame / fps)
    731763    frame = frame - int(sec * fps)
    732     mins = sec / 60
     764    mins = sec // 60
    733765    sec %= 60
    734     hour = mins / 60
     766    hour = mins // 60
    735767    mins %= 60
    736768
    737769    return '%02d:%02d:%02d' % (hour, mins, sec)
    def frameToTime(frame, fps):  
    740772# Convert a time string of format 00:00:00 to number of seconds
    741773
    742774def timeStringToSeconds(formatedtime):
    743     parts = string.split(formatedtime, ':')
     775    parts = formatedtime.split(':')
    744776    if len(parts) != 3:
    745777        return 0
    746778
    def createVideoChapters(itemnum, numofchapters, lengthofvideo, getthumbnails):  
    801833#############################################################
    802834# Creates some fixed length chapter marks
    803835
    804 def createVideoChaptersFixedLength(itemnum, segment, lengthofvideo): 
    805     """Returns chapter marks at cut list ends, 
     836def createVideoChaptersFixedLength(itemnum, segment, lengthofvideo):
     837    """Returns chapter marks at cut list ends,
    806838       or evenly spaced chapters 'segment' seconds through the file"""
    807839
    808840
    def createVideoChaptersFixedLength(itemnum, segment, lengthofvideo):  
    820852    if lengthofvideo < segment:
    821853        return "00:00:00"
    822854
    823     numofchapters = lengthofvideo / segment + 1;
     855    numofchapters = lengthofvideo // segment + 1;
    824856    chapters = "00:00:00"
    825857    starttime = 0
    826858    count = 2
    def getDefaultParametersFromMythTVDB():  
    845877    sqlstatement="""SELECT value, data FROM settings WHERE value IN(
    846878                        'DBSchemaVer',
    847879                        'ISO639Language0',
    848                         'ISO639Language1') 
     880                        'ISO639Language1')
    849881                    OR (hostname=%s AND value IN(
    850882                        'VideoStartupDir',
    851883                        'GalleryDir',
    def getOptions(options):  
    939971
    940972def expandItemText(infoDOM, text, itemnumber, pagenumber, keynumber,chapternumber, chapterlist ):
    941973    """Replaces keywords in a string with variables from the XML and filesystem"""
    942     text=string.replace(text,"%page","%s" % pagenumber)
     974    text=text.replace("%page","%s" % pagenumber)
    943975
    944976    #See if we can use the thumbnail/cover file for videos if there is one.
    945977    if getText( infoDOM.getElementsByTagName("coverfile")[0]) =="":
    946         text=string.replace(text,"%thumbnail", os.path.join( getItemTempPath(itemnumber), "title.jpg"))
     978        text=text.replace("%thumbnail", os.path.join( getItemTempPath(itemnumber), "title.jpg"))
    947979    else:
    948         text=string.replace(text,"%thumbnail", getText( infoDOM.getElementsByTagName("coverfile")[0]) )
     980        text=text.replace("%thumbnail", getText( infoDOM.getElementsByTagName("coverfile")[0]) )
    949981
    950     text=string.replace(text,"%itemnumber","%s" % itemnumber )
    951     text=string.replace(text,"%keynumber","%s" % keynumber )
     982    text=text.replace("%itemnumber","%s" % itemnumber )
     983    text=text.replace("%keynumber","%s" % keynumber )
    952984
    953     text=string.replace(text,"%title",getText( infoDOM.getElementsByTagName("title")[0]) )
    954     text=string.replace(text,"%subtitle",getText( infoDOM.getElementsByTagName("subtitle")[0]) )
    955     text=string.replace(text,"%description",getText( infoDOM.getElementsByTagName("description")[0]) )
    956     text=string.replace(text,"%type",getText( infoDOM.getElementsByTagName("type")[0]) )
     985    text=text.replace("%title",getText( infoDOM.getElementsByTagName("title")[0]) )
     986    text=text.replace("%subtitle",getText( infoDOM.getElementsByTagName("subtitle")[0]) )
     987    text=text.replace("%description",getText( infoDOM.getElementsByTagName("description")[0]) )
     988    text=text.replace("%type",getText( infoDOM.getElementsByTagName("type")[0]) )
    957989
    958     text=string.replace(text,"%recordingdate",getText( infoDOM.getElementsByTagName("recordingdate")[0]) )
    959     text=string.replace(text,"%recordingtime",getText( infoDOM.getElementsByTagName("recordingtime")[0]) )
     990    text=text.replace("%recordingdate",getText( infoDOM.getElementsByTagName("recordingdate")[0]) )
     991    text=text.replace("%recordingtime",getText( infoDOM.getElementsByTagName("recordingtime")[0]) )
    960992
    961     text=string.replace(text,"%duration", getFormatedLengthOfVideo(itemnumber))
     993    text=text.replace("%duration", getFormatedLengthOfVideo(itemnumber))
    962994
    963     text=string.replace(text,"%myfolder",getThemeFile(themeName,""))
     995    text=text.replace("%myfolder",getThemeFile(themeName,""))
    964996
    965997    if chapternumber>0:
    966         text=string.replace(text,"%chapternumber","%s" % chapternumber )
    967         text=string.replace(text,"%chaptertime","%s" % chapterlist[chapternumber - 1] )
    968         text=string.replace(text,"%chapterthumbnail", os.path.join( getItemTempPath(itemnumber), "chapter-%s.jpg" % chapternumber))
     998        text=text.replace("%chapternumber","%s" % chapternumber )
     999        text=text.replace("%chaptertime","%s" % chapterlist[chapternumber - 1] )
     1000        text=text.replace("%chapterthumbnail", os.path.join( getItemTempPath(itemnumber), "chapter-%s.jpg" % chapternumber))
    9691001
    9701002    return text
    9711003
    def intelliDraw(drawer, text, font, containerWidth):  
    9941026    #write("containerWidth: %s" % containerWidth)
    9951027    words = text.split()
    9961028    lines = [] # prepare a return argument
    997     lines.append(words) 
     1029    lines.append(words)
    9981030    finished = False
    9991031    line = 0
    10001032    while not finished:
    def intelliDraw(drawer, text, font, containerWidth):  
    10081040            if drawer.textsize(' '.join(thistext),font.getFont())[0] > containerWidth:
    10091041                # this is the heart of the algorithm: we pop words off the current
    10101042                # sentence until the width is ok, then in the next outer loop
    1011                 # we move on to the next sentence. 
     1043                # we move on to the next sentence.
    10121044                if str(thistext).find(' ') != -1:
    10131045                    newline.insert(0,thistext.pop(-1))
    10141046                else:
    def paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,  
    11331165#############################################################
    11341166# Paint some theme text on to an image
    11351167
    1136 def paintText(draw, image, text, node, color = None, 
     1168def paintText(draw, image, text, node, color = None,
    11371169              x = None, y = None, width = None, height = None):
    11381170    """Takes a piece of text and draws it onto an image inside a bounding box."""
    11391171    #The text is wider than the width of the bounding box
    11401172
    11411173    if x == None:
    1142         x = getScaledAttribute(node, "x") 
     1174        x = getScaledAttribute(node, "x")
    11431175        y = getScaledAttribute(node, "y")
    11441176        width = getScaledAttribute(node, "w")
    11451177        height = getScaledAttribute(node, "h")
    def paintText(draw, image, text, node, color = None,  
    11861218    for i in lines:
    11871219        if (j * h) < (height - (vindent * 2) - h):
    11881220            textImage = font.drawText(i, color)
    1189             write( "Wrapped text  = " + i.encode("ascii", "replace"), False)
     1221            write( "Wrapped text  = " + i )  # encoding is done within 'write'
    11901222
    11911223            if halign == "left":
    11921224                xoffset = hindent
    11931225            elif  halign == "center" or halign == "centre":
    1194                 xoffset = (width / 2) - (textImage.size[0] / 2)
     1226                xoffset = (width // 2) - (textImage.size[0] // 2)
    11951227            elif  halign == "right":
    11961228                xoffset = width - textImage.size[0] - hindent
    11971229            else:
    def paintText(draw, image, text, node, color = None,  
    12001232            if valign == "top":
    12011233                yoffset = vindent
    12021234            elif  valign == "center" or halign == "centre":
    1203                 yoffset = (height / 2) - (textImage.size[1] / 2)
     1235                yoffset = (height // 2) - (textImage.size[1] // 2)
    12041236            elif  valign == "bottom":
    12051237                yoffset = height - textImage.size[1] - vindent
    12061238            else:
    def paintText(draw, image, text, node, color = None,  
    12081240
    12091241            image.paste(textImage, (x + xoffset,y + yoffset + j * h), textImage)
    12101242        else:
    1211             write( "Truncated text = " + i.encode("ascii", "replace"), False)
     1243            write( "Wrapped text  = " + i )  # encoding is done within 'write'
    12121244        #Move to next line
    12131245        j = j + 1
    12141246
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12301262    (imgw, imgh) = picture.size
    12311263    write("Image (%s, %s) into space of (%s, %s) at (%s, %s)" % (imgw, imgh, w, h, xpos, ypos), False)
    12321264
    1233     # the theme can override the default stretch behaviour 
    1234     if imageDom.hasAttribute("stretch"): 
     1265    # the theme can override the default stretch behaviour
     1266    if imageDom.hasAttribute("stretch"):
    12351267        if imageDom.attributes["stretch"].value == "True":
    12361268            stretch = True
    12371269        else:
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12431275    else:
    12441276        if float(w)/imgw < float(h)/imgh:
    12451277            # Width is the constraining dimension
    1246             imgh = imgh*w/imgw
     1278            imgh = imgh*w//imgw
    12471279            imgw = w
    12481280            if imageDom.hasAttribute("valign"):
    12491281                valign = imageDom.attributes["valign"].value
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12531285            if valign == "bottom":
    12541286                ypos += h - imgh
    12551287            if valign == "center":
    1256                 ypos += (h - imgh)/2
     1288                ypos += (h - imgh)//2
    12571289        else:
    12581290            # Height is the constraining dimension
    1259             imgw = imgw*h/imgh
     1291            imgw = imgw*h//imgh
    12601292            imgh = h
    12611293            if imageDom.hasAttribute("halign"):
    12621294                halign = imageDom.attributes["halign"].value
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12661298            if halign == "right":
    12671299                xpos += w - imgw
    12681300            if halign == "center":
    1269                 xpos += (w - imgw)/2
     1301                xpos += (w - imgw)//2
    12701302
    12711303    write("Image resized to (%s, %s) at (%s, %s)" % (imgw, imgh, xpos, ypos), False)
    12721304    picture = picture.resize((imgw, imgh))
    12731305    picture = picture.convert("RGBA")
    12741306
    1275     if maskfilename <> None and doesFileExist(maskfilename):
     1307    if maskfilename != None and doesFileExist(maskfilename):
    12761308        maskpicture = Image.open(maskfilename, "r").resize((imgw, imgh))
    12771309        maskpicture = maskpicture.convert("RGBA")
    12781310    else:
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12801312
    12811313    destimage.paste(picture, (xpos, ypos), maskpicture)
    12821314    del picture
    1283     if maskfilename <> None and doesFileExist(maskfilename):
     1315    if maskfilename != None and doesFileExist(maskfilename):
    12841316        del maskpicture
    12851317
    12861318    write ("Added image %s" % filename)
    def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):  
    12941326def checkBoundaryBox(boundarybox, node):
    12951327    # We work out how much space all of our graphics and text are taking up
    12961328    # in a bounding rectangle so that we can use this as an automatic highlight
    1297     # on the DVD menu   
     1329    # on the DVD menu
    12981330    if getText(node.attributes["static"]) == "False":
    12991331        if getScaledAttribute(node, "x") < boundarybox[0]:
    13001332            boundarybox = getScaledAttribute(node, "x"), boundarybox[1], boundarybox[2], boundarybox[3]
    def getFileInformation(file, folder):  
    13891421        if file.attributes["type"].value=="recording":
    13901422            filename = file.attributes["filename"].value
    13911423            try:
    1392                 rec = DB.searchRecorded(basename=os.path.basename(filename)).next()
     1424                rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
    13931425            except StopIteration:
    13941426                fatalError("Failed to get recording details from the DB for %s" % filename)
    13951427
    def getFileInformation(file, folder):  
    14121444    elif file.attributes["type"].value=="recording":
    14131445        filename = file.attributes["filename"].value
    14141446        try:
    1415             rec = DB.searchRecorded(basename=os.path.basename(filename)).next()
     1447            rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
    14161448        except StopIteration:
    14171449            fatalError("Failed to get recording details from the DB for %s" % filename)
    14181450
    def getFileInformation(file, folder):  
    14431475    elif file.attributes["type"].value=="video":
    14441476        filename = file.attributes["filename"].value
    14451477        try:
    1446             vid = MVID.searchVideos(file=filename).next()
     1478            vid = next(MVID.searchVideos(file=filename))
    14471479        except StopIteration:
    14481480            vid = Video.fromFilename(filename)
    14491481
    def getFileInformation(file, folder):  
    14891521
    14901522        data.thumblist = ','.join(thumblist)
    14911523
    1492     for k,v in data.items():
     1524    for k,v in list(data.items()):
    14931525        write( "Node = %s, Data = %s" % (k, v))
    14941526        node = infoDOM.createElement(k)
    14951527        # v may be either an integer. Therefore we have to
    def getFileInformation(file, folder):  
    15071539# Write an xml file to disc
    15081540
    15091541def WriteXMLToFile(myDOM, filename):
     1542
    15101543    #Save the XML file to disk for use later on
    15111544    f=open(filename, 'w')
    15121545
    1513     if sys.hexversion >= 0x020703F0:
     1546    if sys.hexversion >= 0x03000000:
     1547        f.write(myDOM.toprettyxml(indent="    ", encoding="UTF-8").decode())
     1548    elif sys.hexversion >= 0x020703F0:
    15141549        f.write(myDOM.toprettyxml(indent="    ", encoding="UTF-8"))
    15151550    else:
    15161551        f.write(myDOM.toxml(encoding="UTF-8"))
    def multiplexMPEGStream(video, audio1, audio2, destination, syncOffset):  
    15881623
    15891624    write("Multiplexing MPEG stream to %s" % destination)
    15901625
    1591     # no need to use a sync offset if projectx was used to demux the streams 
     1626    # no need to use a sync offset if projectx was used to demux the streams
    15921627    if useprojectx:
    15931628        syncOffset = 0
    15941629    else:
    def multiplexMPEGStream(video, audio1, audio2, destination, syncOffset):  
    16311666
    16321667    if not doesFileExist(audio2):
    16331668        write("Available streams - video and one audio stream")
     1669        write("running %s -M -f 8 -v 0 --sync-offset %sms -o %s %s %s" %(path_mplex[0], syncOffset, destination, video, audio1))
    16341670        result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
    16351671                    '-M',
    16361672                    '-f', '8',
    def multiplexMPEGStream(video, audio1, audio2, destination, syncOffset):  
    16631699        write("Checking integrity of subtitle pngs")
    16641700        command = quoteCmdArg(os.path.join(scriptpath, "testsubtitlepngs.sh")) + " " + quoteCmdArg(os.path.dirname(destination) + "/stream.d/spumux.xml")
    16651701        result = runCommand(command)
    1666         if result<>0:
     1702        if result!=0:
    16671703            fatalError("Failed while running testsubtitlepngs.sh - %s" % command)
    16681704
    16691705        write("Running spumux to add subtitles")
    16701706        command = quoteCmdArg(path_spumux[0]) + " -P %s <%s >%s" % (quoteCmdArg(os.path.dirname(destination) + "/stream.d/spumux.xml"), quoteCmdArg(destination), quoteCmdArg(os.path.splitext(destination)[0] + "-sub.mpg"))
    16711707        result = runCommand(command)
    1672         if result<>0:
     1708        if result!=0:
    16731709            nonfatalError("Failed while running spumux.\n"
    16741710                          "Command was - %s.\n"
    16751711                          "Look in the full log to see why it failed" % command)
    def getStreamInformation(filename, xmlFilename, lenMethod):  
    16911727
    16921728    result = runCommand(command)
    16931729
    1694     if result <> 0:
     1730    if result != 0:
    16951731        fatalError("Failed while running mytharchivehelper to get stream information.\n"
    16961732                   "Result: %d, Command was %s" % (result, command))
    16971733
    def runMythtranscode(chanid, starttime, destination, usecutlist, localfile):  
    17301766    """Use mythtranscode to cut commercials and/or clean up an mpeg2 file"""
    17311767
    17321768    try:
    1733         rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
     1769        rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
    17341770        cutlist = rec.markup.getcutlist()
    17351771    except StopIteration:
    17361772        cutlist = []
    def runMythtranscode(chanid, starttime, destination, usecutlist, localfile):  
    17701806def generateProjectXCutlist(chanid, starttime, folder):
    17711807    """generate cutlist_x.txt for ProjectX"""
    17721808
    1773     rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
     1809    rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
    17741810    starttime = rec.starttime.utcisoformat()
    17751811    cutlist = rec.markup.getcutlist()
    17761812
    def generateProjectXCutlist(chanid, starttime, folder):  
    17811817            for cut in cutlist:
    17821818                # we need to reverse the cutlist because ProjectX wants to know
    17831819                # the bits to keep not what to cut
    1784                
     1820
    17851821                if i == 0:
    17861822                    if cut[0] != 0:
    17871823                        cutlist_f.write('0\n%d\n' % cut[0])
    def extractVideoFrame(source, destination, seconds):  
    19792015
    19802016        command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (quoteCmdArg(source), seconds, quoteCmdArg(destination))
    19812017        result = runCommand(command)
    1982         if result <> 0:
     2018        if result != 0:
    19832019            fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
    19842020                       "Result: %d, Command was %s" % (result, command))
    19852021    try:
    19862022        myimage=Image.open(destination,"r")
    19872023
    1988         if myimage.format <> "JPEG":
     2024        if myimage.format != "JPEG":
    19892025            write( "Something went wrong with thumbnail capture - " + myimage.format)
    1990             return (0L,0L)
     2026            return (long(0),long(0))
    19912027        else:
    19922028            return myimage.size
    19932029    except IOError:
    1994         return (0L, 0L)
     2030        return (long(0),long(0))
    19952031
    19962032#############################################################
    19972033# Grabs a list of single frames from a file
    def extractVideoFrames(source, destination, thumbList):  
    20032039    command = "mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (quoteCmdArg(source), thumbList, quoteCmdArg(destination))
    20042040    write(command)
    20052041    result = runCommand(command)
    2006     if result <> 0:
     2042    if result != 0:
    20072043        fatalError("Failed while running mytharchivehelper to get thumbnails.\n"
    20082044                   "Result: %d, Command was %s" % (result, command))
    20092045
    def encodeVideoToMPEG2(source, destvideofile, video, audio1, audio2, aspectratio  
    20832119    else:
    20842120        passLog = os.path.join(getTempPath(), 'pass')
    20852121
    2086         pass1 = string.replace(command, "%passno","1")
    2087         pass1 = string.replace(pass1, "%passlogfile", quoteCmdArg(passLog))
     2122        pass1 = command.replace("%passno","1")
     2123        pass1 = pass1.replace("%passlogfile", quoteCmdArg(passLog))
    20882124        write("Pass 1 - " + pass1)
    20892125        result = runCommand(pass1)
    20902126
    def encodeVideoToMPEG2(source, destvideofile, video, audio1, audio2, aspectratio  
    20952131        if os.path.exists(destvideofile):
    20962132            os.remove(destvideofile)
    20972133
    2098         pass2 = string.replace(command, "%passno","2")
    2099         pass2 = string.replace(pass2, "%passlogfile", passLog)
     2134        pass2 = command.replace("%passno","2")
     2135        pass2 = pass2.replace("%passlogfile", passLog)
    21002136        write("Pass 2 - " + pass2)
    21012137        result = runCommand(pass2)
    21022138
    def encodeNuvToMPEG2(chanid, starttime, mediafile, destvideofile, folder, profil  
    21172153    profileNode = findEncodingProfile(profile)
    21182154    parameters = profileNode.getElementsByTagName("parameter")
    21192155
    2120     # default values - will be overriden by values from the profile 
     2156    # default values - will be overriden by values from the profile
    21212157    outvideobitrate = "5000k"
    21222158    if videomode == "ntsc":
    21232159        outvideores = "720x480"
    def encodeNuvToMPEG2(chanid, starttime, mediafile, destvideofile, folder, profil  
    21982234    if cpuCount > 1:
    21992235        command += "-threads %d " % cpuCount
    22002236
    2201     command += "-f s16le -ar %s -ac %s -i %s " % (samplerate, channels, quoteCmdArg(os.path.join(folder, "audout"))) 
     2237    command += "-f s16le -ar %s -ac %s -i %s " % (samplerate, channels, quoteCmdArg(os.path.join(folder, "audout")))
    22022238    command += "-f rawvideo -pix_fmt yuv420p -s %s -aspect %s -r %s " % (videores, aspectratio, fps)
    22032239    command += "-i %s " % quoteCmdArg(os.path.join(folder, "vidout"))
    22042240    command += "-aspect %s -r %s " % (aspectratio, fps)
    def runDVDAuthor():  
    22352271    write( "Starting dvdauthor")
    22362272    checkCancelFlag()
    22372273    result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],'-x',os.path.join(getTempPath(),'dvdauthor.xml'))
    2238     if result<>0:
     2274    if result!=0:
    22392275        fatalError("Failed while running dvdauthor. Result: %d" % result)
    22402276    write( "Finished  dvdauthor")
    22412277
    def CreateDVDISO(title):  
    22522288
    22532289    result = runCommand(command)
    22542290
    2255     if result<>0:
     2291    if result!=0:
    22562292        fatalError("Failed while running mkisofs.\n"
    22572293                   "Command was %s" % command)
    22582294
    22592295    write("Finished creating ISO image")
    22602296
    22612297#############################################################
    2262 # Burns the contents of a directory to create a DVD 
     2298# Burns the contents of a directory to create a DVD
    22632299
    22642300
    22652301def BurnDVDISO(title):
    def BurnDVDISO(title):  
    22932329                try:
    22942330                  ioctl(f,action, value)
    22952331                except:
    2296                   write("Sending command ", action, " to drive failed", False)
     2332                  write("Sending command '0x%x' to drive failed" %action, False)
    22972333                os.close(f)
    22982334            else:   # try eject-command
    22992335                if runCommand("eject " + quoteCmdArg(dvddrivepath)) == 32512:
    def BurnDVDISO(title):  
    23122348              ioctl(f,action, value)
    23132349              res = True
    23142350            except:
    2315               write("Sending command ", action, " to drive failed", False)
     2351              write("Sending command '0x%x' to drive failed" %action, False)
    23162352              res = False
    2317             os.close(f) 
    2318         return res 
     2353            os.close(f)
     2354        return res
    23192355    def waitForDrive():
    23202356        tries = 0
    23212357        while drivestatus() == CDROM.CDS_DRIVE_NOT_READY:
    def BurnDVDISO(title):  
    23632399            result = runCommand(command)
    23642400            if result == 0:
    23652401                finished = True
    2366                
     2402
    23672403                # Wait till the drive is not busy any longer
    23682404                f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
    23692405                busy = True
    def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):  
    24272463        command = "mythreplex --demux --fix_sync -t TS -o %s " % quoteCmdArg(folder + "/stream")
    24282464        command += "-v %d " % (video[VIDEO_ID])
    24292465
    2430         if audio1[AUDIO_ID] != -1: 
     2466        if audio1[AUDIO_ID] != -1:
    24312467            if audio1[AUDIO_CODEC] == 'MP2':
    24322468                command += "-a %d " % (audio1[AUDIO_ID])
    24332469            elif audio1[AUDIO_CODEC] == 'AC3':
    def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):  
    24352471            elif audio1[AUDIO_CODEC] == 'EAC3':
    24362472                command += "-c %d " % (audio1[AUDIO_ID])
    24372473
    2438         if audio2[AUDIO_ID] != -1: 
     2474        if audio2[AUDIO_ID] != -1:
    24392475            if audio2[AUDIO_CODEC] == 'MP2':
    24402476                command += "-a %d " % (audio2[AUDIO_ID])
    24412477            elif audio2[AUDIO_CODEC] == 'AC3':
    def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):  
    24472483        command = "mythreplex --demux --fix_sync -o %s " % quoteCmdArg(folder + "/stream")
    24482484        command += "-v %d " % (video[VIDEO_ID] & 255)
    24492485
    2450         if audio1[AUDIO_ID] != -1: 
     2486        if audio1[AUDIO_ID] != -1:
    24512487            if audio1[AUDIO_CODEC] == 'MP2':
    24522488                command += "-a %d " % (audio1[AUDIO_ID] & 255)
    24532489            elif audio1[AUDIO_CODEC] == 'AC3':
    def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):  
    24562492                command += "-c %d " % (audio1[AUDIO_ID] & 255)
    24572493
    24582494
    2459         if audio2[AUDIO_ID] != -1: 
     2495        if audio2[AUDIO_ID] != -1:
    24602496            if audio2[AUDIO_CODEC] == 'MP2':
    24612497                command += "-a %d " % (audio2[AUDIO_ID] & 255)
    24622498            elif audio2[AUDIO_CODEC] == 'AC3':
    def deMultiplexMPEG2File(folder, mediafile, video, audio1, audio2):  
    24702506
    24712507    result = runCommand(command)
    24722508
    2473     if result<>0:
     2509    if result!=0:
    24742510        fatalError("Failed while running mythreplex. Command was %s" % command)
    24752511
    24762512#############################################################
    def runM2VRequantiser(source,destination,factor):  
    24862522    command += " %s "  % M2Vsize0
    24872523    command += " <  %s " % quoteCmdArg(source)
    24882524    command += " >  %s " % quoteCmdArg(destination)
    2489  
     2525
    24902526    write("Running: " + command)
    24912527    result = runCommand(command)
    2492     if result<>0:
     2528    if result!=0:
    24932529        fatalError("Failed while running M2VRequantiser. Command was %s" % command)
    24942530
    24952531    M2Vsize1 = os.path.getsize(destination)
    2496        
     2532
    24972533    write("M2Vsize after requant is  %.2f Mb " % (float(M2Vsize1)/mega))
    24982534    fac1=float(M2Vsize0) / float(M2Vsize1)
    24992535    write("Factor demanded %.5f, achieved %.5f, ratio %.5f " % ( factor, fac1, fac1/factor))
    25002536
    25012537#############################################################
    2502 # Calculates the total size of all the video, audio and menu files 
     2538# Calculates the total size of all the video, audio and menu files
    25032539
    25042540def calculateFileSizes(files):
    25052541    """ Returns the sizes of all video, audio and menu files"""
    def calculateFileSizes(files):  
    25152551        #Process this file
    25162552        file=os.path.join(folder,"stream.mv2")
    25172553        #Get size of vobfile in MBytes
    2518         totalvideosize+=os.path.getsize(file) 
     2554        totalvideosize+=os.path.getsize(file)
    25192555
    25202556        #Get size of audio track 1
    25212557        if doesFileExist(os.path.join(folder,"stream0.ac3")):
    2522             totalaudiosize+=os.path.getsize(os.path.join(folder,"stream0.ac3")) 
     2558            totalaudiosize+=os.path.getsize(os.path.join(folder,"stream0.ac3"))
    25232559        if doesFileExist(os.path.join(folder,"stream0.mp2")):
    2524             totalaudiosize+=os.path.getsize(os.path.join(folder,"stream0.mp2")) 
     2560            totalaudiosize+=os.path.getsize(os.path.join(folder,"stream0.mp2"))
    25252561
    2526         #Get size of audio track 2 if available 
     2562        #Get size of audio track 2 if available
    25272563        if doesFileExist(os.path.join(folder,"stream1.ac3")):
    2528             totalaudiosize+=os.path.getsize(os.path.join(folder,"stream1.ac3")) 
     2564            totalaudiosize+=os.path.getsize(os.path.join(folder,"stream1.ac3"))
    25292565        if doesFileExist(os.path.join(folder,"stream1.mp2")):
    2530             totalaudiosize+=os.path.getsize(os.path.join(folder,"stream1.mp2")) 
     2566            totalaudiosize+=os.path.getsize(os.path.join(folder,"stream1.mp2"))
    25312567
    25322568        # add chapter menu if available
    25332569        if doesFileExist(os.path.join(getTempPath(),"chaptermenu-%s.mpg" % filecount)):
    2534             totalmenusize+=os.path.getsize(os.path.join(getTempPath(),"chaptermenu-%s.mpg" % filecount)) 
     2570            totalmenusize+=os.path.getsize(os.path.join(getTempPath(),"chaptermenu-%s.mpg" % filecount))
    25352571
    25362572        # add details page if available
    25372573        if doesFileExist(os.path.join(getTempPath(),"details-%s.mpg" % filecount)):
    def calculateFileSizes(files):  
    25472583########################################
    25482584#returns total size of bitrate-limited m2v files
    25492585
    2550 def total_mv2_brl(files,rate): 
    2551     tvsize=0 
     2586def total_mv2_brl(files,rate):
     2587    tvsize=0
    25522588    filecount=0
    25532589    for node in files:
    25542590        filecount+=1
    def total_mv2_brl(files,rate):  
    25572593        file=os.path.join(folder,"stream.mv2")
    25582594        progvsize=os.path.getsize(file)
    25592595        progvbitrate=progvsize/progduration
    2560         if progvbitrate>rate : 
     2596        if progvbitrate>rate :
    25612597            tvsize+=progduration*rate
    25622598        else:
    25632599            tvsize+=progvsize
    25642600
    2565     return tvsize   
     2601    return tvsize
    25662602
    25672603#########################################
    2568 # Uses requantiser if available to shrink the video streams so 
     2604# Uses requantiser if available to shrink the video streams so
    25692605# they will fit on a DVD
    25702606
    25712607def performMPEG2Shrink(files,dvdrsize):
    def performMPEG2Shrink(files,dvdrsize):  
    25822618
    25832619    #Subtract the audio, menus and packaging overhead from the size of the disk (we cannot shrink this further)
    25842620    mv2space=((dvdrsize*mega-totalmenusize)/fudge_pack)-totalaudiosize
    2585  
     2621
    25862622    if mv2space<0:
    25872623        fatalError("Audio and menu files are too big. No room for video. Giving up!")
    25882624
    def performMPEG2Shrink(files,dvdrsize):  
    26022638            vsize+=os.path.getsize(file)
    26032639            duration+=getLengthOfVideo(filecount)
    26042640
    2605         #We need to shrink the video files to fit into the space available.  It seems sensible 
    2606         #to do this by imposing a common upper limit on the mean video bit-rate of each recording; 
     2641        #We need to shrink the video files to fit into the space available.  It seems sensible
     2642        #to do this by imposing a common upper limit on the mean video bit-rate of each recording;
    26072643        #this will not further reduce the visual quality of any that were transmitted at lower bit-rates.
    26082644
    2609         #Now find the bit-rate limit by iteration between initially defined upper and lower bounds. 
     2645        #Now find the bit-rate limit by iteration between initially defined upper and lower bounds.
    26102646        #The code is based on 'rtbis' from Numerical Recipes by W H Press et al., CUP.
    2611        
     2647
    26122648        #A small multiple of the average input bit-rate should be ok as the initial upper bound,
    26132649        #(although a fixed value or one related to the max value could be used), and zero as the lower bound.
    26142650        #The function relating bit-rate upper limit to total file size is smooth and monotonic,
    2615         #so there should be no convergence problem. 
    2616      
     2651        #so there should be no convergence problem.
     2652
    26172653        vrLo=0.0
    26182654        vrHi=3.0*float(vsize)/duration
    2619        
     2655
    26202656        vrate=vrLo
    26212657        vrinc=vrHi-vrLo
    26222658        count=0
    def performMPEG2Shrink(files,dvdrsize):  
    26282664            testsize=total_mv2_brl(files,vrtest)
    26292665            if (testsize<mv2space):
    26302666                vrate=vrtest
    2631            
     2667
    26322668        write("vrate %.3f kb/s, testsize %.4f , mv2space %.4f Mb " % ((vrate)/1000.0, (testsize)/mega, (mv2space)/mega) )
    26332669        filecount=0
    26342670        for node in files:
    def createDVDAuthorXML(screensize, numberofitems):  
    26652701    #Total number of video items on a single menu page (no less than 1!)
    26662702    itemsperpage = menuitems.length
    26672703    write( "Menu items per page %s" % itemsperpage)
    2668     autoplaymenu = 2 + ((numberofitems + itemsperpage - 1)/itemsperpage)
     2704    autoplaymenu = 2 + ((numberofitems + itemsperpage - 1)//itemsperpage)
    26692705
    26702706    if wantChapterMenu:
    26712707        #Get the chapter menu node (we must only have 1)
    def createDVDAuthorXML(screensize, numberofitems):  
    27752811        #g4 holds the menu page last displayed
    27762812        pre = dvddom.createElement("pre")
    27772813        pre.appendChild(dvddom.createTextNode("{button=g2*1024;g4=%s;}" % page))
    2778         menupgc.appendChild(pre)   
     2814        menupgc.appendChild(pre)
    27792815
    27802816        vob = dvddom.createElement("vob")
    27812817        vob.setAttribute("file",os.path.join(getTempPath(),"menu-%s.mpg" % page))
    def createDVDAuthorXML(screensize, numberofitems):  
    28332869            elif chaptermenuAspectRatio == "16:9":
    28342870                video.setAttribute("aspect", "16:9")
    28352871                video.setAttribute("widescreen", "nopanscan")
    2836             else: 
     2872            else:
    28372873                # use same aspect ratio as the video
    28382874                if getAspectRatioOfVideo(itemnum) > aspectRatioThreshold:
    28392875                    video.setAttribute("aspect", "16:9")
    def createDVDAuthorXML(screensize, numberofitems):  
    28492885
    28502886                pre = dvddom.createElement("pre")
    28512887                mymenupgc.appendChild(pre)
    2852                 if wantDetailsPage: 
     2888                if wantDetailsPage:
    28532889                    pre.appendChild(dvddom.createTextNode("{button=s7 - 1 * 1024;}"))
    28542890                else:
    28552891                    pre.appendChild(dvddom.createTextNode("{button=s7 * 1024;}"))
    28562892
    28572893                vob = dvddom.createElement("vob")
    28582894                vob.setAttribute("file",os.path.join(getTempPath(),"chaptermenu-%s.mpg" % itemnum))
    2859                 mymenupgc.appendChild(vob)   
     2895                mymenupgc.appendChild(vob)
    28602896
    28612897                #Loop menu forever
    28622898                post = dvddom.createElement("post")
    28632899                post.appendChild(dvddom.createTextNode("jump cell 1;"))
    28642900                mymenupgc.appendChild(post)
    28652901
    2866                 # the first chapter MUST be 00:00:00 if its not dvdauthor adds it which 
     2902                # the first chapter MUST be 00:00:00 if its not dvdauthor adds it which
    28672903                # throws of the chapter selection - so make sure we add it if needed so we
    2868                 # can compensate for it in the chapter selection menu 
     2904                # can compensate for it in the chapter selection menu
    28692905                firstChapter = 0
    28702906                thumblist = createVideoChapters(itemnum, chapters, getLengthOfVideo(itemnum), False)
    2871                 chapterlist = string.split(thumblist, ",")
     2907                chapterlist = thumblist.split(",")
    28722908                if chapterlist[0] != '00:00:00':
    28732909                    firstChapter = 1
    28742910                x = 1
    def createDVDAuthorXML(screensize, numberofitems):  
    28762912                    #Add this recording to this page's menu...
    28772913                    button = dvddom.createElement("button")
    28782914                    button.setAttribute("name","%s" % x)
    2879                     if wantDetailsPage: 
     2915                    if wantDetailsPage:
    28802916                        button.appendChild(dvddom.createTextNode("jump title %s chapter %s;" % (1, firstChapter + x + 1)))
    28812917                    else:
    28822918                        button.appendChild(dvddom.createTextNode("jump title %s chapter %s;" % (1, firstChapter + x)))
    def createDVDAuthorXML(screensize, numberofitems):  
    29332969            vob = dvddom.createElement("vob")
    29342970            if wantChapterMenu:
    29352971                thumblist = createVideoChapters(itemnum, chapters, getLengthOfVideo(itemnum), False)
    2936                 chapterlist = string.split(thumblist, ",")
     2972                chapterlist = thumblist.split(",")
    29372973                if chapterlist[0] != '00:00:00':
    29382974                    thumblist = '00:00:00,' + thumblist
    29392975                vob.setAttribute("chapters", thumblist)
    29402976            else:
    2941                 vob.setAttribute("chapters", 
     2977                vob.setAttribute("chapters",
    29422978                    createVideoChaptersFixedLength(itemnum,
    2943                                                    chapterLength, 
     2979                                                   chapterLength,
    29442980                                                   getLengthOfVideo(itemnum)))
    29452981
    29462982            vob.setAttribute("file",os.path.join(getItemTempPath(itemnum),"final.vob"))
    def createDVDAuthorXML(screensize, numberofitems):  
    30063042
    30073043    pre = dvddom.createElement("pre")
    30083044    pre.appendChild(dvddom.createTextNode(dvdcode))
    3009     menupgc.appendChild(pre)   
     3045    menupgc.appendChild(pre)
    30103046
    30113047    if wantIntro:
    30123048        #Menu creation is finished so we know how many pages were created
    def createDVDAuthorXML(screensize, numberofitems):  
    30183054            dvdcode+="jump menu %s;" % (page + 1)
    30193055            if (page>1):
    30203056                dvdcode+=" else "
    3021         dvdcode+="}"       
     3057        dvdcode+="}"
    30223058        vmgm_pre_node.appendChild(dvddom.createTextNode(dvdcode))
    30233059
    30243060    #write(dvddom.toprettyxml())
    def createDVDAuthorXML(screensize, numberofitems):  
    30263062    WriteXMLToFile (dvddom,os.path.join(getTempPath(),"dvdauthor.xml"))
    30273063
    30283064    #Destroy the DOM and free memory
    3029     dvddom.unlink()   
     3065    dvddom.unlink()
    30303066
    30313067#############################################################
    30323068# Creates the DVDAuthor xml file used to create a DVD with no main menu
    def createDVDAuthorXMLNoMenus(screensize, numberofitems):  
    32203256    dvddom.unlink()
    32213257
    32223258#############################################################
    3223 # Creates the directory to hold the preview images for an animated menu 
     3259# Creates the directory to hold the preview images for an animated menu
    32243260
    32253261def createEmptyPreviewFolder(videoitem):
    32263262    previewfolder = os.path.join(getItemTempPath(videoitem), "preview")
    def generateVideoPreview(videoitem, itemonthispage, menuitem, starttime, menulen  
    32643300                #see if this graphics item has a mask
    32653301                if node.hasAttribute("mask"):
    32663302                    imagemaskfilename = getThemeFile(themeName, node.attributes["mask"].value)
    3267                     if node.attributes["mask"].value <> "" and doesFileExist(imagemaskfilename):
     3303                    if node.attributes["mask"].value != "" and doesFileExist(imagemaskfilename):
    32683304                        maskpicture = Image.open(imagemaskfilename,"r").resize((width, height))
    32693305                        maskpicture = maskpicture.convert("RGBA")
    32703306
    def generateVideoPreview(videoitem, itemonthispage, menuitem, starttime, menulen  
    32763312def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,
    32773313                  bgimagemask, drawmask, highlightcolor, spumuxdom, spunode,
    32783314                  numberofitems, chapternumber, chapterlist):
    3279     """Draws text and graphics onto a dvd menu, called by 
     3315    """Draws text and graphics onto a dvd menu, called by
    32803316       createMenu and createChapterMenu"""
    32813317
    32823318    #Get the XML containing information about this item
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    32873323        fatalError("The info.xml file (%s) doesn't look right" %
    32883324                    os.path.join(getItemTempPath(itemnum),"info.xml"))
    32893325
    3290     #boundarybox holds the max and min dimensions for this item 
     3326    #boundarybox holds the max and min dimensions for this item
    32913327    #so we can auto build a menu highlight box
    32923328    boundarybox = 9999,9999,0,0
    32933329    wantHighlightBox = True
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    33193355
    33203356                # see if an image mask exists
    33213357                maskfilename = None
    3322                 if node.hasAttribute("mask") and node.attributes["mask"].value <> "":
     3358                if node.hasAttribute("mask") and node.attributes["mask"].value != "":
    33233359                    maskfilename = getThemeFile(themeName, node.attributes["mask"].value)
    33243360
    3325                 # if this is a thumb image and is a MythVideo coverart image then preserve 
     3361                # if this is a thumb image and is a MythVideo coverart image then preserve
    33263362                # its aspect ratio unless overriden later by the theme
    33273363                if (node.attributes["filename"].value == "%thumbnail"
    33283364                  and getText(infoDOM.getElementsByTagName("coverfile")[0]) !=""):
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    33663402                button.setAttribute("name","previous")
    33673403                button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
    33683404                button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
    3369                 button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
     3405                button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") +
    33703406                                                getScaledAttribute(node, "w")))
    33713407                button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
    33723408                                                getScaledAttribute(node, "h")))
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    33903426                button.setAttribute("name","next")
    33913427                button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
    33923428                button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
    3393                 button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
     3429                button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") +
    33943430                                                 getScaledAttribute(node, "w")))
    3395                 button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") + 
     3431                button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
    33963432                                                 getScaledAttribute(node, "h")))
    33973433                spunode.appendChild(button)
    33983434
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    34113447            button.setAttribute("name","playall")
    34123448            button.setAttribute("x0","%s" % getScaledAttribute(node, "x"))
    34133449            button.setAttribute("y0","%s" % getScaledAttribute(node, "y"))
    3414             button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") + 
     3450            button.setAttribute("x1","%s" % (getScaledAttribute(node, "x") +
    34153451                                             getScaledAttribute(node, "w")))
    34163452            button.setAttribute("y1","%s" % (getScaledAttribute(node, "y") +
    34173453                                             getScaledAttribute(node, "h")))
    def drawThemeItem(page, itemsonthispage, itemnum, menuitem, bgimage, draw,  
    34263462                # draw background if required
    34273463                paintBackground(bgimage, node)
    34283464
    3429                 paintButton(draw, bgimage, bgimagemask, node, infoDOM, 
    3430                             itemnum, page, itemsonthispage, chapternumber, 
     3465                paintButton(draw, bgimage, bgimagemask, node, infoDOM,
     3466                            itemnum, page, itemsonthispage, chapternumber,
    34313467                            chapterlist)
    34323468
    34333469                button = spumuxdom.createElement("button")
    def createMenu(screensize, screendpi, numberofitems):  
    36163652        bgimage.paste(overlayimage, (0,0), overlayimage)
    36173653
    36183654        #Save this menu image and its mask
    3619         bgimage.save(os.path.join(getTempPath(),"background-%s.jpg" % page),"JPEG", quality=99)
     3655        rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     3656        rgb_bgimage.save(os.path.join(getTempPath(),"background-%s.jpg" % page),"JPEG", quality=99)
     3657        del rgb_bgimage
    36203658        bgimagemask.save(os.path.join(getTempPath(),"backgroundmask-%s.png" % page),"PNG",quality=99,optimize=0,dpi=screendpi)
    36213659
    36223660        #now that the base background has been made and all the previews generated
    36233661        #we need to add the previews to the background
    3624         #Assumption: We assume that there is nothing in the location of where the items go 
     3662        #Assumption: We assume that there is nothing in the location of where the items go
    36253663        #(ie, no text on the images)
    36263664
    36273665        itemsonthispage = 0
    def createMenu(screensize, screendpi, numberofitems):  
    36543692                            del picture
    36553693                    previewitem+=1
    36563694                #bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.png" % (page, framenum)),"PNG",quality=100,optimize=0,dpi=screendpi)
    3657                 bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
     3695                rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     3696                rgb_bgimage.save(os.path.join(getTempPath(),"background-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
     3697                del rgb_bgimage
    36583698                framenum+=1
    36593699
    36603700        spumuxdom.documentElement.firstChild.firstChild.setAttribute("select",os.path.join(getTempPath(),"backgroundmask-%s.png" % page))
    def createChapterMenu(screensize, screendpi, numberofitems):  
    37693809
    37703810        #Extract the thumbnails
    37713811        chapterlist=createVideoChapters(page,itemsperpage,getLengthOfVideo(page),True)
    3772         chapterlist=string.split(chapterlist,",")
     3812        chapterlist=chapterlist.split(",")
    37733813
    37743814        #now need to preprocess the menu to see if any preview videos are required
    37753815        #This must be done on an individual basis since we do the resize as the
    def createChapterMenu(screensize, screendpi, numberofitems):  
    38133853            chapter+=1
    38143854
    38153855            drawThemeItem(page, itemsperpage, page, menuitem,
    3816                         overlayimage, draw, 
     3856                        overlayimage, draw,
    38173857                        bgimagemask, drawmask, highlightcolor,
    38183858                        spumuxdom, spunode,
    38193859                        999, chapter, chapterlist)
    def createChapterMenu(screensize, screendpi, numberofitems):  
    38213861        #Save this menu image and its mask
    38223862        bgimage=Image.open(backgroundfilename,"r").resize(screensize)
    38233863        bgimage.paste(overlayimage, (0,0), overlayimage)
    3824         bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s.jpg" % page),"JPEG", quality=99)
     3864        rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     3865        rgb_bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s.jpg" % page),"JPEG", quality=99)
     3866        del rgb_bgimage
    38253867
    38263868        bgimagemask.save(os.path.join(getTempPath(),"chaptermenumask-%s.png" % page),"PNG",quality=90,optimize=0)
    38273869
    def createChapterMenu(screensize, screendpi, numberofitems):  
    38503892                                bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]))
    38513893                            del picture
    38523894                    previewchapter+=1
    3853                 bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
     3895                rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     3896                rgb_bgimage.save(os.path.join(getTempPath(),"chaptermenu-%s-f%06d.jpg" % (page, framenum)),"JPEG",quality=99)
     3897                del rgb_bgimage
    38543898                framenum+=1
    38553899
    38563900        spumuxdom.documentElement.firstChild.firstChild.setAttribute("select",os.path.join(getTempPath(),"chaptermenumask-%s.png" % page))
    def createChapterMenu(screensize, screendpi, numberofitems):  
    38733917            aspect_ratio = '2'
    38743918        elif chaptermenuAspectRatio == "16:9":
    38753919            aspect_ratio = '3'
    3876         else: 
     3920        else:
    38773921            if getAspectRatioOfVideo(page) > aspectRatioThreshold:
    38783922                aspect_ratio = '3'
    38793923            else:
    def createDetailsPage(screensize, screendpi, numberofitems):  
    39714015        #Save this details image
    39724016        bgimage=Image.open(backgroundfilename,"r").resize(screensize)
    39734017        bgimage.paste(overlayimage, (0,0), overlayimage)
    3974         bgimage.save(os.path.join(getTempPath(),"details-%s.jpg" % itemnum),"JPEG", quality=99)
     4018        rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     4019        rgb_bgimage.save(os.path.join(getTempPath(),"details-%s.jpg" % itemnum),"JPEG", quality=99)
     4020        del rgb_bgimage
    39754021
    39764022        if haspreview == True:
    39774023            numframes=secondsToFrames(menulength)
    def createDetailsPage(screensize, screendpi, numberofitems):  
    39944040                        else:
    39954041                            bgimage.paste(picture, (previewx, previewy))
    39964042                        del picture
    3997                 bgimage.save(os.path.join(getTempPath(),"details-%s-f%06d.jpg" % (itemnum, framenum)),"JPEG",quality=99)
     4043                rgb_bgimage=bgimage.convert('RGB')  ### ticket #13306
     4044                rgb_bgimage.save(os.path.join(getTempPath(),"details-%s-f%06d.jpg" % (itemnum, framenum)),"JPEG",quality=99)
     4045                del rgb_bgimage
    39984046                framenum+=1
    39994047
    40004048
    def isMediaAVIFile(file):  
    40434091    return Magic=="RIFF"
    40444092
    40454093#############################################################
    4046 # checks to see if an audio stream need to be converted to ac3 
     4094# checks to see if an audio stream need to be converted to ac3
    40474095
    40484096def processAudio(folder):
    40494097    """encode audio to ac3 for better compression and compatability with NTSC players"""
    def selectStreams(folder):  
    41354183    for node in nodes:
    41364184        index = int(node.attributes["ffmpegindex"].value)
    41374185        lang = node.attributes["language"].value
    4138         format = string.upper(node.attributes["codec"].value)
     4186        format = node.attributes["codec"].value.upper()
    41394187        pid = int(node.attributes["id"].value)
    41404188        if lang == preferredlang1 and format == "AC3":
    41414189            if found:
    def selectStreams(folder):  
    41504198        for node in nodes:
    41514199            index = int(node.attributes["ffmpegindex"].value)
    41524200            lang = node.attributes["language"].value
    4153             format = string.upper(node.attributes["codec"].value)
     4201            format = node.attributes["codec"].value.upper()
    41544202            pid = int(node.attributes["id"].value)
    41554203            if lang == preferredlang1 and format == "MP2":
    41564204                if found:
    def selectStreams(folder):  
    41644212    if not found:
    41654213        for node in nodes:
    41664214            index = int(node.attributes["ffmpegindex"].value)
    4167             format = string.upper(node.attributes["codec"].value)
     4215            format = node.attributes["codec"].value.upper()
    41684216            pid = int(node.attributes["id"].value)
    41694217            if not found:
    41704218                audio1 = (index, format, pid, lang)
    def selectStreams(folder):  
    41834231        for node in nodes:
    41844232            index = int(node.attributes["ffmpegindex"].value)
    41854233            lang = node.attributes["language"].value
    4186             format = string.upper(node.attributes["codec"].value)
     4234            format = node.attributes["codec"].value.upper()
    41874235            pid = int(node.attributes["id"].value)
    41884236            if lang == preferredlang2 and format == "AC3":
    41894237                if found:
    def selectStreams(folder):  
    41984246            for node in nodes:
    41994247                index = int(node.attributes["ffmpegindex"].value)
    42004248                lang = node.attributes["language"].value
    4201                 format = string.upper(node.attributes["codec"].value)
     4249                format = node.attributes["codec"].value.upper()
    42024250                pid = int(node.attributes["id"].value)
    42034251                if lang == preferredlang2 and format == "MP2":
    42044252                    if found:
    def selectStreams(folder):  
    42124260        if not found:
    42134261            for node in nodes:
    42144262                index = int(node.attributes["ffmpegindex"].value)
    4215                 format = string.upper(node.attributes["codec"].value)
     4263                format = node.attributes["codec"].value.upper()
    42164264                pid = int(node.attributes["id"].value)
    42174265                if not found:
    42184266                    # make sure we don't choose the same stream as audio1
    def selectSubtitleStream(folder):  
    42664314    for node in nodes:
    42674315        index = int(node.attributes["ffmpegindex"].value)
    42684316        lang = node.attributes["language"].value
    4269         format = string.upper(node.attributes["codec"].value)
     4317        format = node.attributes["codec"].value.upper()
    42704318        pid = int(node.attributes["id"].value)
    42714319        if not found and lang == preferredlang1 and format == "dvbsub":
    42724320            subtitle = (index, format, pid, lang)
    def selectSubtitleStream(folder):  
    42774325        for node in nodes:
    42784326            index = int(node.attributes["ffmpegindex"].value)
    42794327            lang = node.attributes["language"].value
    4280             format = string.upper(node.attributes["codec"].value)
     4328            format = node.attributes["codec"].value.upper()
    42814329            pid = int(node.attributes["id"].value)
    42824330            if not found and lang == preferredlang2 and format == "dvbsub":
    42834331                subtitle = (index, format, pid, lang)
    def selectSubtitleStream(folder):  
    42874335    if not found:
    42884336        for node in nodes:
    42894337            index = int(node.attributes["ffmpegindex"].value)
    4290             format = string.upper(node.attributes["codec"].value)
     4338            format = node.attributes["codec"].value.upper()
    42914339            pid = int(node.attributes["id"].value)
    42924340            if not found:
    42934341                subtitle = (index, format, pid, lang)
    def getStreamList(folder):  
    44144462def isFileOkayForDVD(file, folder):
    44154463    """return true if the file is dvd compliant"""
    44164464
    4417     if not string.lower(getVideoCodec(folder)).startswith("mpeg2video"):
     4465    if not getVideoCodec(folder).lower().startswith("mpeg2video"):
    44184466        return False
    44194467
    4420 #    if string.lower(getAudioCodec(folder)) != "ac3" and encodeToAC3:
     4468
     4469#    if (getAudioCodec(folder)).lower() != "ac3" and encodeToAC3:
    44214470#        return False
    44224471
    44234472    videosize = getVideoSize(os.path.join(folder, "streaminfo.xml"))
    def processFile(file, folder, count):  
    44544503
    44554504#############################################################
    44564505# process a single file ready for burning using mythtranscode/mythreplex
    4457 # to cut and demux 
     4506# to cut and demux
    44584507
    44594508def doProcessFile(file, folder, count):
    44604509    """Process a single video/recording file ready for burning."""
    def doProcessFile(file, folder, count):  
    44944543        #can only use mythtranscode to cut commercials on mpeg2 files
    44954544        write("File type is '%s'" % getFileType(folder))
    44964545        write("Video codec is '%s'" % getVideoCodec(folder))
    4497         if string.lower(getVideoCodec(folder)).startswith("mpeg2video"):
     4546        if (getVideoCodec(folder)).lower().startswith("mpeg2video"):
    44984547            if file.attributes["usecutlist"].value == "1" and getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes":
    44994548                # Run from local file?
    45004549                if file.hasAttribute("localfilename"):
    def doProcessFile(file, folder, count):  
    45104559                    write("Failed to run mythtranscode to remove unwanted segments")
    45114560            else:
    45124561                #does the user always want to run recordings through mythtranscode?
    4513                 #may help to fix any errors in the file 
    4514                 if (alwaysRunMythtranscode == True or 
     4562                #may help to fix any errors in the file
     4563                if (alwaysRunMythtranscode == True or
    45154564                        (getFileType(folder) == "mpegts" and isFileOkayForDVD(file, folder))):
    45164565                    # Run from local file?
    45174566                    if file.hasAttribute("localfilename"):
    def doProcessFile(file, folder, count):  
    45274576                        write("Failed to run mythtranscode to fix any errors")
    45284577    else:
    45294578        #does the user always want to run mpeg2 files through mythtranscode?
    4530         #may help to fix any errors in the file 
     4579        #may help to fix any errors in the file
    45314580        write("File type is '%s'" % getFileType(folder))
    45324581        write("Video codec is '%s'" % getVideoCodec(folder))
    45334582
    45344583        if (alwaysRunMythtranscode == True and
    4535                 string.lower(getVideoCodec(folder)).startswith("mpeg2video") and
     4584                getVideoCodec(folder).lower().startswith("mpeg2video") and
    45364585                isFileOkayForDVD(file, folder)):
    45374586            if file.hasAttribute("localfilename"):
    45384587                localfile = file.attributes["localfilename"].value
    def doProcessFile(file, folder, count):  
    45794628                mediafile = -1
    45804629                chanid = getText(infoDOM.getElementsByTagName("chanid")[0])
    45814630                starttime = getText(infoDOM.getElementsByTagName("starttime")[0])
    4582                 usecutlist = (file.attributes["usecutlist"].value == "1" and 
     4631                usecutlist = (file.attributes["usecutlist"].value == "1" and
    45834632                            getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes")
    45844633            else:
    45854634                chanid = -1
    def doProcessFile(file, folder, count):  
    46124661            else:
    46134662                profile = defaultEncodingProfile
    46144663
    4615             #do the re-encode 
     4664            #do the re-encode
    46164665            encodeVideoToMPEG2(mediafile, os.path.join(folder, "newfile2.mpg"), video,
    46174666                            audio1, audio2, aspectratio, profile)
    46184667            mediafile = os.path.join(folder, 'newfile2.mpg')
    def doProcessFileProjectX(file, folder, count):  
    46774726
    46784727    #As part of this routine we need to pre-process the video this MAY mean:
    46794728    #1. encoding to mpeg2 (if its an avi for instance or isn't DVD compatible)
    4680     #2. removing commercials/cleaning up mpeg2 stream 
     4729    #2. removing commercials/cleaning up mpeg2 stream
    46814730    #3. selecting audio track(s) to use and encoding audio from mp2 into ac3
    46824731    #4. de-multiplexing into video and audio steams
    46834732
    def doProcessFileProjectX(file, folder, count):  
    47334782                mediafile = -1
    47344783                chanid = getText(infoDOM.getElementsByTagName("chanid")[0])
    47354784                starttime = getText(infoDOM.getElementsByTagName("starttime")[0])
    4736                 usecutlist = (file.attributes["usecutlist"].value == "1" and 
     4785                usecutlist = (file.attributes["usecutlist"].value == "1" and
    47374786                            getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes")
    47384787            else:
    47394788                chanid = -1
    def doProcessFileProjectX(file, folder, count):  
    47664815            else:
    47674816                profile = defaultEncodingProfile
    47684817
    4769             #do the re-encode 
     4818            #do the re-encode
    47704819            encodeVideoToMPEG2(mediafile, os.path.join(folder, "newfile2.mpg"), video,
    47714820                            audio1, audio2, aspectratio, profile)
    47724821            mediafile = os.path.join(folder, 'newfile2.mpg')
    def doProcessFileProjectX(file, folder, count):  
    47874836    # now attempt to split the source file into video and audio parts
    47884837    # using projectX
    47894838
    4790     # If this is an mpeg2 myth recording and there is a cut list available and the 
     4839    # If this is an mpeg2 myth recording and there is a cut list available and the
    47914840    # user wants to use it run projectx to cut out commercials etc
    47924841    if file.attributes["type"].value == "recording":
    47934842        if file.attributes["usecutlist"].value == "1" and getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes":
    def processJob(job):  
    49955044                filecount+=1
    49965045                folder=getItemTempPath(filecount)
    49975046                #Multiplex this file
    4998                 #(This also removes non-required audio feeds inside mpeg streams 
     5047                #(This also removes non-required audio feeds inside mpeg streams
    49995048                #(through re-multiplexing) we only take 1 video and 1 or 2 audio streams)
    50005049                pid=multiplexMPEGStream(os.path.join(folder,'stream.mv2'),
    50015050                        os.path.join(folder,'stream0'),
    def main():  
    51665215    videopath = defaultsettings.get("VideoStartupDir", None)
    51675216    gallerypath = defaultsettings.get("GalleryDir", None)
    51685217    musicpath = defaultsettings.get("MusicLocation", None)
    5169     videomode = string.lower(defaultsettings["MythArchiveVideoFormat"])
     5218    videomode = defaultsettings["MythArchiveVideoFormat"].lower()
    51705219    temppath = os.path.join(defaultsettings["MythArchiveTempDir"], "work")
    51715220    logpath = os.path.join(defaultsettings["MythArchiveTempDir"], "logs")
    51725221    write("temppath: " + temppath)
    def main():  
    52335282        try:
    52345283            fd = os.open(lckpath, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
    52355284            try:
    5236                 os.write(fd, "%d\n" % os.getpid())
     5285                os.write(fd, b"%d\n" % os.getpid())
    52375286                os.close(fd)
    52385287            except:
    52395288                os.remove(lckpath)
    52405289                raise
    5241         except OSError, e:
     5290        except OSError as e:
    52425291            if e.errno == errno.EEXIST:
    52435292                write("Lock file exists -- already running???")
    52445293                sys.exit(1)
    def main():  
    52815330            # remove our lock file
    52825331            os.remove(lckpath)
    52835332
    5284             # make sure the files we created are read/writable by all 
     5333            # make sure the files we created are read/writable by all
    52855334            os.system("chmod -R a+rw-x+X %s" % defaultsettings["MythArchiveTempDir"])
    52865335    except SystemExit:
    52875336        write("Terminated")