64 VERSION=
"0.2.20200122-1"
69 debug_keeptempfiles =
False
77 debug_secondrunthrough =
False
80 defaultEncodingProfile =
"SP"
87 addCutlistChapters =
False
102 import xml.dom.minidom
103 from PIL
import Image
104 from PIL
import ImageDraw
105 from PIL
import ImageFont
106 from PIL
import ImageColor
110 from fcntl
import ioctl
121 CDS_DRIVE_NOT_READY = 3
125 CDROM_DRIVE_STATUS = 0x5326
126 CDROM_LOCKDOOR = 0x5329
128 from shutil
import copy
131 from MythTV
import datetime
132 from MythTV.altdict
import OrdDict
145 dvdPALHalfD1=
"352x576"
146 dvdNTSCHalfD1=
"352x480"
147 dvdPALD1=
"%sx%s" % (dvdPAL[0],dvdPAL[1])
148 dvdNTSCD1=
"%sx%s" % (dvdNTSC[0],dvdNTSC[1])
157 aspectRatioThreshold = 1.4
175 alwaysRunMythtranscode =
False
176 copyremoteFiles =
False
179 clearArchiveTable =
True
184 mainmenuAspectRatio =
"16:9"
188 chaptermenuAspectRatio =
"Video"
191 chapterLength = 5 * 60;
198 progressfile = codecs.open(
"/dev/null",
'w',
'utf-8')
201 dvddrivepath =
"/dev/dvd"
226 MVID = MythTV.MythVideo(db=DB)
229 configHostname = DB.gethostname()
235 oldlocale = os.environ[
"LC_ALL"]
238 os.putenv(
"LC_ALL",
"en_US.UTF-8")
250 sys.stdout.write(
"Using simple_fix_rtl\n")
251 fix_rtl = simple_fix_rtl
253 sys.stdout.write(
"Using pyfribidi.log2vis\n")
254 fix_rtl = pyfribidi.log2vis
260 def __init__(self, name=None, fontFile=None, size=19, color="white", effect="normal", shadowColor="black", shadowSize=1):
271 if self.
font is None:
277 if self.
font is None:
285 image = Image.new(
"RGBA", (textwidth + (self.
shadowSize * 2), textheight), (0,0,0,0))
286 draw = ImageDraw.ImageDraw(image)
288 if self.
effect ==
"shadow":
290 draw.text((0,0), text, font=self.
font, fill=color)
291 elif self.
effect ==
"outline":
298 draw.text((0,0), text, font=self.
font, fill=color)
300 bbox = image.getbbox()
301 image = image.crop(bbox)
308 """Simple place to channel all text output through"""
310 if sys.version_info == 2:
311 sys.stdout.write((text +
"\n").encode(
"utf-8",
"replace"))
313 sys.stdout.write(text +
"\n")
316 if progress ==
True and progresslog !=
"":
317 progressfile.write(time.strftime(
"%Y-%m-%d %H:%M:%S ") + text +
"\n")
324 """Display an error message and exit app"""
326 write(
"ERROR: " + msg)
327 write(
"See mythburn.log for more information.")
331 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
338 """Display a warning message"""
340 write(
"WARNING: " + msg)
348 """Return the input string with single quotes escaped."""
349 return str.replace(
"'",
"'\"'\"'")
355 """This is the folder where all temporary files will be created."""
362 """return the number of CPUs"""
364 cpustat = codecs.open(
"/proc/cpuinfo",
'r',
'utf-8')
365 cpudata = cpustat.readlines()
370 tokens = line.split()
372 if tokens[0] ==
"processor":
378 write(
"Found %d CPUs" % cpucount)
386 """This is the folder where all encoder profile files are located."""
387 return os.path.join(sharepath,
"mytharchive",
"encoder_profiles")
393 """Returns true/false if a given file or path exists."""
394 return os.path.exists( file )
400 arg = arg.replace(
'"',
'\\"')
401 arg = arg.replace(
'`',
'\\`')
408 """Returns the text contents from a given XML element."""
409 if node.childNodes.length>0:
410 return node.childNodes[0].data
418 """Find a theme file - first look in the specified theme directory then look in the
419 shared music and image directories"""
420 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"themes", theme, file)):
421 return os.path.join(sharepath,
"mytharchive",
"themes", theme, file)
423 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"images", file)):
424 return os.path.join(sharepath,
"mytharchive",
"images", file)
426 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"intro", file)):
427 return os.path.join(sharepath,
"mytharchive",
"intro", file)
429 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"music", file)):
430 return os.path.join(sharepath,
"mytharchive",
"music", file)
432 fatalError(
"Cannot find theme file '%s' in theme '%s'" % (file, theme))
438 return os.path.join(sharepath,
"fonts", fontname)
444 return os.path.join(
getTempPath(),
"%s" % itemnumber)
452 write(
"Looking for: " + file)
459 if videomode==
"ntsc":
460 return videoresolution==(720,480)
or videoresolution==(704,480)
or videoresolution==(352,480)
or videoresolution==(352,240)
462 return videoresolution==(720,576)
or videoresolution==(704,576)
or videoresolution==(352,576)
or videoresolution==(352,288)
468 """Does what it says on the tin!."""
469 for root, dirs, deletefiles
in os.walk(folder, topdown=
False):
470 for name
in deletefiles:
471 os.remove(os.path.join(root, name))
477 for root, dirs, files
in os.walk(folder, topdown=
False):
479 os.remove(os.path.join(root, name))
481 if os.path.islink(os.path.join(root, name)):
482 os.remove(os.path.join(root, name))
484 os.rmdir(os.path.join(root, name))
490 """Checks to see if the user has cancelled this run"""
491 if os.path.exists(os.path.join(logpath,
"mythburncancel.lck")):
492 os.remove(os.path.join(logpath,
"mythburncancel.lck"))
494 write(
"Job has been cancelled at users request")
505 result = os.system(command.encode(
'utf-8'))
507 if os.WIFEXITED(result):
508 result = os.WEXITSTATUS(result)
516 """Convert a time in seconds to a frame position"""
518 framespersecond=frameratePAL
520 framespersecond=framerateNTSC
522 frames=int(seconds * framespersecond)
528 def encodeMenu(background, tempvideo, music, musiclength, tempmovie, xmlfile, finaloutput, aspectratio):
530 framespersecond=frameratePAL
532 framespersecond=framerateNTSC
534 totalframes=int(musiclength * framespersecond)
536 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" \
540 fatalError(
"Failed while running jpeg2yuv - %s" % command)
545 fatalError(
"Failed while running mplex - %s" % command)
551 fatalError(
"Failed while running spumux - %s" % command)
553 os.rename(tempmovie, finaloutput)
555 if os.path.exists(tempvideo):
557 if os.path.exists(tempmovie):
565 """Returns the XML node for the given encoding profile"""
570 if videomode ==
"ntsc":
571 filename = os.path.expanduser(
"~/.mythtv/MythArchive/ffmpeg_dvd_ntsc.xml")
573 filename = os.path.expanduser(
"~/.mythtv/MythArchive/ffmpeg_dvd_pal.xml")
575 if not os.path.exists(filename):
577 if videomode ==
"ntsc":
582 write(
"Using encoder profiles from %s" % filename)
584 DOM = xml.dom.minidom.parse(filename)
587 if DOM.documentElement.tagName !=
"encoderprofiles":
588 fatalError(
"Profile xml file doesn't look right (%s)" % filename)
590 profiles = DOM.getElementsByTagName(
"profile")
591 for node
in profiles:
592 if getText(node.getElementsByTagName(
"name")[0]) == profile:
593 write(
"Encoding profile (%s) found" % profile)
596 write(
'WARNING: Encoding profile "' + profile +
'" not found.')
597 write(
'Using default profile "' + defaultEncodingProfile +
'".')
598 for node
in profiles:
599 if getText(node.getElementsByTagName(
"name")[0]) == defaultEncodingProfile:
600 write(
"Encoding profile (%s) found" % defaultEncodingProfile)
603 fatalError(
'Neither encoding profile "' + profile +
'" nor default enocding profile "' + defaultEncodingProfile +
'" found. Giving up.')
610 """Loads the XML file from disk for a specific theme"""
613 themeDOM = xml.dom.minidom.parse(
getThemeFile(theme,
"theme.xml") )
615 if themeDOM.documentElement.tagName !=
"mythburntheme":
616 fatalError(
"Theme xml file doesn't look right (%s)" % theme)
623 """Returns the length of a video file (in seconds)"""
626 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
629 if infoDOM.documentElement.tagName !=
"file":
631 file = infoDOM.getElementsByTagName(
"file")[0]
632 if file.attributes[
"cutduration"].value !=
'N/A':
633 duration = int(file.attributes[
"cutduration"].value)
644 """Returns the audio bitrate and no of channels for a file from its streaminfo.xml"""
647 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
650 if infoDOM.documentElement.tagName !=
"file":
651 fatalError(
"Stream info file doesn't look right (%s)" % os.path.join(folder,
'streaminfo.xml'))
652 audio = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"audio")[0]
654 samplerate = audio.attributes[
"samplerate"].value
655 channels = audio.attributes[
"channels"].value
657 return (samplerate, channels)
664 """Returns the video resolution, fps and aspect ratio for the video file from the streaminfo.xml file"""
667 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
670 if infoDOM.documentElement.tagName !=
"file":
672 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
674 if video.attributes[
"aspectratio"].value !=
'N/A':
675 aspect_ratio = video.attributes[
"aspectratio"].value
677 aspect_ratio =
"1.77778"
679 videores = video.attributes[
"width"].value +
'x' + video.attributes[
"height"].value
680 fps = video.attributes[
"fps"].value
688 if float(fr) != float(fps):
689 write(
"WARNING: frames rates do not match")
690 write(
"The frame rate for %s should be %s but the stream info file "
691 "report a fps of %s" % (videomode, fr, fps))
694 return (videores, fps, aspect_ratio)
700 """Returns the aspect ratio of the video file (1.333, 1.778, etc)"""
703 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
706 if infoDOM.documentElement.tagName !=
"file":
708 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
709 if video.attributes[
"aspectratio"].value !=
'N/A':
710 aspect_ratio = float(video.attributes[
"aspectratio"].value)
712 aspect_ratio = 1.77778;
713 write(
"aspect ratio is: %s" % aspect_ratio)
720 """Returns the sync offset between the video and first audio stream"""
724 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
727 if infoDOM.documentElement.tagName !=
"file":
730 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
731 video_start = float(video.attributes[
"start_time"].value)
733 audio = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"audio")[0]
734 audio_start = float(audio.attributes[
"start_time"].value)
739 sync_offset = int((video_start - audio_start) * 1000)
750 minutes = int(duration / 60)
751 seconds = duration % 60
752 hours = int(minutes / 60)
755 return '%02d:%02d:%02d' % (hours, minutes, seconds)
761 sec = int(frame / fps)
762 frame = frame - int(sec * fps)
768 return '%02d:%02d:%02d' % (hour, mins, sec)
774 parts = formatedtime.split(
':')
782 return sec + (mins * 60) + (hour * 60 * 60)
789 """Returns numofchapters chapter marks even spaced through a certain time period"""
792 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
793 thumblistNode = infoDOM.getElementsByTagName(
"thumblist")
794 if thumblistNode.length > 0:
795 thumblist =
getText(thumblistNode[0])
796 write(
"Using user defined thumb images - %s" % thumblist)
800 segment=int(lengthofvideo / numofchapters)
802 write(
"Video length is %s seconds. Each chapter will be %s seconds" % (lengthofvideo,segment))
809 while count<=numofchapters:
810 chapters.append(time.strftime(
"%H:%M:%S",time.gmtime(starttime)))
813 if thumboffset < segment:
814 thumbList.append(str(thumboffset))
816 thumbList.append(str(starttime))
818 thumbList.append(str(starttime))
823 chapters =
','.join(chapters)
824 thumbList =
','.join(thumbList)
826 if getthumbnails==
True:
836 """Returns chapter marks at cut list ends,
837 or evenly spaced chapters 'segment' seconds through the file"""
840 if addCutlistChapters ==
True:
844 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
845 chapterlistNode = infoDOM.getElementsByTagName(
"chapterlist")
846 if chapterlistNode.length > 0:
847 chapterlist =
getText(chapterlistNode[0])
848 write(
"Using commercial end marks - %s" % chapterlist)
851 if lengthofvideo < segment:
854 numofchapters = lengthofvideo // segment + 1;
855 chapters =
"00:00:00"
858 while count <= numofchapters:
860 chapters +=
"," + time.strftime(
"%H:%M:%S", time.gmtime(starttime))
863 write(
"Fixed length chapters: %s" % chapters)
871 """Reads settings from MythTV database"""
873 write(
"Obtaining MythTV settings from MySQL database for hostname " + configHostname)
876 sqlstatement=
"""SELECT value, data FROM settings WHERE value IN(
880 OR (hostname=%s AND value IN(
884 'MythArchiveVideoFormat',
885 'MythArchiveTempDir',
886 'MythArchiveMplexCmd',
887 'MythArchiveDvdauthorCmd',
888 'MythArchiveMkisofsCmd',
889 'MythArchiveM2VRequantiserCmd',
890 'MythArchiveMpg123Cmd',
891 'MythArchiveProjectXCmd',
892 'MythArchiveDVDLocation',
893 'MythArchiveGrowisofsCmd',
894 'MythArchiveJpeg2yuvCmd',
895 'MythArchiveSpumuxCmd',
896 'MythArchiveMpeg2encCmd',
897 'MythArchiveCopyRemoteFiles',
898 'MythArchiveAlwaysUseMythTranscode',
899 'MythArchiveUseProjectX',
900 'MythArchiveAddSubtitles',
901 'MythArchiveUseFIFO',
902 'MythArchiveMainMenuAR',
903 'MythArchiveChapterMenuAR',
904 'MythArchiveDateFormat',
905 'MythArchiveTimeFormat',
906 'MythArchiveClearArchiveTable',
907 'MythArchiveDriveSpeed',
914 cursor.execute(sqlstatement, (configHostname,))
916 result = cursor.fetchall()
919 for i
in range(len(result)):
920 cfg[result[i][0]] = result[i][1]
923 if not "MythArchiveTempDir" in cfg:
924 fatalError(
"Can't find the setting for the temp directory. \nHave you run setup in the frontend?")
931 host = DB.gethostname()
932 DB.settings[host][name] = data
938 ''' Remove all archive items from the archiveitems DB table'''
940 write(
"Removing all archive items from the archiveitems DB table")
942 cursor.execute(
"DELETE FROM archiveitems")
954 if options.length == 0:
955 fatalError(
"Trying to read the options from the job file but none found?")
958 doburn = options.attributes[
"doburn"].value !=
'0'
959 docreateiso = options.attributes[
"createiso"].value !=
'0'
960 erasedvdrw = options.attributes[
"erasedvdrw"].value !=
'0'
961 mediatype = int(options.attributes[
"mediatype"].value)
962 savefilename = options.attributes[
"savefilename"].value
964 write(
"Options - mediatype = %d, doburn = %d, createiso = %d, erasedvdrw = %d" \
965 % (mediatype, doburn, docreateiso, erasedvdrw))
966 write(
" savefilename = '%s'" % savefilename)
971 def expandItemText(infoDOM, text, itemnumber, pagenumber, keynumber,chapternumber, chapterlist ):
972 """Replaces keywords in a string with variables from the XML and filesystem"""
973 text=text.replace(
"%page",
"%s" % pagenumber)
976 if getText( infoDOM.getElementsByTagName(
"coverfile")[0]) ==
"":
977 text=text.replace(
"%thumbnail", os.path.join(
getItemTempPath(itemnumber),
"title.jpg"))
979 text=text.replace(
"%thumbnail",
getText( infoDOM.getElementsByTagName(
"coverfile")[0]) )
981 text=text.replace(
"%itemnumber",
"%s" % itemnumber )
982 text=text.replace(
"%keynumber",
"%s" % keynumber )
984 text=text.replace(
"%title",
getText( infoDOM.getElementsByTagName(
"title")[0]) )
985 text=text.replace(
"%subtitle",
getText( infoDOM.getElementsByTagName(
"subtitle")[0]) )
986 text=text.replace(
"%description",
getText( infoDOM.getElementsByTagName(
"description")[0]) )
987 text=text.replace(
"%type",
getText( infoDOM.getElementsByTagName(
"type")[0]) )
989 text=text.replace(
"%recordingdate",
getText( infoDOM.getElementsByTagName(
"recordingdate")[0]) )
990 text=text.replace(
"%recordingtime",
getText( infoDOM.getElementsByTagName(
"recordingtime")[0]) )
994 text=text.replace(
"%myfolder",
getThemeFile(themeName,
""))
997 text=text.replace(
"%chapternumber",
"%s" % chapternumber )
998 text=text.replace(
"%chaptertime",
"%s" % chapterlist[chapternumber - 1] )
999 text=text.replace(
"%chapterthumbnail", os.path.join(
getItemTempPath(itemnumber),
"chapter-%s.jpg" % chapternumber))
1007 """ Returns a value taken from attribute in node scaled for the current video mode"""
1009 if videomode ==
"pal" or attribute ==
"x" or attribute ==
"w":
1010 return int(node.attributes[attribute].value)
1012 return int(float(node.attributes[attribute].value) / 1.2)
1018 """Based on http://mail.python.org/pipermail/image-sig/2004-December/003064.html"""
1026 words = text.split()
1032 thistext = lines[line]
1034 innerFinished =
False
1035 while not innerFinished:
1039 if drawer.textsize(
' '.join(thistext),font.getFont())[0] > containerWidth:
1043 if str(thistext).
find(
' ') != -1:
1044 newline.insert(0,thistext.pop(-1))
1047 innerFinished =
True
1049 innerFinished =
True
1050 if len(newline) > 0:
1051 lines.append(newline)
1057 tmp.append(
fix_rtl(
' '.join(i) ) )
1065 if node.hasAttribute(
"bgcolor"):
1066 bgcolor = node.attributes[
"bgcolor"].value
1071 r,g,b = ImageColor.getrgb(bgcolor)
1073 if node.hasAttribute(
"bgalpha"):
1074 a = int(node.attributes[
"bgalpha"].value)
1078 image.paste((r, g, b, a), (x, y, x + w, y + h))
1084 def paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
1085 itemsonthispage, chapternumber, chapterlist):
1087 imagefilename =
getThemeFile(themeName, node.attributes[
"filename"].value)
1089 fatalError(
"Cannot find image for menu button (%s)." % imagefilename)
1090 maskimagefilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
1092 fatalError(
"Cannot find mask image for menu button (%s)." % maskimagefilename)
1094 picture = Image.open(imagefilename,
"r").resize(
1096 picture = picture.convert(
"RGBA")
1102 textnode = node.getElementsByTagName(
"textnormal")
1103 if textnode.length > 0:
1104 textnode = textnode[0]
1105 text =
expandItemText(infoDOM,textnode.attributes[
"value"].value,
1106 itemnum, page, itemsonthispage,
1107 chapternumber,chapterlist)
1110 paintText(draw, bgimage, text, textnode)
1114 write(
"Added button image %s" % imagefilename)
1116 picture = Image.open(maskimagefilename,
"r").resize(
1118 picture = picture.convert(
"RGBA")
1124 textnode = node.getElementsByTagName(
"textselected")
1125 if textnode.length > 0:
1126 textnode = textnode[0]
1127 text =
expandItemText(infoDOM, textnode.attributes[
"value"].value,
1128 itemnum, page, itemsonthispage,
1129 chapternumber, chapterlist)
1130 textImage = Image.new(
"RGBA",picture.size)
1131 textDraw = ImageDraw.Draw(textImage)
1134 paintText(textDraw, textImage, text, textnode,
"white",
1141 (width, height) = textImage.size
1142 for y
in range(height):
1143 for x
in range(width):
1144 if textImage.getpixel((x,y)) < (100, 100, 100, 255):
1145 textImage.putpixel((x,y), (0, 0, 0, 0))
1147 textImage.putpixel((x,y), (255, 255, 255, 255))
1149 if textnode.hasAttribute(
"colour"):
1150 color = textnode.attributes[
"colour"].value
1151 elif textnode.hasAttribute(
"color"):
1152 color = textnode.attributes[
"color"].value
1156 bgimagemask.paste(color,
1161 del text, textImage, textDraw
1168 x = None, y = None, width = None, height = None):
1169 """Takes a piece of text and draws it onto an image inside a bounding box."""
1178 font = themeFonts[node.attributes[
"font"].value]
1181 if node.hasAttribute(
"colour"):
1182 color = node.attributes[
"colour"].value
1183 elif node.hasAttribute(
"color"):
1184 color = node.attributes[
"color"].value
1188 if node.hasAttribute(
"halign"):
1189 halign = node.attributes[
"halign"].value
1190 elif node.hasAttribute(
"align"):
1191 halign = node.attributes[
"align"].value
1195 if node.hasAttribute(
"valign"):
1196 valign = node.attributes[
"valign"].value
1200 if node.hasAttribute(
"vindent"):
1201 vindent = int(node.attributes[
"vindent"].value)
1205 if node.hasAttribute(
"hindent"):
1206 hindent = int(node.attributes[
"hindent"].value)
1210 lines =
intelliDraw(draw, text, font, width - (hindent * 2))
1214 textImage = font.drawText(lines[0])
1215 h = int(textImage.size[1] * 1.1)
1218 if (j * h) < (height - (vindent * 2) - h):
1219 textImage = font.drawText(i, color)
1220 write(
"Wrapped text = " + i )
1222 if halign ==
"left":
1224 elif halign ==
"center" or halign ==
"centre":
1225 xoffset = (width // 2) - (textImage.size[0] // 2)
1226 elif halign ==
"right":
1227 xoffset = width - textImage.size[0] - hindent
1233 elif valign ==
"center" or halign ==
"centre":
1234 yoffset = (height // 2) - (textImage.size[1] // 2)
1235 elif valign ==
"bottom":
1236 yoffset = height - textImage.size[1] - vindent
1240 image.paste(textImage, (x + xoffset,y + yoffset + j * h), textImage)
1242 write(
"Wrapped text = " + i )
1249 def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):
1250 """Paste the image specified in the filename into the specified image"""
1253 write(
"Image file (%s) does not exist" % filename)
1256 picture = Image.open(filename,
"r")
1261 (imgw, imgh) = picture.size
1262 write(
"Image (%s, %s) into space of (%s, %s) at (%s, %s)" % (imgw, imgh, w, h, xpos, ypos),
False)
1265 if imageDom.hasAttribute(
"stretch"):
1266 if imageDom.attributes[
"stretch"].value ==
"True":
1275 if float(w)/imgw < float(h)/imgh:
1279 if imageDom.hasAttribute(
"valign"):
1280 valign = imageDom.attributes[
"valign"].value
1284 if valign ==
"bottom":
1286 if valign ==
"center":
1287 ypos += (h - imgh)//2
1292 if imageDom.hasAttribute(
"halign"):
1293 halign = imageDom.attributes[
"halign"].value
1297 if halign ==
"right":
1299 if halign ==
"center":
1300 xpos += (w - imgw)//2
1302 write(
"Image resized to (%s, %s) at (%s, %s)" % (imgw, imgh, xpos, ypos),
False)
1303 picture = picture.resize((imgw, imgh))
1304 picture = picture.convert(
"RGBA")
1307 maskpicture = Image.open(maskfilename,
"r").resize((imgw, imgh))
1308 maskpicture = maskpicture.convert(
"RGBA")
1310 maskpicture = picture
1312 destimage.paste(picture, (xpos, ypos), maskpicture)
1317 write (
"Added image %s" % filename)
1329 if getText(node.attributes[
"static"]) ==
"False":
1331 boundarybox =
getScaledAttribute(node,
"x"), boundarybox[1], boundarybox[2], boundarybox[3]
1334 boundarybox = boundarybox[0],
getScaledAttribute(node,
"y"), boundarybox[2], boundarybox[3]
1341 boundarybox = boundarybox[0], boundarybox[1], boundarybox[2], \
1353 nodelistfonts = themeDOM.getElementsByTagName(
"font")
1356 for node
in nodelistfonts:
1359 if node.hasAttribute(
"name"):
1360 name = node.attributes[
"name"].value
1362 name = str(fontnumber)
1366 if node.hasAttribute(
"color"):
1367 color = node.attributes[
"color"].value
1371 if node.hasAttribute(
"effect"):
1372 effect = node.attributes[
"effect"].value
1376 if node.hasAttribute(
"shadowsize"):
1377 shadowsize = int(node.attributes[
"shadowsize"].value)
1381 if node.hasAttribute(
"shadowcolor"):
1382 shadowcolor = node.attributes[
"shadowcolor"].value
1384 shadowcolor =
"black"
1387 fontsize, color, effect, shadowcolor, shadowsize)
1396 outputfile = os.path.join(folder,
"info.xml")
1397 impl = xml.dom.minidom.getDOMImplementation()
1398 infoDOM = impl.createDocument(
None,
"fileinfo",
None)
1399 top_element = infoDOM.documentElement
1401 data = OrdDict(((
'chanid',
''),
1402 (
'type',
''), (
'filename',
''),
1403 (
'title',
''), (
'recordingdate',
''),
1404 (
'recordingtime',
''), (
'subtitle',
''),
1405 (
'description',
''), (
'rating',
''),
1406 (
'coverfile',
''), (
'cutlist',
'')))
1409 details = file.getElementsByTagName(
"details")
1410 if details.length > 0:
1411 data.type = file.attributes[
"type"].value
1412 data.filename = file.attributes[
"filename"].value
1413 data.title = details[0].attributes[
"title"].value
1414 data.recordingdate = details[0].attributes[
"startdate"].value
1415 data.recordingtime = details[0].attributes[
"starttime"].value
1416 data.subtitle = details[0].attributes[
"subtitle"].value
1417 data.description =
getText(details[0])
1420 if file.attributes[
"type"].value==
"recording":
1421 filename = file.attributes[
"filename"].value
1423 rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
1424 except StopIteration:
1425 fatalError(
"Failed to get recording details from the DB for %s" % filename)
1427 data.chanid = rec.chanid
1428 data.recordingtime = rec.starttime.isoformat()
1429 data.recordingdate = rec.starttime.isoformat()
1431 cutlist = rec.markup.getcutlist()
1433 data.hascutlist =
'yes'
1434 if file.attributes[
"usecutlist"].value ==
"0" and addCutlistChapters ==
True:
1435 chapterlist = [
'00:00:00']
1439 data.chapterlist =
','.join(chapterlist)
1441 data.hascutlist =
'no'
1443 elif file.attributes[
"type"].value==
"recording":
1444 filename = file.attributes[
"filename"].value
1446 rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
1447 except StopIteration:
1448 fatalError(
"Failed to get recording details from the DB for %s" % filename)
1450 write(
" " + rec.title)
1451 data.type = file.attributes[
"type"].value
1452 data.filename = filename
1453 data.title = rec.title
1454 data.recordingdate = rec.progstart.strftime(dateformat)
1455 data.recordingtime = rec.progstart.strftime(timeformat)
1456 data.subtitle = rec.subtitle
1457 data.description = rec.description
1458 data.rating = str(rec.stars)
1459 data.chanid = rec.chanid
1460 data.starttime = rec.starttime.utcisoformat()
1462 cutlist = rec.markup.getcutlist()
1464 data.hascutlist =
'yes'
1465 if file.attributes[
"usecutlist"].value ==
"0" and addCutlistChapters ==
True:
1466 chapterlist = [
'00:00:00']
1470 data.chapterlist =
','.join(chapterlist)
1472 data.hascutlist =
'no'
1474 elif file.attributes[
"type"].value==
"video":
1475 filename = file.attributes[
"filename"].value
1477 vid = next(MVID.searchVideos(file=filename))
1478 except StopIteration:
1479 vid = Video.fromFilename(filename)
1481 data.type = file.attributes[
"type"].value
1482 data.filename = filename
1483 data.title = vid.title
1485 if vid.year != 1895:
1486 data.recordingdate =
unicode(vid.year)
1488 data.subtitle = vid.subtitle
1490 if (vid.plot
is not None)
and (vid.plot !=
'None'):
1491 data.description = vid.plot
1493 data.rating = str(vid.userrating)
1496 data.coverfile = vid.coverfile
1498 elif file.attributes[
"type"].value==
"file":
1499 data.type = file.attributes[
"type"].value
1500 data.filename = file.attributes[
"filename"].value
1501 data.title = file.attributes[
"filename"].value
1504 thumbs = file.getElementsByTagName(
"thumbimages")
1505 if thumbs.length > 0:
1507 thumbs = file.getElementsByTagName(
"thumb")
1511 for thumb
in thumbs:
1512 caption = thumb.attributes[
"caption"].value
1513 frame = thumb.attributes[
"frame"].value
1514 filename = thumb.attributes[
"filename"].value
1515 if caption !=
"Title":
1516 thumblist.append(
frameToTime(int(frame), float(fps)))
1519 copy(filename, folder)
1521 data.thumblist =
','.join(thumblist)
1523 for k,v
in list(data.items()):
1524 write(
"Node = %s, Data = %s" % (k, v))
1525 node = infoDOM.createElement(k)
1532 node.appendChild(infoDOM.createTextNode(
unicode(v)))
1533 top_element.appendChild(node)
1535 WriteXMLToFile (infoDOM, outputfile)
1543 f=open(filename,
'w')
1545 if sys.hexversion >= 0x03000000:
1546 f.write(myDOM.toprettyxml(indent=
" ", encoding=
"UTF-8").decode())
1547 elif sys.hexversion >= 0x020703F0:
1548 f.write(myDOM.toprettyxml(indent=
" ", encoding=
"UTF-8"))
1550 f.write(myDOM.toxml(encoding=
"UTF-8"))
1559 """Pre-process a single video/recording file."""
1561 write(
"Pre-processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
1569 if file.attributes[
"type"].value ==
"recording":
1570 mediafile = file.attributes[
"filename"].value
1571 elif file.attributes[
"type"].value ==
"video":
1572 mediafile = os.path.join(videopath, file.attributes[
"filename"].value)
1573 elif file.attributes[
"type"].value ==
"file":
1574 mediafile = file.attributes[
"filename"].value
1576 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
1578 if file.hasAttribute(
"localfilename"):
1579 mediafile = file.attributes[
"localfilename"].value
1582 fatalError(
"Source file does not exist: " + mediafile)
1585 copy(os.path.join(folder,
"streaminfo.xml"), os.path.join(folder,
"streaminfo_orig.xml"))
1589 videosize =
getVideoSize(os.path.join(folder,
"streaminfo.xml"))
1591 write(
"Video resolution is %s by %s" % (videosize[0], videosize[1]))
1596 def encodeAudio(format, sourcefile, destinationfile, deletesourceafterencode):
1597 write(
"Encoding audio to "+format)
1599 cmd =
"mythffmpeg -v 0 -y "
1602 cmd +=
"-threads %d " % cpuCount
1608 fatalError(
"Failed while running mythffmpeg to re-encode the audio to ac3\n"
1609 "Command was %s" % cmd)
1611 fatalError(
"Unknown encodeAudio format " + format)
1613 if deletesourceafterencode==
True:
1614 os.remove(sourcefile)
1621 """multiplex one video and one or two audio streams together"""
1623 write(
"Multiplexing MPEG stream to %s" % destination)
1629 if useSyncOffset ==
True:
1630 write(
"Adding sync offset of %dms" % syncOffset)
1632 write(
"Using sync offset is disabled - it would be %dms" % syncOffset)
1636 os.remove(destination)
1640 audio1 = audio1 +
".ac3"
1642 audio1 = audio1 +
".mp2"
1647 audio2 = audio2 +
".ac3"
1649 audio2 = audio2 +
".mp2"
1653 if os.path.exists(os.path.dirname(destination) +
"/stream.d/spumux.xml"):
1656 localUseFIFO=useFIFO
1658 if localUseFIFO==
True:
1659 os.mkfifo(destination)
1667 write(
"Available streams - video and one audio stream")
1668 write(
"running %s -M -f 8 -v 0 --sync-offset %sms -o %s %s %s" %(path_mplex[0], syncOffset, destination, video, audio1))
1669 result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
1673 '--sync-offset',
'%sms' % syncOffset,
1678 write(
"Available streams - video and two audio streams")
1679 result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
1683 '--sync-offset',
'%sms' % syncOffset,
1689 if localUseFIFO ==
True:
1690 write(
"Multiplex started PID=%s" % result)
1694 fatalError(
"mplex failed with result %d" % result)
1697 if os.path.exists(os.path.dirname(destination) +
"/stream.d/spumux.xml"):
1698 write(
"Checking integrity of subtitle pngs")
1699 command =
quoteCmdArg(os.path.join(scriptpath,
"testsubtitlepngs.sh")) +
" " +
quoteCmdArg(os.path.dirname(destination) +
"/stream.d/spumux.xml")
1702 fatalError(
"Failed while running testsubtitlepngs.sh - %s" % command)
1704 write(
"Running spumux to add subtitles")
1709 "Command was - %s.\n"
1710 "Look in the full log to see why it failed" % command)
1711 os.remove(os.path.splitext(destination)[0] +
"-sub.mpg")
1713 os.rename(os.path.splitext(destination)[0] +
"-sub.mpg", destination)
1722 """create a stream.xml file for filename"""
1724 command =
"mytharchivehelper -q -q --getfileinfo --infile %s --outfile %s --method %d" % (
quoteCmdArg(filename),
quoteCmdArg(xmlFilename), lenMethod)
1730 fatalError(
"Failed while running mytharchivehelper to get stream information.\n"
1731 "Result: %d, Command was %s" % (result, command))
1734 infoDOM = xml.dom.minidom.parse(xmlFilename)
1735 write(xmlFilename +
":-\n" + infoDOM.toprettyxml(
" ",
""),
False)
1741 """Get video width and height from stream.xml file"""
1744 infoDOM = xml.dom.minidom.parse(xmlFilename)
1747 if infoDOM.documentElement.tagName !=
"file":
1748 fatalError(
"This info file doesn't look right (%s)." % xmlFilename)
1749 nodes = infoDOM.getElementsByTagName(
"video")
1750 if nodes.length == 0:
1751 fatalError(
"Didn't find any video elements in stream info file. (%s)" % xmlFilename)
1753 if nodes.length > 1:
1754 write(
"Found more than one video element in stream info file.!!!")
1756 width = int(node.attributes[
"width"].value)
1757 height = int(node.attributes[
"height"].value)
1759 return (width, height)
1765 """Use mythtranscode to cut commercials and/or clean up an mpeg2 file"""
1768 rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
1769 cutlist = rec.markup.getcutlist()
1770 except StopIteration:
1774 if usecutlist
and len(cutlist):
1777 cutlist_s +=
' %d-%d ' % cut
1779 write(
"Using cutlist: %s" % cutlist_s)
1781 if (localfile !=
""):
1782 if usecutlist ==
True:
1783 command =
"mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s,
quoteCmdArg(localfile),
quoteCmdArg(destination))
1785 command =
"mythtranscode --mpeg2 --infile %s --outfile %s" % (
quoteCmdArg(localfile),
quoteCmdArg(destination))
1787 if usecutlist ==
True:
1788 command =
"mythtranscode --mpeg2 --honorcutlist --chanid %s --starttime %s --outfile %s" % (chanid, starttime,
quoteCmdArg(destination))
1790 command =
"mythtranscode --mpeg2 --chanid %s --starttime %s --outfile %s" % (chanid, starttime,
quoteCmdArg(destination))
1795 write(
"Failed while running mythtranscode to cut commercials and/or clean up an mpeg2 file.\n"
1796 "Result: %d, Command was %s" % (result, command))
1806 """generate cutlist_x.txt for ProjectX"""
1808 rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
1809 starttime = rec.starttime.utcisoformat()
1810 cutlist = rec.markup.getcutlist()
1813 with codecs.open(os.path.join(folder,
"cutlist_x.txt"),
'w',
'utf-8')
as cutlist_f:
1814 cutlist_f.write(
"CollectionPanel.CutMode=2\n")
1822 cutlist_f.write(
'0\n%d\n' % cut[0])
1823 cutlist_f.write(
'%d\n' % cut[1])
1824 elif i == len(cutlist) - 1:
1825 cutlist_f.write(
'%d\n' % cut[0])
1826 if cut[1] != 9999999:
1827 cutlist_f.write(
'%d\n9999999\n' % cut[1])
1829 cutlist_f.write(
'%d\n%d\n' % cut)
1834 write(
"No cutlist in the DB for chanid %s, starttime %s" % chanid, starttime)
1841 """Use Project-X to cut commercials and demux an mpeg2 file"""
1845 write(
"Failed to generate Project-X cutlist.")
1848 if os.path.exists(file) !=
True:
1849 write(
"Error: input file doesn't exist on local filesystem")
1853 if usecutlist ==
True:
1854 command +=
" -cut %s" %
quoteCmdArg(os.path.join(folder,
"cutlist_x.txt"))
1859 write(
"Failed while running Project-X to cut commercials and/or demux an mpeg2 file.\n"
1860 "Result: %d, Command was %s" % (result, command))
1869 videoID_hex =
"0x%x" % video[VIDEO_ID]
1870 if audio1[AUDIO_ID] != -1:
1871 audio1ID_hex =
"0x%x" % audio1[AUDIO_ID]
1874 if audio2[AUDIO_ID] != -1:
1875 audio2ID_hex =
"0x%x" % audio2[AUDIO_ID]
1878 if addSubtitles
and subtitles[SUBTITLE_ID] != -1:
1879 subtitlesID_hex =
"0x%x" % subtitles[SUBTITLE_ID]
1881 subtitlesID_hex =
""
1884 files = os.listdir(folder)
1886 if file[0:9] ==
"stream{0x":
1889 if PID == videoID_hex
or SubID == videoID_hex:
1890 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.mv2"))
1891 elif PID == audio1ID_hex
or SubID == audio1ID_hex:
1892 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0." + file[-3:]))
1893 elif PID == audio2ID_hex
or SubID == audio2ID_hex:
1894 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1." + file[-3:]))
1895 elif PID == subtitlesID_hex
or SubID == subtitlesID_hex:
1896 if file[-3:] ==
"sup":
1897 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup"))
1899 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup.IFO"))
1904 files = os.listdir(folder)
1906 if file[0:9] ==
"stream{0x":
1907 if not os.path.exists(os.path.join(folder,
"stream.mv2"))
and file[-3:] ==
"m2v":
1908 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.mv2"))
1909 elif not (os.path.exists(os.path.join(folder,
"stream0.ac3"))
or os.path.exists(os.path.join(folder,
"stream0.mp2")))
and file[-3:] ==
"ac3":
1910 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0.ac3"))
1911 elif not (os.path.exists(os.path.join(folder,
"stream0.ac3"))
or os.path.exists(os.path.join(folder,
"stream0.mp2")))
and file[-3:] ==
"mp2":
1912 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0.mp2"))
1913 elif not (os.path.exists(os.path.join(folder,
"stream1.ac3"))
or os.path.exists(os.path.join(folder,
"stream1.mp2")))
and file[-3:] ==
"ac3":
1914 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1.ac3"))
1915 elif not (os.path.exists(os.path.join(folder,
"stream1.ac3"))
or os.path.exists(os.path.join(folder,
"stream1.mp2")))
and file[-3:] ==
"mp2":
1916 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1.mp2"))
1917 elif not os.path.exists(os.path.join(folder,
"stream.sup"))
and file[-3:] ==
"sup":
1918 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup"))
1919 elif not os.path.exists(os.path.join(folder,
"stream.sup.IFO"))
and file[-3:] ==
"IFO":
1920 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup.IFO"))
1926 if (os.path.exists(os.path.join(folder,
"stream.sup"))
and
1927 os.path.exists(os.path.join(folder,
"stream.sup.IFO"))):
1928 write(
"Found DVB subtitles converting to DVD subtitles")
1929 command =
"mytharchivehelper -q -q --sup2dast "
1930 command +=
" --infile %s --ifofile %s --delay 0" % (
quoteCmdArg(os.path.join(folder,
"stream.sup")),
quoteCmdArg(os.path.join(folder,
"stream.sup.IFO")))
1935 write(
"Failed while running mytharchivehelper to convert DVB subtitles to DVD subtitles.\n"
1936 "Result: %d, Command was %s" % (result, command))
1948 h = int(time[0:2]) * 3600 * 90000
1949 m = int(time[3:5]) * 60 * 90000
1950 s = int(time[6:8]) * 90000
1951 ms = int(time[9:11]) * 90
1953 return h + m + s + ms
1961 subDOM = xml.dom.minidom.parse(spumuxFile)
1964 if subDOM.documentElement.tagName !=
"subpictures":
1965 fatalError(
"This does not look like a spumux.xml file (%s)" % spumuxFile)
1967 streamNodes = subDOM.getElementsByTagName(
"stream")
1968 if streamNodes.length == 0:
1969 write(
"Didn't find any stream elements in file.!!!")
1971 streamNode = streamNodes[0]
1973 nodes = subDOM.getElementsByTagName(
"spu")
1974 if nodes.length == 0:
1975 write(
"Didn't find any spu elements in file.!!!")
1982 start =
ts2pts(node.attributes[
"start"].value)
1983 end =
ts2pts(node.attributes[
"end"].value)
1984 image = node.attributes[
"image"].value
1988 if start <= lastEnd:
1992 write(
"removing subtitle: %s to %s - (%d - %d (%d))" % (node.attributes[
"start"].value, node.attributes[
"end"].value, start, end, lastEnd),
False)
1993 streamNode.removeChild(node)
2005 write(
"Extracting thumbnail image from %s at position %s" % (source, seconds))
2006 write(
"Destination file %s" % destination)
2010 if videomode==
"pal":
2015 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (
quoteCmdArg(source), seconds,
quoteCmdArg(destination))
2018 fatalError(
"Failed while running mytharchivehelper to get thumbnails.\n"
2019 "Result: %d, Command was %s" % (result, command))
2021 myimage=Image.open(destination,
"r")
2023 if myimage.format !=
"JPEG":
2024 write(
"Something went wrong with thumbnail capture - " + myimage.format)
2035 write(
"Extracting thumbnail images from: %s - at %s" % (source, thumbList))
2036 write(
"Destination file %s" % destination)
2038 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (
quoteCmdArg(source), thumbList,
quoteCmdArg(destination))
2042 fatalError(
"Failed while running mytharchivehelper to get thumbnails.\n"
2043 "Result: %d, Command was %s" % (result, command))
2049 """Encodes an unknown video source file eg. AVI to MPEG2 video and AC3 audio, use mythffmpeg"""
2053 passes = int(
getText(profileNode.getElementsByTagName(
"passes")[0]))
2055 command =
"mythffmpeg"
2058 command +=
" -threads %d" % cpuCount
2060 parameters = profileNode.getElementsByTagName(
"parameter")
2062 for param
in parameters:
2063 name = param.attributes[
"name"].value
2064 value = param.attributes[
"value"].value
2067 if value ==
"%inputfile":
2069 if value ==
"%outputfile":
2071 if value ==
"%aspect":
2075 if audio1[AUDIO_CODEC] ==
"AC3":
2076 if name ==
"-acodec":
2078 if name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2083 command +=
" " + name
2086 command +=
" " + value
2090 if audio2[AUDIO_ID] != -1:
2091 for param
in parameters:
2092 name = param.attributes[
"name"].value
2093 value = param.attributes[
"value"].value
2096 if audio1[AUDIO_CODEC] ==
"AC3":
2097 if name ==
"-acodec":
2099 if name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2103 if name ==
"-acodec" or name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2104 command +=
" " + name +
" " + value
2107 command +=
" -map 0:%d -map 0:%d " % (video[VIDEO_INDEX], audio1[AUDIO_INDEX])
2108 if audio2[AUDIO_ID] != -1:
2109 command +=
"-map 0:%d" % (audio2[AUDIO_INDEX])
2115 fatalError(
"Failed while running mythffmpeg to re-encode video.\n"
2116 "Command was %s" % command)
2121 pass1 = command.replace(
"%passno",
"1")
2122 pass1 = pass1.replace(
"%passlogfile",
quoteCmdArg(passLog))
2123 write(
"Pass 1 - " + pass1)
2127 fatalError(
"Failed while running mythffmpeg (Pass 1) to re-encode video.\n"
2128 "Command was %s" % command)
2130 if os.path.exists(destvideofile):
2131 os.remove(destvideofile)
2133 pass2 = command.replace(
"%passno",
"2")
2134 pass2 = pass2.replace(
"%passlogfile", passLog)
2135 write(
"Pass 2 - " + pass2)
2139 fatalError(
"Failed while running mythffmpeg (Pass 2) to re-encode video.\n"
2140 "Command was %s" % command)
2144 def encodeNuvToMPEG2(chanid, starttime, mediafile, destvideofile, folder, profile, usecutlist):
2145 """Encodes a nuv video source file to MPEG2 video and AC3 audio, using mythtranscode & mythffmpeg"""
2149 fatalError(
"Something is wrong! Found one or more stale fifo's from mythtranscode\n"
2150 "Delete the fifos in '%s' and start again" % folder)
2153 parameters = profileNode.getElementsByTagName(
"parameter")
2156 outvideobitrate =
"5000k"
2157 if videomode ==
"ntsc":
2158 outvideores =
"720x480"
2160 outvideores =
"720x576"
2162 outaudiochannels = 2
2163 outaudiobitrate = 384
2164 outaudiosamplerate = 48000
2165 outaudiocodec =
"ac3"
2172 for param
in parameters:
2173 name = param.attributes[
"name"].value
2174 value = param.attributes[
"value"].value
2177 if name ==
"-acodec":
2178 outaudiocodec = value
2180 outaudiochannels = value
2182 outaudiobitrate = value
2184 outaudiosamplerate = value
2186 outvideobitrate = value
2189 if name ==
"-deinterlace":
2191 if name ==
"-filter:v":
2197 if name ==
"-qdiff":
2201 utcstarttime = datetime.duck(starttime).utcisoformat()
2202 if (usecutlist ==
True):
2203 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2206 '--starttime', utcstarttime,
2208 '--fifodir', folder)
2209 write(
"mythtranscode started (using cut list) PID = %s" % PID)
2211 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2214 '--starttime', utcstarttime,
2215 '--fifodir', folder)
2217 write(
"mythtranscode started PID = %s" % PID)
2218 elif mediafile != -1:
2219 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2221 '--infile', mediafile,
2222 '--fifodir', folder)
2223 write(
"mythtranscode started (using file) PID = %s" % PID)
2225 fatalError(
"no video source passed to encodeNuvToMPEG2.\n")
2231 command =
"mythffmpeg -y "
2234 command +=
"-threads %d " % cpuCount
2236 command +=
"-f s16le -ar %s -ac %s -i %s " % (samplerate, channels,
quoteCmdArg(os.path.join(folder,
"audout")))
2237 command +=
"-f rawvideo -pix_fmt yuv420p -s %s -aspect %s -r %s " % (videores, aspectratio, fps)
2238 command +=
"-i %s " %
quoteCmdArg(os.path.join(folder,
"vidout"))
2239 command +=
"-aspect %s -r %s " % (aspectratio, fps)
2240 if (deinterlace == 1):
2241 command +=
"-deinterlace "
2242 command +=
"%s" % filter
2243 command +=
"-s %s -b %s -vcodec mpeg2video " % (outvideores, outvideobitrate)
2244 command +=
"-qmin %s -qmax %s -qdiff %s " % (qmin, qmax, qdiff)
2245 command +=
"-ab %s -ar %s -acodec %s " % (outaudiobitrate, outaudiosamplerate, outaudiocodec)
2246 command +=
"-f dvd %s" %
quoteCmdArg(destvideofile)
2250 while (tries
and not(
doesFileExist(os.path.join(folder,
"audout"))
and
2253 write(
"Waiting for mythtranscode to create the fifos")
2257 fatalError(
"Waited too long for mythtranscode to create the fifos - giving up!!")
2259 write(
"Running mythffmpeg")
2262 os.kill(PID, signal.SIGKILL)
2263 fatalError(
"Failed while running mythffmpeg to re-encode video.\n"
2264 "Command was %s" % command)
2270 write(
"Starting dvdauthor")
2272 result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],
'-x',os.path.join(
getTempPath(),
'dvdauthor.xml'))
2274 fatalError(
"Failed while running dvdauthor. Result: %d" % result)
2275 write(
"Finished dvdauthor")
2281 write(
"Creating ISO image")
2283 command =
quoteCmdArg(path_mkisofs[0]) +
' -dvd-video '
2292 "Command was %s" % command)
2294 write(
"Finished creating ISO image")
2301 write(
"Burning ISO image to %s" % dvddrivepath)
2306 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2307 status = ioctl(f,CDROM.CDROM_DRIVE_STATUS, 0)
2310 def displayneededdisktype():
2311 if mediatype == DVD_SL:
2312 write(
"Please insert an empty single-layer disc (DVD+R or DVD-R).")
2313 if mediatype == DVD_DL:
2314 write(
"Please insert an empty double-layer disc (DVD+R DL or DVD-R DL).")
2315 if mediatype == DVD_RW:
2316 write(
"Please insert a rewritable disc (DVD+RW or DVD-RW).")
2317 def drive(action, value=0):
2321 if action == CDROM.CDROMEJECT:
2323 while drivestatus() != CDROM.CDS_TRAY_OPEN
and counter < 15:
2324 counter = counter + 1
2325 drive(CDROM.CDROM_LOCKDOOR, 0)
2327 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2329 ioctl(f,action, value)
2331 write(
"Sending command '0x%x' to drive failed" %action,
False)
2335 write(
'"eject" is probably not installed.',
False)
2338 if drivestatus() == CDROM.CDS_TRAY_OPEN:
2342 write(
"Failed to eject the disc! Probably drive is blocked by another program.")
2345 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2347 ioctl(f,action, value)
2350 write(
"Sending command '0x%x' to drive failed" %action,
False)
2356 while drivestatus() == CDROM.CDS_DRIVE_NOT_READY:
2358 write(
"Waiting for drive")
2364 write(
"Try a hard-reset of the device")
2365 drive(CDROM.CDROMRESET)
2382 if drivestatus() == CDROM.CDS_DISC_OK
or drivestatus() == CDROM.CDS_NO_INFO:
2389 command =
quoteCmdArg(path_growisofs[0]) +
" -input-charset=UTF-8 -dvd-compat"
2391 command +=
" -speed=%d" % drivespeed
2392 if mediatype == DVD_RW
and erasedvdrw ==
True:
2393 command +=
" -use-the-force-luke"
2396 write(
"Running growisofs to burn DVD")
2403 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2406 while busy
and tries < 10:
2409 ioctl(f, CDROM.CDROM_LOCKDOOR, 0)
2412 write(
"Drive is still busy")
2419 write(
"You probably inserted a medium of wrong type.")
2420 elif (result == 156):
2422 write(
"You probably inserted a non-empty, corrupt or too small medium.")
2423 elif (result == 144):
2425 write(
"You inserted a non-empty medium.")
2428 write(
"ERROR: Failed while running growisofs.")
2429 write(
"Result %d, Command was: %s" % (result, command))
2430 write(
"Please check mythburn.log for further information")
2433 write(
"Going to try it again until canceled by user:")
2436 displayneededdisktype()
2439 drive(CDROM.CDROMEJECT)
2442 elif drivestatus() == CDROM.CDS_TRAY_OPEN:
2443 displayneededdisktype()
2444 write(
"Waiting for tray to close.")
2446 while drivestatus() == CDROM.CDS_TRAY_OPEN:
2449 elif drivestatus() == CDROM.CDS_NO_DISC:
2450 drive(CDROM.CDROMEJECT)
2451 displayneededdisktype()
2453 write(
"Finished burning ISO image")
2462 command =
"mythreplex --demux --fix_sync -t TS -o %s " %
quoteCmdArg(folder +
"/stream")
2463 command +=
"-v %d " % (video[VIDEO_ID])
2465 if audio1[AUDIO_ID] != -1:
2466 if audio1[AUDIO_CODEC] ==
'MP2':
2467 command +=
"-a %d " % (audio1[AUDIO_ID])
2468 elif audio1[AUDIO_CODEC] ==
'AC3':
2469 command +=
"-c %d " % (audio1[AUDIO_ID])
2470 elif audio1[AUDIO_CODEC] ==
'EAC3':
2471 command +=
"-c %d " % (audio1[AUDIO_ID])
2473 if audio2[AUDIO_ID] != -1:
2474 if audio2[AUDIO_CODEC] ==
'MP2':
2475 command +=
"-a %d " % (audio2[AUDIO_ID])
2476 elif audio2[AUDIO_CODEC] ==
'AC3':
2477 command +=
"-c %d " % (audio2[AUDIO_ID])
2478 elif audio2[AUDIO_CODEC] ==
'EAC3':
2479 command +=
"-c %d " % (audio2[AUDIO_ID])
2482 command =
"mythreplex --demux --fix_sync -o %s " %
quoteCmdArg(folder +
"/stream")
2483 command +=
"-v %d " % (video[VIDEO_ID] & 255)
2485 if audio1[AUDIO_ID] != -1:
2486 if audio1[AUDIO_CODEC] ==
'MP2':
2487 command +=
"-a %d " % (audio1[AUDIO_ID] & 255)
2488 elif audio1[AUDIO_CODEC] ==
'AC3':
2489 command +=
"-c %d " % (audio1[AUDIO_ID] & 255)
2490 elif audio1[AUDIO_CODEC] ==
'EAC3':
2491 command +=
"-c %d " % (audio1[AUDIO_ID] & 255)
2494 if audio2[AUDIO_ID] != -1:
2495 if audio2[AUDIO_CODEC] ==
'MP2':
2496 command +=
"-a %d " % (audio2[AUDIO_ID] & 255)
2497 elif audio2[AUDIO_CODEC] ==
'AC3':
2498 command +=
"-c %d " % (audio2[AUDIO_ID] & 255)
2499 elif audio2[AUDIO_CODEC] ==
'EAC3':
2500 command +=
"-c %d " % (audio2[AUDIO_ID] & 255)
2503 command += mediafile
2504 write(
"Running: " + command)
2509 fatalError(
"Failed while running mythreplex. Command was %s" % command)
2516 M2Vsize0 = os.path.getsize(source)
2517 write(
"Initial M2Vsize is %.2f Mb , target is %.2f Mb" % ( (float(M2Vsize0)/mega), (float(M2Vsize0)/(factor*mega)) ))
2520 command +=
" %.5f " % factor
2521 command +=
" %s " % M2Vsize0
2525 write(
"Running: " + command)
2528 fatalError(
"Failed while running M2VRequantiser. Command was %s" % command)
2530 M2Vsize1 = os.path.getsize(destination)
2532 write(
"M2Vsize after requant is %.2f Mb " % (float(M2Vsize1)/mega))
2533 fac1=float(M2Vsize0) / float(M2Vsize1)
2534 write(
"Factor demanded %.5f, achieved %.5f, ratio %.5f " % ( factor, fac1, fac1/factor))
2540 """ Returns the sizes of all video, audio and menu files"""
2551 file=os.path.join(folder,
"stream.mv2")
2553 totalvideosize+=os.path.getsize(file)
2557 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream0.ac3"))
2559 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream0.mp2"))
2563 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream1.ac3"))
2565 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream1.mp2"))
2569 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % filecount))
2573 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"details-%s.mpg" % filecount))
2577 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"menu-%s.mpg" % filecount))
2580 return totalvideosize,totalaudiosize,totalmenusize
2592 file=os.path.join(folder,
"stream.mv2")
2593 progvsize=os.path.getsize(file)
2594 progvbitrate=progvsize/progduration
2595 if progvbitrate>rate :
2596 tvsize+=progduration*rate
2613 allfiles=totalvideosize+totalaudiosize+totalmenusize
2616 write(
"Total video %.2f Mb, audio %.2f Mb, menus %.2f Mb." % (totalvideosize/mega,totalaudiosize/mega,totalmenusize/mega))
2619 mv2space=((dvdrsize*mega-totalmenusize)/fudge_pack)-totalaudiosize
2622 fatalError(
"Audio and menu files are too big. No room for video. Giving up!")
2624 if totalvideosize>mv2space:
2625 write(
"Video files are %.1f Mb too big. Need to shrink." % ((totalvideosize - mv2space)/mega) )
2627 if path_M2VRequantiser[0] ==
"":
2628 fatalError(
"M2VRequantiser is not available to resize the files. Giving up!")
2636 file=os.path.join(folder,
"stream.mv2")
2637 vsize+=os.path.getsize(file)
2653 vrHi=3.0*float(vsize)/duration
2664 if (testsize<mv2space):
2667 write(
"vrate %.3f kb/s, testsize %.4f , mv2space %.4f Mb " % ((vrate)/1000.0, (testsize)/mega, (mv2space)/mega) )
2672 file=os.path.join(folder,
"stream.mv2")
2673 progvsize=os.path.getsize(file)
2675 progvbitrate=progvsize/progduration
2676 write(
"File %s, size %.2f Mb, rate %.2f, limit %.2f kb/s " %( filecount, float(progvsize)/mega, progvbitrate/1000.0, vrate/1000.0 ))
2677 if progvbitrate>vrate :
2678 scalefactor=1.0+(fudge_requant*float(progvbitrate-vrate)/float(vrate))
2679 if scalefactor>3.0 :
2680 write(
"Large shrink factor. You may not like the result! ")
2685 write(
"Unpackaged total %.2f Mb. About %.0f Mb will be unused." % ((allfiles/mega),(mv2space-totalvideosize)/mega))
2691 """Creates the xml file for dvdauthor to use the MythBurn menus."""
2694 menunode=themeDOM.getElementsByTagName(
"menu")
2695 if menunode.length!=1:
2696 fatalError(
"Cannot find the menu element in the theme file")
2697 menunode=menunode[0]
2699 menuitems=menunode.getElementsByTagName(
"item")
2701 itemsperpage = menuitems.length
2702 write(
"Menu items per page %s" % itemsperpage)
2703 autoplaymenu = 2 + ((numberofitems + itemsperpage - 1)//itemsperpage)
2707 submenunode=themeDOM.getElementsByTagName(
"submenu")
2708 if submenunode.length!=1:
2709 fatalError(
"Cannot find the submenu element in the theme file")
2711 submenunode=submenunode[0]
2713 chapteritems=submenunode.getElementsByTagName(
"chapter")
2715 chapters = chapteritems.length
2716 write(
"Chapters per recording %s" % chapters)
2727 write(
"Creating DVD XML file for dvd author")
2729 dvddom = xml.dom.minidom.parseString(
2739 dvdauthor_element=dvddom.documentElement
2740 menus_element = dvdauthor_element.childNodes[1].childNodes[1]
2742 dvdauthor_element.insertBefore( dvddom.createComment(
"""
2746 g2=title number selected on current menu page (see g4)
2747 g3=1 if intro movie has played
2748 g4=last menu page on display
2749 g5=next title to autoplay (0 or > # titles means no more autoplay)
2750 """), dvdauthor_element.firstChild )
2751 dvdauthor_element.insertBefore(dvddom.createComment(
"dvdauthor XML file created by MythBurn script"), dvdauthor_element.firstChild )
2753 menus_element.appendChild( dvddom.createComment(
"Title menu used to hold intro movie") )
2755 dvdauthor_element.setAttribute(
"dest",os.path.join(
getTempPath(),
"dvd"))
2757 video = dvddom.createElement(
"video")
2758 video.setAttribute(
"format",videomode)
2761 if mainmenuAspectRatio ==
"4:3":
2762 video.setAttribute(
"aspect",
"4:3")
2764 video.setAttribute(
"aspect",
"16:9")
2765 video.setAttribute(
"widescreen",
"nopanscan")
2767 menus_element.appendChild(video)
2769 pgc=menus_element.childNodes[1]
2773 pre = dvddom.createElement(
"pre")
2774 pgc.appendChild(pre)
2778 node = themeDOM.getElementsByTagName(
"intro")[0]
2779 introFile = node.attributes[
"filename"].value
2782 vob = dvddom.createElement(
"vob")
2783 vob.setAttribute(
"file",os.path.join(
getThemeFile(themeName, videomode +
'_' + introFile)))
2784 pgc.appendChild(vob)
2789 post = dvddom.createElement(
"post")
2790 post .appendChild(dvddom.createTextNode(
"{g3=1;g2=1;jump menu 2;}"))
2791 pgc.appendChild(post)
2795 post = dvddom.createElement(
"post")
2796 post .appendChild(dvddom.createTextNode(
"{g3=1;g2=1;jump menu 2;}"))
2797 pgc.appendChild(post)
2800 while itemnum <= numberofitems:
2801 write(
"Menu page %s" % page)
2804 menupgc = dvddom.createElement(
"pgc")
2805 menus_element.appendChild(menupgc)
2807 menupgc.appendChild( dvddom.createComment(
"Menu Page %s" % page) )
2811 pre = dvddom.createElement(
"pre")
2812 pre.appendChild(dvddom.createTextNode(
"{button=g2*1024;g4=%s;}" % page))
2813 menupgc.appendChild(pre)
2815 vob = dvddom.createElement(
"vob")
2816 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"menu-%s.mpg" % page))
2817 menupgc.appendChild(vob)
2820 post = dvddom.createElement(
"post")
2821 post.appendChild(dvddom.createTextNode(
"jump cell 1;"))
2822 menupgc.appendChild(post)
2831 while itemnum <= numberofitems
and itemsonthispage < itemsperpage:
2832 menuitem=menuitems[ itemsonthispage ]
2837 infoDOM = xml.dom.minidom.parse( os.path.join(
getItemTempPath(itemnum),
"info.xml") )
2839 if infoDOM.documentElement.tagName !=
"fileinfo":
2845 button=dvddom.createElement(
"button")
2846 button.setAttribute(
"name",
"%s" % itemnum)
2847 button.appendChild(dvddom.createTextNode(
"{g2=" +
"%s" % itemsonthispage +
"; g5=0; jump title %s;}" % itemnum))
2848 menupgc.appendChild(button)
2852 titleset = dvddom.createElement(
"titleset")
2853 dvdauthor_element.appendChild(titleset)
2856 comment =
getText(infoDOM.getElementsByTagName(
"title")[0]).replace(
'--',
'-')
2857 titleset.appendChild( dvddom.createComment(comment))
2859 menus= dvddom.createElement(
"menus")
2860 titleset.appendChild(menus)
2862 video = dvddom.createElement(
"video")
2863 video.setAttribute(
"format",videomode)
2866 if chaptermenuAspectRatio ==
"4:3":
2867 video.setAttribute(
"aspect",
"4:3")
2868 elif chaptermenuAspectRatio ==
"16:9":
2869 video.setAttribute(
"aspect",
"16:9")
2870 video.setAttribute(
"widescreen",
"nopanscan")
2874 video.setAttribute(
"aspect",
"16:9")
2875 video.setAttribute(
"widescreen",
"nopanscan")
2877 video.setAttribute(
"aspect",
"4:3")
2879 menus.appendChild(video)
2882 mymenupgc = dvddom.createElement(
"pgc")
2883 menus.appendChild(mymenupgc)
2885 pre = dvddom.createElement(
"pre")
2886 mymenupgc.appendChild(pre)
2888 pre.appendChild(dvddom.createTextNode(
"{button=s7 - 1 * 1024;}"))
2890 pre.appendChild(dvddom.createTextNode(
"{button=s7 * 1024;}"))
2892 vob = dvddom.createElement(
"vob")
2893 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % itemnum))
2894 mymenupgc.appendChild(vob)
2897 post = dvddom.createElement(
"post")
2898 post.appendChild(dvddom.createTextNode(
"jump cell 1;"))
2899 mymenupgc.appendChild(post)
2906 chapterlist = thumblist.split(
",")
2907 if chapterlist[0] !=
'00:00:00':
2910 while x <= chapters:
2912 button = dvddom.createElement(
"button")
2913 button.setAttribute(
"name",
"%s" % x)
2915 button.appendChild(dvddom.createTextNode(
"jump title %s chapter %s;" % (1, firstChapter + x + 1)))
2917 button.appendChild(dvddom.createTextNode(
"jump title %s chapter %s;" % (1, firstChapter + x)))
2919 mymenupgc.appendChild(button)
2924 submenunode = themeDOM.getElementsByTagName(
"submenu")
2925 submenunode = submenunode[0]
2926 titlemenunodes = submenunode.getElementsByTagName(
"titlemenu")
2927 if titlemenunodes.length > 0:
2928 button = dvddom.createElement(
"button")
2929 button.setAttribute(
"name",
"titlemenu")
2930 button.appendChild(dvddom.createTextNode(
"{jump vmgm menu;}"))
2931 mymenupgc.appendChild(button)
2934 titles = dvddom.createElement(
"titles")
2935 titleset.appendChild(titles)
2938 title_video = dvddom.createElement(
"video")
2939 title_video.setAttribute(
"format",videomode)
2942 title_video.setAttribute(
"aspect",
"16:9")
2943 title_video.setAttribute(
"widescreen",
"nopanscan")
2945 title_video.setAttribute(
"aspect",
"4:3")
2947 titles.appendChild(title_video)
2951 title_audio = dvddom.createElement(
"audio")
2952 title_audio.setAttribute(
"format",
"mp2")
2954 title_audio = dvddom.createElement(
"audio")
2955 title_audio.setAttribute(
"format",
"ac3")
2957 titles.appendChild(title_audio)
2959 pgc = dvddom.createElement(
"pgc")
2960 titles.appendChild(pgc)
2964 vob = dvddom.createElement(
"vob")
2965 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum))
2966 pgc.appendChild(vob)
2968 vob = dvddom.createElement(
"vob")
2971 chapterlist = thumblist.split(
",")
2972 if chapterlist[0] !=
'00:00:00':
2973 thumblist =
'00:00:00,' + thumblist
2974 vob.setAttribute(
"chapters", thumblist)
2976 vob.setAttribute(
"chapters",
2981 vob.setAttribute(
"file",os.path.join(
getItemTempPath(itemnum),
"final.vob"))
2982 pgc.appendChild(vob)
2984 post = dvddom.createElement(
"post")
2985 post.appendChild(dvddom.createTextNode(
"if (g5 eq %s) call vmgm menu %s; call vmgm menu %s;" % (itemnum + 1, autoplaymenu, page + 1)))
2986 pgc.appendChild(post)
2998 for node
in menuitem.childNodes:
3000 if node.nodeName==
"previous":
3002 button=dvddom.createElement(
"button")
3003 button.setAttribute(
"name",
"previous")
3004 button.appendChild(dvddom.createTextNode(
"{g2=1;jump menu %s;}" % page ))
3005 endbuttons.append(button)
3008 elif node.nodeName==
"next":
3009 if itemnum < numberofitems:
3010 button=dvddom.createElement(
"button")
3011 button.setAttribute(
"name",
"next")
3012 button.appendChild(dvddom.createTextNode(
"{g2=1;jump menu %s;}" % (page + 2)))
3013 endbuttons.append(button)
3015 elif node.nodeName==
"playall":
3016 button=dvddom.createElement(
"button")
3017 button.setAttribute(
"name",
"playall")
3018 button.appendChild(dvddom.createTextNode(
"{g5=1; jump menu %s;}" % autoplaymenu))
3019 endbuttons.append(button)
3027 for button
in endbuttons:
3028 menupgc.appendChild(button)
3031 menupgc = dvddom.createElement(
"pgc")
3032 menus_element.appendChild(menupgc)
3033 menupgc.setAttribute(
"pause",
"inf")
3034 menupgc.appendChild( dvddom.createComment(
"Autoplay hack") )
3037 while (itemnum > 1):
3039 dvdcode +=
"if (g5 eq %s) {g5 = %s; jump title %s;} " % (itemnum, itemnum + 1, itemnum)
3040 dvdcode +=
"g5 = 0; jump menu 1;"
3042 pre = dvddom.createElement(
"pre")
3043 pre.appendChild(dvddom.createTextNode(dvdcode))
3044 menupgc.appendChild(pre)
3049 dvdcode=
"if (g3 eq 1) {"
3052 dvdcode+=
"if (g4 eq %s) " % page
3053 dvdcode+=
"jump menu %s;" % (page + 1)
3057 vmgm_pre_node.appendChild(dvddom.createTextNode(dvdcode))
3061 WriteXMLToFile (dvddom,os.path.join(
getTempPath(),
"dvdauthor.xml"))
3070 """Creates the xml file for dvdauthor to use the MythBurn menus."""
3076 write(
"Creating DVD XML file for dvd author (No Main Menu)")
3084 """Creates the xml file for dvdauthor containing no menus."""
3090 write(
"Creating DVD XML file for dvd author (No Menus)")
3092 dvddom = xml.dom.minidom.parseString(
3097 <pgc entry="title" pause="0">
3103 dvdauthor_element = dvddom.documentElement
3104 menus = dvdauthor_element.childNodes[1].childNodes[1]
3105 menu_pgc = menus.childNodes[1]
3107 dvdauthor_element.insertBefore(dvddom.createComment(
"dvdauthor XML file created by MythBurn script"), dvdauthor_element.firstChild )
3108 dvdauthor_element.setAttribute(
"dest",os.path.join(
getTempPath(),
"dvd"))
3112 video = dvddom.createElement(
"video")
3113 video.setAttribute(
"format", videomode)
3116 if mainmenuAspectRatio ==
"4:3":
3117 video.setAttribute(
"aspect",
"4:3")
3119 video.setAttribute(
"aspect",
"16:9")
3120 video.setAttribute(
"widescreen",
"nopanscan")
3121 menus.appendChild(video)
3123 pre = dvddom.createElement(
"pre")
3124 pre.appendChild(dvddom.createTextNode(
"if (g2==1) jump menu 2;"))
3125 menu_pgc.appendChild(pre)
3127 node = themeDOM.getElementsByTagName(
"intro")[0]
3128 introFile = node.attributes[
"filename"].value
3130 vob = dvddom.createElement(
"vob")
3131 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' + introFile))
3132 menu_pgc.appendChild(vob)
3134 post = dvddom.createElement(
"post")
3135 post.appendChild(dvddom.createTextNode(
"g2=1; jump menu 2;"))
3136 menu_pgc.appendChild(post)
3142 pre = dvddom.createElement(
"pre")
3143 pre.appendChild(dvddom.createTextNode(
"g2=1;jump menu 2;"))
3144 menu_pgc.appendChild(pre)
3146 vob = dvddom.createElement(
"vob")
3147 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3148 menu_pgc.appendChild(vob)
3155 menu_pgc = dvddom.createElement(
"pgc")
3157 preText =
"if (g1==0) g1=1;"
3158 for i
in range(numberofitems):
3159 preText +=
"if (g1==%d) jump titleset %d menu;" % (i + 1, i + 1)
3161 pre = dvddom.createElement(
"pre")
3162 pre.appendChild(dvddom.createTextNode(preText))
3163 menu_pgc.appendChild(pre)
3165 vob = dvddom.createElement(
"vob")
3166 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3167 menu_pgc.appendChild(vob)
3168 menus.appendChild(menu_pgc)
3172 while itemNum <= numberofitems:
3173 write(
"Adding item %s" % itemNum)
3175 titleset = dvddom.createElement(
"titleset")
3176 dvdauthor_element.appendChild(titleset)
3179 menu = dvddom.createElement(
"menus")
3180 menupgc = dvddom.createElement(
"pgc")
3181 menu.appendChild(menupgc)
3182 titleset.appendChild(menu)
3186 vob = dvddom.createElement(
"vob")
3187 vob.setAttribute(
"file", os.path.join(
getTempPath(),
"details-%s.mpg" % itemNum))
3188 menupgc.appendChild(vob)
3190 post = dvddom.createElement(
"post")
3191 post.appendChild(dvddom.createTextNode(
"jump title 1;"))
3192 menupgc.appendChild(post)
3196 pre = dvddom.createElement(
"pre")
3197 pre.appendChild(dvddom.createTextNode(
"jump title 1;"))
3198 menupgc.appendChild(pre)
3201 vob = dvddom.createElement(
"vob")
3202 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3203 menupgc.appendChild(vob)
3205 titles = dvddom.createElement(
"titles")
3208 title_video = dvddom.createElement(
"video")
3209 title_video.setAttribute(
"format", videomode)
3213 title_video.setAttribute(
"aspect",
"16:9")
3214 title_video.setAttribute(
"widescreen",
"nopanscan")
3216 title_video.setAttribute(
"aspect",
"4:3")
3218 titles.appendChild(title_video)
3220 pgc = dvddom.createElement(
"pgc")
3222 vob = dvddom.createElement(
"vob")
3223 vob.setAttribute(
"file", os.path.join(
getItemTempPath(itemNum),
"final.vob"))
3227 pgc.appendChild(vob)
3232 post = dvddom.createElement(
"post")
3233 if itemNum == numberofitems:
3234 post.appendChild(dvddom.createTextNode(
"exit;"))
3236 post.appendChild(dvddom.createTextNode(
"g1=%d;call vmgm menu 2;" % (itemNum + 1)))
3238 pgc.appendChild(post)
3240 titles.appendChild(pgc)
3241 titleset.appendChild(titles)
3252 WriteXMLToFile (dvddom,os.path.join(
getTempPath(),
"dvdauthor.xml"))
3262 if os.path.exists(previewfolder):
3264 os.rmdir (previewfolder)
3265 os.makedirs(previewfolder)
3266 return previewfolder
3272 """generate thumbnails for a preview in a menu"""
3281 for node
in menuitem.childNodes:
3282 if node.nodeName==
"graphic":
3283 if node.attributes[
"filename"].value ==
"%movie":
3286 outputfile = os.path.join(previewfolder,
"preview-i%d-t%%1-f%%2.jpg" % itemonthispage)
3291 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s --framecount %d" % (
quoteCmdArg(inputfile), starttime,
quoteCmdArg(outputfile), frames)
3294 write(
"mytharchivehelper failed with code %d. Command = %s" % (result, command) )
3300 if node.hasAttribute(
"mask"):
3301 imagemaskfilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
3302 if node.attributes[
"mask"].value !=
"" and doesFileExist(imagemaskfilename):
3303 maskpicture = Image.open(imagemaskfilename,
"r").resize((width, height))
3304 maskpicture = maskpicture.convert(
"RGBA")
3306 return (positionx, positiony, width, height, maskpicture)
3312 bgimagemask, drawmask, highlightcolor, spumuxdom, spunode,
3313 numberofitems, chapternumber, chapterlist):
3314 """Draws text and graphics onto a dvd menu, called by
3315 createMenu and createChapterMenu"""
3318 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
3321 if infoDOM.documentElement.tagName !=
"fileinfo":
3322 fatalError(
"The info.xml file (%s) doesn't look right" %
3327 boundarybox = 9999,9999,0,0
3328 wantHighlightBox =
True
3331 for node
in menuitem.childNodes:
3334 if node.nodeName==
"graphic":
3341 if node.attributes[
"filename"].value ==
"%movie":
3346 node.attributes[
"filename"].value,
3347 itemnum, page, itemsonthispage,
3348 chapternumber, chapterlist)
3351 if imagefilename == node.attributes[
"filename"].value:
3353 node.attributes[
"filename"].value)
3357 if node.hasAttribute(
"mask")
and node.attributes[
"mask"].value !=
"":
3358 maskfilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
3362 if (node.attributes[
"filename"].value ==
"%thumbnail"
3363 and getText(infoDOM.getElementsByTagName(
"coverfile")[0]) !=
""):
3368 if paintImage(imagefilename, maskfilename, node, bgimage, stretch):
3371 write(
"Image file does not exist '%s'" % imagefilename)
3373 elif node.nodeName ==
"text":
3380 itemnum, page, itemsonthispage,
3381 chapternumber, chapterlist)
3389 elif node.nodeName==
"previous":
3396 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3397 itemnum, page, itemsonthispage, chapternumber,
3400 button = spumuxdom.createElement(
"button")
3401 button.setAttribute(
"name",
"previous")
3408 spunode.appendChild(button)
3410 write(
"Added previous page button")
3413 elif node.nodeName ==
"next":
3414 if itemnum < numberofitems:
3420 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3421 itemnum, page, itemsonthispage, chapternumber,
3424 button = spumuxdom.createElement(
"button")
3425 button.setAttribute(
"name",
"next")
3432 spunode.appendChild(button)
3434 write(
"Added next page button")
3436 elif node.nodeName==
"playall":
3442 paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
3443 itemsonthispage, chapternumber, chapterlist)
3445 button = spumuxdom.createElement(
"button")
3446 button.setAttribute(
"name",
"playall")
3453 spunode.appendChild(button)
3455 write(
"Added playall button")
3457 elif node.nodeName ==
"titlemenu":
3458 if itemnum < numberofitems:
3464 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3465 itemnum, page, itemsonthispage, chapternumber,
3468 button = spumuxdom.createElement(
"button")
3469 button.setAttribute(
"name",
"titlemenu")
3476 spunode.appendChild(button)
3478 write(
"Added titlemenu button")
3480 elif node.nodeName==
"button":
3486 wantHighlightBox =
False
3488 paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
3489 itemsonthispage, chapternumber, chapterlist)
3494 elif node.nodeName==
"#text" or node.nodeName==
"#comment":
3498 write(
"Dont know how to process %s" % node.nodeName)
3500 if drawmask
is None:
3504 if wantHighlightBox ==
True:
3506 boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
3507 drawmask.rectangle(boundarybox,outline=highlightcolor)
3510 boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
3511 drawmask.rectangle(boundarybox,outline=highlightcolor)
3513 node = spumuxdom.createElement(
"button")
3516 node.setAttribute(
"name",
"%s" % chapternumber)
3518 node.setAttribute(
"name",
"%s" % itemnum)
3519 node.setAttribute(
"x0",
"%d" % int(boundarybox[0]))
3520 node.setAttribute(
"y0",
"%d" % int(boundarybox[1]))
3521 node.setAttribute(
"x1",
"%d" % int(boundarybox[2] + 1))
3522 node.setAttribute(
"y1",
"%d" % int(boundarybox[3] + 1))
3523 spunode.appendChild(node)
3529 """Creates all the necessary menu images and files for the MythBurn menus."""
3532 menunode=themeDOM.getElementsByTagName(
"menu")
3533 if menunode.length!=1:
3534 fatalError(
"Cannot find menu element in theme file")
3535 menunode=menunode[0]
3537 menuitems=menunode.getElementsByTagName(
"item")
3539 itemsperpage = menuitems.length
3540 write(
"Menu items per page %s" % itemsperpage)
3543 backgroundfilename = menunode.attributes[
"background"].value
3544 if backgroundfilename==
"":
3545 fatalError(
"Background image is not set in theme file")
3547 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3548 write(
"Background image file is %s" % backgroundfilename)
3550 fatalError(
"Background image not found (%s)" % backgroundfilename)
3553 highlightcolor =
"red"
3554 if menunode.hasAttribute(
"highlightcolor"):
3555 highlightcolor = menunode.attributes[
"highlightcolor"].value
3558 menumusic =
"menumusic.ac3"
3559 if menunode.hasAttribute(
"music"):
3560 menumusic = menunode.attributes[
"music"].value
3564 if menunode.hasAttribute(
"length"):
3565 menulength = int(menunode.attributes[
"length"].value)
3567 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3575 write(
"Creating DVD menus")
3577 while itemnum <= numberofitems:
3578 write(
"Menu page %s" % page)
3583 write(
"Creating Preview Video")
3584 previewitem = itemnum
3594 while previewitem <= numberofitems
and itemsonthispage < itemsperpage:
3595 menuitem=menuitems[ itemsonthispage ]
3602 px, py, pw, ph, maskimage =
generateVideoPreview(previewitem, itemsonthispage, menuitem, 0, menulength, previewfolder)
3607 previewmask.append(maskimage)
3614 savedpreviewitem = itemnum
3625 overlayimage=Image.new(
"RGBA",screensize)
3626 draw=ImageDraw.Draw(overlayimage)
3629 bgimagemask=Image.new(
"RGBA",overlayimage.size)
3630 drawmask=ImageDraw.Draw(bgimagemask)
3632 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
3633 spunode = spumuxdom.documentElement.firstChild.firstChild
3636 while itemnum <= numberofitems
and itemsonthispage < itemsperpage:
3637 menuitem=menuitems[ itemsonthispage ]
3642 itemnum, menuitem, overlayimage,
3643 draw, bgimagemask, drawmask, highlightcolor,
3644 spumuxdom, spunode, numberofitems, 0,
"")
3650 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
3651 bgimage.paste(overlayimage, (0,0), overlayimage)
3654 rgb_bgimage=bgimage.convert(
'RGB')
3655 rgb_bgimage.save(os.path.join(
getTempPath(),
"background-%s.jpg" % page),
"JPEG", quality=99)
3657 bgimagemask.save(os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page),
"PNG",quality=99,optimize=0,dpi=screendpi)
3670 if haspreview ==
True:
3671 write(
"Generating the preview images" )
3673 while framenum < numframes:
3674 previewitem = savedpreviewitem
3676 while previewitem <= numberofitems
and itemsonthispage < itemsperpage:
3678 if previewx[itemsonthispage-1] != 9999:
3680 previewfile =
"preview-i%d-t1-f%d.jpg" % (itemsonthispage, framenum)
3681 imagefile = os.path.join(previewpath, previewfile)
3684 picture = Image.open(imagefile,
"r").resize((previeww[itemsonthispage-1], previewh[itemsonthispage-1]))
3685 picture = picture.convert(
"RGBA")
3686 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % itemsonthispage)
3687 if previewmask[itemsonthispage-1]
is not None:
3688 bgimage.paste(picture, (previewx[itemsonthispage-1], previewy[itemsonthispage-1]), previewmask[itemsonthispage-1])
3690 bgimage.paste(picture, (previewx[itemsonthispage-1], previewy[itemsonthispage-1]))
3694 rgb_bgimage=bgimage.convert(
'RGB')
3695 rgb_bgimage.save(os.path.join(
getTempPath(),
"background-%s-f%06d.jpg" % (page, framenum)),
"JPEG",quality=99)
3699 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"select",os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page))
3700 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"highlight",os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page))
3712 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"spumux-%s.xml" % page))
3714 if mainmenuAspectRatio ==
"4:3":
3719 write(
"Encoding Menu Page %s using aspect ratio '%s'" % (page, mainmenuAspectRatio))
3720 if haspreview ==
True:
3726 os.path.join(
getTempPath(),
"spumux-%s.xml" % page),
3735 os.path.join(
getTempPath(),
"spumux-%s.xml" % page),
3746 """Creates all the necessary menu images and files for the MythBurn menus."""
3749 menunode=themeDOM.getElementsByTagName(
"submenu")
3750 if menunode.length!=1:
3751 fatalError(
"Cannot find submenu element in theme file")
3752 menunode=menunode[0]
3754 menuitems=menunode.getElementsByTagName(
"chapter")
3756 itemsperpage = menuitems.length
3757 write(
"Chapter items per page %s " % itemsperpage)
3760 backgroundfilename = menunode.attributes[
"background"].value
3761 if backgroundfilename==
"":
3762 fatalError(
"Background image is not set in theme file")
3763 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3764 write(
"Background image file is %s" % backgroundfilename)
3766 fatalError(
"Background image not found (%s)" % backgroundfilename)
3769 highlightcolor =
"red"
3770 if menunode.hasAttribute(
"highlightcolor"):
3771 highlightcolor = menunode.attributes[
"highlightcolor"].value
3774 menumusic =
"menumusic.ac3"
3775 if menunode.hasAttribute(
"music"):
3776 menumusic = menunode.attributes[
"music"].value
3780 if menunode.hasAttribute(
"length"):
3781 menulength = int(menunode.attributes[
"length"].value)
3783 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3788 write(
"Creating DVD sub-menus")
3790 while page <= numberofitems:
3791 write(
"Sub-menu %s " % page)
3799 overlayimage=Image.new(
"RGBA",screensize, (0,0,0,0))
3800 draw=ImageDraw.Draw(overlayimage)
3803 bgimagemask=Image.new(
"RGBA",overlayimage.size, (0,0,0,0))
3804 drawmask=ImageDraw.Draw(bgimagemask)
3806 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
3807 spunode = spumuxdom.documentElement.firstChild.firstChild
3811 chapterlist=chapterlist.split(
",")
3830 while previewchapter < itemsperpage:
3831 menuitem=menuitems[ previewchapter ]
3836 px, py, pw, ph, maskimage =
generateVideoPreview(page, previewchapter, menuitem, previewtime, menulength, previewfolder)
3841 previewmask.append(maskimage)
3850 while chapter < itemsperpage:
3851 menuitem=menuitems[ chapter ]
3856 bgimagemask, drawmask, highlightcolor,
3858 999, chapter, chapterlist)
3861 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
3862 bgimage.paste(overlayimage, (0,0), overlayimage)
3863 rgb_bgimage=bgimage.convert(
'RGB')
3864 rgb_bgimage.save(os.path.join(
getTempPath(),
"chaptermenu-%s.jpg" % page),
"JPEG", quality=99)
3867 bgimagemask.save(os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page),
"PNG",quality=90,optimize=0)
3869 if haspreview ==
True:
3874 write(
"Generating the preview images" )
3876 while framenum < numframes:
3878 while previewchapter < itemsperpage:
3879 if previewx[previewchapter] != 9999:
3881 previewfile =
"preview-i%d-t1-f%d.jpg" % (previewchapter, framenum)
3882 imagefile = os.path.join(previewpath, previewfile)
3885 picture = Image.open(imagefile,
"r").resize((previeww[previewchapter], previewh[previewchapter]))
3886 picture = picture.convert(
"RGBA")
3887 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % previewchapter)
3888 if previewmask[previewchapter]
is not None:
3889 bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]), previewmask[previewchapter])
3891 bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]))
3894 rgb_bgimage=bgimage.convert(
'RGB')
3895 rgb_bgimage.save(os.path.join(
getTempPath(),
"chaptermenu-%s-f%06d.jpg" % (page, framenum)),
"JPEG",quality=99)
3899 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"select",os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page))
3900 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"highlight",os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page))
3913 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page))
3915 if chaptermenuAspectRatio ==
"4:3":
3917 elif chaptermenuAspectRatio ==
"16:9":
3925 write(
"Encoding Chapter Menu Page %s using aspect ratio '%s'" % (page, chaptermenuAspectRatio))
3927 if haspreview ==
True:
3933 os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page),
3934 os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % page),
3942 os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page),
3943 os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % page),
3953 """Creates all the necessary images and files for the details page."""
3955 write(
"Creating details pages")
3958 detailnode=themeDOM.getElementsByTagName(
"detailspage")
3959 if detailnode.length!=1:
3960 fatalError(
"Cannot find detailspage element in theme file")
3961 detailnode=detailnode[0]
3964 backgroundfilename = detailnode.attributes[
"background"].value
3965 if backgroundfilename==
"":
3966 fatalError(
"Background image is not set in theme file")
3967 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3968 write(
"Background image file is %s" % backgroundfilename)
3970 fatalError(
"Background image not found (%s)" % backgroundfilename)
3973 menumusic =
"menumusic.ac3"
3974 if detailnode.hasAttribute(
"music"):
3975 menumusic = detailnode.attributes[
"music"].value
3979 if detailnode.hasAttribute(
"length"):
3980 menulength = int(detailnode.attributes[
"length"].value)
3982 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3987 while itemnum <= numberofitems:
3988 write(
"Creating details page for %s" % itemnum)
3995 previewx, previewy, previeww, previewh, previewmask =
generateVideoPreview(itemnum, 1, detailnode, 0, menulength, previewfolder)
3996 if previewx != 9999:
4005 overlayimage=Image.new(
"RGBA",screensize, (0,0,0,0))
4006 draw=ImageDraw.Draw(overlayimage)
4008 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
4009 spunode = spumuxdom.documentElement.firstChild.firstChild
4011 drawThemeItem(0, 0, itemnum, detailnode, overlayimage, draw,
None,
None,
4012 "", spumuxdom, spunode, numberofitems, 0,
"")
4015 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
4016 bgimage.paste(overlayimage, (0,0), overlayimage)
4017 rgb_bgimage=bgimage.convert(
'RGB')
4018 rgb_bgimage.save(os.path.join(
getTempPath(),
"details-%s.jpg" % itemnum),
"JPEG", quality=99)
4021 if haspreview ==
True:
4025 write(
"Generating the detail preview images" )
4027 while framenum < numframes:
4028 if previewx != 9999:
4030 previewfile =
"preview-i%d-t1-f%d.jpg" % (1, framenum)
4031 imagefile = os.path.join(previewpath, previewfile)
4034 picture = Image.open(imagefile,
"r").resize((previeww, previewh))
4035 picture = picture.convert(
"RGBA")
4036 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % 1)
4037 if previewmask
is not None:
4038 bgimage.paste(picture, (previewx, previewy), previewmask)
4040 bgimage.paste(picture, (previewx, previewy))
4042 rgb_bgimage=bgimage.convert(
'RGB')
4043 rgb_bgimage.save(os.path.join(
getTempPath(),
"details-%s-f%06d.jpg" % (itemnum, framenum)),
"JPEG",quality=99)
4058 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"detailsspumux-%s.xml" % itemnum))
4060 write(
"Encoding Details Page %s" % itemnum)
4061 if haspreview ==
True:
4068 os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum),
4077 os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum),
4087 fh = open(file,
'rb')
4090 return Magic==
"RIFF"
4096 """encode audio to ac3 for better compression and compatability with NTSC players"""
4099 if not encodetoac3
and doesFileExist(os.path.join(folder,
'stream0.mp2')):
4101 write(
"Audio track 1 is in mp2 format - NOT re-encoding to ac3")
4102 elif doesFileExist(os.path.join(folder,
'stream0.mp2'))==
True:
4103 write(
"Audio track 1 is in mp2 format - re-encoding to ac3")
4104 encodeAudio(
"ac3",os.path.join(folder,
'stream0.mp2'), os.path.join(folder,
'stream0.ac3'),
True)
4105 elif doesFileExist(os.path.join(folder,
'stream0.mpa'))==
True:
4106 write(
"Audio track 1 is in mpa format - re-encoding to ac3")
4107 encodeAudio(
"ac3",os.path.join(folder,
'stream0.mpa'), os.path.join(folder,
'stream0.ac3'),
True)
4108 elif doesFileExist(os.path.join(folder,
'stream0.ac3'))==
True:
4109 write(
"Audio is already in ac3 format")
4111 fatalError(
"Track 1 - Unknown audio format or de-multiplex failed!")
4114 if not encodetoac3
and doesFileExist(os.path.join(folder,
'stream1.mp2')):
4116 write(
"Audio track 2 is in mp2 format - NOT re-encoding to ac3")
4117 elif doesFileExist(os.path.join(folder,
'stream1.mp2'))==
True:
4118 write(
"Audio track 2 is in mp2 format - re-encoding to ac3")
4119 encodeAudio(
"ac3",os.path.join(folder,
'stream1.mp2'), os.path.join(folder,
'stream1.ac3'),
True)
4120 elif doesFileExist(os.path.join(folder,
'stream1.mpa'))==
True:
4121 write(
"Audio track 2 is in mpa format - re-encoding to ac3")
4122 encodeAudio(
"ac3",os.path.join(folder,
'stream1.mpa'), os.path.join(folder,
'stream1.ac3'),
True)
4123 elif doesFileExist(os.path.join(folder,
'stream1.ac3'))==
True:
4124 write(
"Audio is already in ac3 format")
4140 """Choose the streams we want from the source file"""
4142 video = (-1,
'N/A', -1)
4143 audio1 = (-1,
'N/A', -1,
'N/A')
4144 audio2 = (-1,
'N/A', -1,
'N/A')
4147 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4149 if infoDOM.documentElement.tagName !=
"file":
4150 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4154 nodes = infoDOM.getElementsByTagName(
"video")
4155 if nodes.length == 0:
4156 write(
"Didn't find any video elements in stream info file.!!!")
4159 if nodes.length > 1:
4160 write(
"Found more than one video element in stream info file.!!!")
4162 video = (int(node.attributes[
"ffmpegindex"].value), node.attributes[
"codec"].value, int(node.attributes[
"id"].value))
4171 write(
"Preferred audio languages %s and %s" % (preferredlang1, preferredlang2))
4173 nodes = infoDOM.getElementsByTagName(
"audio")
4175 if nodes.length == 0:
4176 write(
"Didn't find any audio elements in stream info file.!!!")
4183 index = int(node.attributes[
"ffmpegindex"].value)
4184 lang = node.attributes[
"language"].value
4185 format = node.attributes[
"codec"].value.upper()
4186 pid = int(node.attributes[
"id"].value)
4187 if lang == preferredlang1
and format ==
"AC3":
4189 if pid < audio1[AUDIO_ID]:
4190 audio1 = (index, format, pid, lang)
4192 audio1 = (index, format, pid, lang)
4198 index = int(node.attributes[
"ffmpegindex"].value)
4199 lang = node.attributes[
"language"].value
4200 format = node.attributes[
"codec"].value.upper()
4201 pid = int(node.attributes[
"id"].value)
4202 if lang == preferredlang1
and format ==
"MP2":
4204 if pid < audio1[AUDIO_ID]:
4205 audio1 = (index, format, pid, lang)
4207 audio1 = (index, format, pid, lang)
4213 index = int(node.attributes[
"ffmpegindex"].value)
4214 format = node.attributes[
"codec"].value.upper()
4215 pid = int(node.attributes[
"id"].value)
4217 audio1 = (index, format, pid, lang)
4220 if format ==
"AC3" and audio1[AUDIO_CODEC] ==
"MP2":
4221 audio1 = (index, format, pid, lang)
4223 if pid < audio1[AUDIO_ID]:
4224 audio1 = (index, format, pid, lang)
4227 if preferredlang1 != preferredlang2
and nodes.length > 1:
4231 index = int(node.attributes[
"ffmpegindex"].value)
4232 lang = node.attributes[
"language"].value
4233 format = node.attributes[
"codec"].value.upper()
4234 pid = int(node.attributes[
"id"].value)
4235 if lang == preferredlang2
and format ==
"AC3":
4237 if pid < audio2[AUDIO_ID]:
4238 audio2 = (index, format, pid, lang)
4240 audio2 = (index, format, pid, lang)
4246 index = int(node.attributes[
"ffmpegindex"].value)
4247 lang = node.attributes[
"language"].value
4248 format = node.attributes[
"codec"].value.upper()
4249 pid = int(node.attributes[
"id"].value)
4250 if lang == preferredlang2
and format ==
"MP2":
4252 if pid < audio2[AUDIO_ID]:
4253 audio2 = (index, format, pid, lang)
4255 audio2 = (index, format, pid, lang)
4261 index = int(node.attributes[
"ffmpegindex"].value)
4262 format = node.attributes[
"codec"].value.upper()
4263 pid = int(node.attributes[
"id"].value)
4266 if pid != audio1[AUDIO_ID]:
4267 audio2 = (index, format, pid, lang)
4270 if format ==
"AC3" and audio2[AUDIO_CODEC] ==
"MP2" and pid != audio1[AUDIO_ID]:
4271 audio2 = (index, format, pid, lang)
4273 if pid < audio2[AUDIO_ID]
and pid != audio1[AUDIO_ID]:
4274 audio2 = (index, format, pid, lang)
4276 write(
"Video id: 0x%x, Audio1: [%d] 0x%x (%s, %s), Audio2: [%d] - 0x%x (%s, %s)" % \
4277 (video[VIDEO_ID], audio1[AUDIO_INDEX], audio1[AUDIO_ID], audio1[AUDIO_CODEC], audio1[AUDIO_LANG], \
4278 audio2[AUDIO_INDEX], audio2[AUDIO_ID], audio2[AUDIO_CODEC], audio2[AUDIO_LANG]))
4280 return (video, audio1, audio2)
4292 """Choose the subtitle stream we want from the source file"""
4294 subtitle = (-1,
'N/A', -1,
'N/A')
4297 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4299 if infoDOM.documentElement.tagName !=
"file":
4300 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4304 nodes = infoDOM.getElementsByTagName(
"subtitle")
4305 if nodes.length == 0:
4306 write(
"Didn't find any subtitle elements in stream info file.")
4309 write(
"Preferred languages %s and %s" % (preferredlang1, preferredlang2))
4314 index = int(node.attributes[
"ffmpegindex"].value)
4315 lang = node.attributes[
"language"].value
4316 format = node.attributes[
"codec"].value.upper()
4317 pid = int(node.attributes[
"id"].value)
4318 if not found
and lang == preferredlang1
and format ==
"dvbsub":
4319 subtitle = (index, format, pid, lang)
4325 index = int(node.attributes[
"ffmpegindex"].value)
4326 lang = node.attributes[
"language"].value
4327 format = node.attributes[
"codec"].value.upper()
4328 pid = int(node.attributes[
"id"].value)
4329 if not found
and lang == preferredlang2
and format ==
"dvbsub":
4330 subtitle = (index, format, pid, lang)
4336 index = int(node.attributes[
"ffmpegindex"].value)
4337 format = node.attributes[
"codec"].value.upper()
4338 pid = int(node.attributes[
"id"].value)
4340 subtitle = (index, format, pid, lang)
4343 write(
"Subtitle id: 0x%x" % (subtitle[SUBTITLE_ID]))
4351 """figure out what aspect ratio we want from the source file"""
4357 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4359 if infoDOM.documentElement.tagName !=
"file":
4360 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4364 nodes = infoDOM.getElementsByTagName(
"video")
4365 if nodes.length == 0:
4366 write(
"Didn't find any video elements in stream info file.!!!")
4369 if nodes.length > 1:
4370 write(
"Found more than one video element in stream info file.!!!")
4373 ar = float(node.attributes[
"aspectratio"].value)
4374 if ar > float(4.0/3.0 - 0.01)
and ar < float(4.0/3.0 + 0.01):
4376 write(
"Aspect ratio is 4:3")
4377 elif ar > float(16.0/9.0 - 0.01)
and ar < float(16.0/9.0 + 0.01):
4378 aspectratio =
"16:9"
4379 write(
"Aspect ratio is 16:9")
4381 write(
"Unknown aspect ratio %f - Using 16:9" % ar)
4382 aspectratio =
"16:9"
4384 aspectratio =
"16:9"
4392 """Get the video codec from the streaminfo.xml for the file"""
4395 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4397 if infoDOM.documentElement.tagName !=
"file":
4398 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4400 nodes = infoDOM.getElementsByTagName(
"video")
4401 if nodes.length == 0:
4402 write(
"Didn't find any video elements in stream info file!!!")
4405 if nodes.length > 1:
4406 write(
"Found more than one video element in stream info file!!!")
4408 return node.attributes[
"codec"].value
4414 """Get the overall file type from the streaminfo.xml for the file"""
4417 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4419 if infoDOM.documentElement.tagName !=
"file":
4420 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4422 nodes = infoDOM.getElementsByTagName(
"file")
4423 if nodes.length == 0:
4424 write(
"Didn't find any file elements in stream info file!!!")
4427 if nodes.length > 1:
4428 write(
"Found more than one file element in stream info file!!!")
4431 return node.attributes[
"type"].value
4441 streamList =
"0x%x" % video[VIDEO_ID]
4443 if audio1[AUDIO_ID] != -1:
4444 streamList +=
",0x%x" % audio1[AUDIO_ID]
4446 if audio2[AUDIO_ID] != -1:
4447 streamList +=
",0x%x" % audio2[AUDIO_ID]
4452 if subtitles[SUBTITLE_ID] != -1:
4453 streamList +=
",0x%x" % subtitles[SUBTITLE_ID]
4462 """return true if the file is dvd compliant"""
4464 if not getVideoCodec(folder).lower().startswith(
"mpeg2video"):
4471 videosize =
getVideoSize(os.path.join(folder,
"streaminfo.xml"))
4474 if file.hasAttribute(
"encodingprofile"):
4475 if file.attributes[
"encodingprofile"].value !=
"NONE":
4476 write(
"File will be re-encoded using profile %s" % file.attributes[
"encodingprofile"].value)
4481 if file.hasAttribute(
"encodingprofile"):
4482 if file.attributes[
"encodingprofile"].value ==
"NONE":
4483 write(
"WARNING: File does not have a DVD compliant resolution but "
4484 "you have selected not to re-encode the file")
4496 """Process a single video/recording file ready for burning."""
4508 """Process a single video/recording file ready for burning."""
4510 write(
"*************************************************************")
4511 write(
"Processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
4512 write(
"*************************************************************")
4522 if file.hasAttribute(
"localfilename"):
4523 mediafile=file.attributes[
"localfilename"].value
4524 elif file.attributes[
"type"].value==
"recording":
4525 mediafile = file.attributes[
"filename"].value
4526 elif file.attributes[
"type"].value==
"video":
4527 mediafile=os.path.join(videopath, file.attributes[
"filename"].value)
4528 elif file.attributes[
"type"].value==
"file":
4529 mediafile=file.attributes[
"filename"].value
4531 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
4534 infoDOM = xml.dom.minidom.parse( os.path.join(folder,
"info.xml") )
4536 if infoDOM.documentElement.tagName !=
"fileinfo":
4537 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
4541 if file.attributes[
"type"].value ==
"recording":
4545 if (
getVideoCodec(folder)).lower().startswith(
"mpeg2video"):
4546 if file.attributes[
"usecutlist"].value ==
"1" and getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes":
4548 if file.hasAttribute(
"localfilename"):
4549 localfile = file.attributes[
"localfilename"].value
4552 write(
"File has a cut list - running mythtranscode to remove unwanted segments")
4553 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4554 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4555 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
True, localfile):
4556 mediafile = os.path.join(folder,
'newfile.mpg')
4558 write(
"Failed to run mythtranscode to remove unwanted segments")
4562 if (alwaysRunMythtranscode ==
True or
4565 if file.hasAttribute(
"localfilename"):
4566 localfile = file.attributes[
"localfilename"].value
4569 write(
"Running mythtranscode --mpeg2 to fix any errors")
4570 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4571 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4572 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
False, localfile):
4573 mediafile = os.path.join(folder,
'newfile.mpg')
4575 write(
"Failed to run mythtranscode to fix any errors")
4582 if (alwaysRunMythtranscode ==
True and
4585 if file.hasAttribute(
"localfilename"):
4586 localfile = file.attributes[
"localfilename"].value
4588 localfile = file.attributes[
"filename"].value
4589 write(
"Running mythtranscode --mpeg2 to fix any errors")
4592 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
False, localfile):
4593 mediafile = os.path.join(folder,
'newfile.mpg')
4595 write(
"Failed to run mythtranscode to fix any errors")
4613 write(
"Re-encoding audio and video from nuv file")
4616 if file.hasAttribute(
"encodingprofile"):
4617 profile = file.attributes[
"encodingprofile"].value
4619 profile = defaultEncodingProfile
4621 if file.hasAttribute(
"localfilename"):
4622 mediafile = file.attributes[
"localfilename"].value
4626 elif file.attributes[
"type"].value ==
"recording":
4628 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4629 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4630 usecutlist = (file.attributes[
"usecutlist"].value ==
"1" and
4631 getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes")
4637 encodeNuvToMPEG2(chanid, starttime, mediafile, os.path.join(folder,
"newfile2.mpg"), folder,
4638 profile, usecutlist)
4639 mediafile = os.path.join(folder,
'newfile2.mpg')
4651 write(
"Re-encoding audio and video")
4654 if file.hasAttribute(
"localfilename"):
4655 mediafile = file.attributes[
"localfilename"].value
4658 if file.hasAttribute(
"encodingprofile"):
4659 profile = file.attributes[
"encodingprofile"].value
4661 profile = defaultEncodingProfile
4665 audio1, audio2, aspectratio, profile)
4666 mediafile = os.path.join(folder,
'newfile2.mpg')
4670 if debug_keeptempfiles==
False:
4671 if os.path.exists(os.path.join(folder,
"newfile.mpg")):
4672 os.remove(os.path.join(folder,
'newfile.mpg'))
4683 write(
"Splitting MPEG stream into audio and video parts")
4687 if debug_keeptempfiles==
False:
4688 if os.path.exists(os.path.join(folder,
"newfile.mpg")):
4689 os.remove(os.path.join(folder,
'newfile.mpg'))
4690 if os.path.exists(os.path.join(folder,
"newfile2.mpg")):
4691 os.remove(os.path.join(folder,
'newfile2.mpg'))
4698 titleImage = os.path.join(folder,
"title.jpg")
4699 if not os.path.exists(titleImage):
4701 if file.attributes[
"type"].value ==
"recording":
4702 previewImage = file.attributes[
"filename"].value +
".png"
4703 if usebookmark ==
True and os.path.exists(previewImage):
4704 copy(previewImage, titleImage)
4710 write(
"*************************************************************")
4711 write(
"Finished processing '%s'" % file.attributes[
"filename"].value)
4712 write(
"*************************************************************")
4720 """Process a single video/recording file ready for burning."""
4722 write(
"*************************************************************")
4723 write(
"Processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
4724 write(
"*************************************************************")
4734 if file.hasAttribute(
"localfilename"):
4735 mediafile=file.attributes[
"localfilename"].value
4736 elif file.attributes[
"type"].value==
"recording":
4737 mediafile = file.attributes[
"filename"].value
4738 elif file.attributes[
"type"].value==
"video":
4739 mediafile=os.path.join(videopath, file.attributes[
"filename"].value)
4740 elif file.attributes[
"type"].value==
"file":
4741 mediafile=file.attributes[
"filename"].value
4743 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
4746 infoDOM = xml.dom.minidom.parse( os.path.join(folder,
"info.xml") )
4748 if infoDOM.documentElement.tagName !=
"fileinfo":
4749 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
4767 write(
"Re-encoding audio and video from nuv file")
4770 if file.hasAttribute(
"encodingprofile"):
4771 profile = file.attributes[
"encodingprofile"].value
4773 profile = defaultEncodingProfile
4775 if file.hasAttribute(
"localfilename"):
4776 mediafile = file.attributes[
"localfilename"].value
4780 elif file.attributes[
"type"].value ==
"recording":
4782 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4783 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4784 usecutlist = (file.attributes[
"usecutlist"].value ==
"1" and
4785 getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes")
4791 encodeNuvToMPEG2(chanid, starttime, mediafile, os.path.join(folder,
"newfile2.mpg"), folder,
4792 profile, usecutlist)
4793 mediafile = os.path.join(folder,
'newfile2.mpg')
4805 write(
"Re-encoding audio and video")
4808 if file.hasAttribute(
"localfilename"):
4809 mediafile = file.attributes[
"localfilename"].value
4812 if file.hasAttribute(
"encodingprofile"):
4813 profile = file.attributes[
"encodingprofile"].value
4815 profile = defaultEncodingProfile
4819 audio1, audio2, aspectratio, profile)
4820 mediafile = os.path.join(folder,
'newfile2.mpg')
4823 if os.path.exists(os.path.join(folder,
"newfile1.mpg")):
4824 os.remove(os.path.join(folder,
'newfile1.mpg'))
4840 if file.attributes[
"type"].value ==
"recording":
4841 if file.attributes[
"usecutlist"].value ==
"1" and getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes":
4842 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4843 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4844 write(
"File has a cut list - running Project-X to remove unwanted segments")
4845 if not runProjectX(chanid, starttime, folder,
True, mediafile):
4846 fatalError(
"Failed to run Project-X to remove unwanted segments and demux")
4849 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4850 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4851 write(
"Using Project-X to demux file")
4852 if not runProjectX(chanid, starttime, folder,
False, mediafile):
4853 fatalError(
"Failed to run Project-X to demux file")
4858 write(
"Running Project-X to demux file")
4859 if not runProjectX(chanid, starttime, folder,
False, mediafile):
4860 fatalError(
"Failed to run Project-X to demux file")
4867 titleImage = os.path.join(folder,
"title.jpg")
4868 if not os.path.exists(titleImage):
4870 if file.attributes[
"type"].value ==
"recording":
4871 previewImage = file.attributes[
"filename"].value +
".png"
4872 if usebookmark ==
True and os.path.exists(previewImage):
4873 copy(previewImage, titleImage)
4879 write(
"*************************************************************")
4880 write(
"Finished processing file '%s'" % file.attributes[
"filename"].value)
4881 write(
"*************************************************************")
4887 '''go through the list of files looking for files on remote filesytems
4888 and copy them to a local file for quicker processing'''
4889 localTmpPath = os.path.join(tmpPath,
"localcopy")
4891 tmpfile = node.attributes[
"filename"].value
4892 filename = os.path.basename(tmpfile)
4896 if res == 2
and copyremoteFiles==
True:
4898 write(
"Copying file from " + tmpfile)
4899 write(
"to " + os.path.join(localTmpPath, filename))
4903 copy(tmpfile, os.path.join(localTmpPath, filename))
4906 node.setAttribute(
"localfilename", os.path.join(localTmpPath, filename))
4909 write(
"Copying file from " + tmpfile)
4910 localfile = os.path.join(localTmpPath, filename)
4911 write(
"to " + localfile)
4918 node.setAttribute(
"localfilename", localfile)
4925 """Starts processing a MythBurn job, expects XML nodes to be passed as input."""
4926 global wantIntro, wantMainMenu, wantChapterMenu, wantDetailsPage
4927 global themeDOM, themeName, themeFonts
4930 media=job.getElementsByTagName(
"media")
4934 themeName=job.attributes[
"theme"].value
4938 fatalError(
"Failed to validate theme (%s)" % themeName)
4946 nodes=themeDOM.getElementsByTagName(
"intro")
4947 wantIntro = (nodes.length > 0)
4949 nodes=themeDOM.getElementsByTagName(
"menu")
4950 wantMainMenu = (nodes.length > 0)
4952 nodes=themeDOM.getElementsByTagName(
"submenu")
4953 wantChapterMenu = (nodes.length > 0)
4955 nodes=themeDOM.getElementsByTagName(
"detailspage")
4956 wantDetailsPage = (nodes.length > 0)
4958 write(
"wantIntro: %d, wantMainMenu: %d, wantChapterMenu: %d, wantDetailsPage: %d" \
4959 % (wantIntro, wantMainMenu, wantChapterMenu, wantDetailsPage))
4961 if videomode==
"ntsc":
4964 elif videomode==
"pal":
4968 fatalError(
"Unknown videomode is set (%s)" % videomode)
4970 write(
"Final DVD Video format will be " + videomode)
4974 files=media[0].getElementsByTagName(
"file")
4976 if files.length > 0:
4977 write(
"There are %s file(s) to process" % files.length)
4979 if debug_secondrunthrough==
False:
4982 localCopyFolder=os.path.join(
getTempPath(),
"localcopy")
4983 os.makedirs(localCopyFolder)
4995 if debug_secondrunthrough==
False:
5000 if debug_secondrunthrough==
False:
5026 if not wantMainMenu
and not wantChapterMenu:
5028 elif not wantMainMenu:
5034 if mediatype == DVD_DL:
5049 os.path.join(folder,
'stream0'),
5050 os.path.join(folder,
'stream1'),
5051 os.path.join(folder,
'final.vob'),
5058 if debug_keeptempfiles==
False:
5063 if os.path.exists(os.path.join(folder,
"stream.mv2")):
5064 os.remove(os.path.join(folder,
'stream.mv2'))
5065 if os.path.exists(os.path.join(folder,
"stream0.mp2")):
5066 os.remove(os.path.join(folder,
'stream0.mp2'))
5067 if os.path.exists(os.path.join(folder,
"stream1.mp2")):
5068 os.remove(os.path.join(folder,
'stream1.mp2'))
5069 if os.path.exists(os.path.join(folder,
"stream0.ac3")):
5070 os.remove(os.path.join(folder,
'stream0.ac3'))
5071 if os.path.exists(os.path.join(folder,
"stream1.ac3")):
5072 os.remove(os.path.join(folder,
'stream1.ac3'))
5076 infoDOM = xml.dom.minidom.parse( os.path.join(
getItemTempPath(1),
"info.xml") )
5078 if infoDOM.documentElement.tagName !=
"fileinfo":
5079 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
5082 title = title.encode(
'ascii',
'replace').decode(
'ascii',
'replace')
5083 title = title.strip()
5088 while (index < len(title))
and (index < 32):
5089 if title[index].isalnum
and title[index] !=
' ':
5090 title_new += title[index]
5095 title = title_new.upper()
5101 if docreateiso ==
True or mediatype == FILE:
5105 if doburn ==
True and mediatype != FILE:
5109 if mediatype == FILE
and savefilename !=
"":
5110 write(
"Moving ISO image to: %s" % savefilename)
5112 os.rename(os.path.join(
getTempPath(),
'mythburn.iso'), savefilename)
5114 f1 = open(os.path.join(
getTempPath(),
'mythburn.iso'),
'rb')
5115 f2 = open(savefilename,
'wb')
5116 data = f1.read(1024 * 1024)
5119 data = f1.read(1024 * 1024)
5122 os.unlink(os.path.join(
getTempPath(),
'mythburn.iso'))
5124 write(
"Nothing to do! (files)")
5126 write(
"Nothing to do! (media)")
5134 -h/--help (Show this usage)
5135 -j/--jobfile file (use file as the job file)
5136 -l/--progresslog file (log file to output progress messages)
5144 global sharepath, scriptpath, cpuCount, videopath, gallerypath, musicpath
5145 global videomode, temppath, logpath, dvddrivepath, dbVersion, preferredlang1
5146 global preferredlang2, useFIFO, encodetoac3, alwaysRunMythtranscode
5147 global copyremoteFiles, mainmenuAspectRatio, chaptermenuAspectRatio, dateformat
5148 global timeformat, clearArchiveTable, nicelevel, drivespeed, path_mplex
5149 global path_dvdauthor, path_mkisofs, path_growisofs, path_M2VRequantiser, addSubtitles
5150 global path_jpeg2yuv, path_spumux, path_mpeg2enc, path_projectx, useprojectx, progresslog
5151 global progressfile, jobfile
5153 write(
"mythburn.py (%s) starting up..." % VERSION)
5156 if not hasattr(sys,
"hexversion")
or sys.hexversion < 0x20305F0:
5157 sys.stderr.write(
"Sorry, your Python is too old. Please upgrade at least to 2.3.5\n")
5161 scriptpath = os.path.dirname(sys.argv[0])
5162 scriptpath = os.path.abspath(scriptpath)
5163 write(
"script path:" + scriptpath)
5166 sharepath = os.path.split(scriptpath)[0]
5167 sharepath = os.path.split(sharepath)[0]
5168 write(
"myth share path:" + sharepath)
5172 opts, args = getopt.getopt(sys.argv[1:],
"j:hl:", [
"jobfile=",
"help",
"progresslog="])
5173 except getopt.GetoptError:
5179 if o
in (
"-h",
"--help"):
5182 if o
in (
"-j",
"--jobfile"):
5184 write(
"passed job file: " + a)
5185 if o
in (
"-l",
"--progresslog"):
5186 progresslog = str(a)
5187 write(
"passed progress log file: " + a)
5190 if progresslog !=
"":
5191 if os.path.exists(progresslog):
5192 os.remove(progresslog)
5193 progressfile = codecs.open(progresslog,
'w',
'utf-8')
5194 write(
"mythburn.py (%s) starting up..." % VERSION)
5199 saveSetting(
"MythArchiveLastRunStart", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5201 saveSetting(
"MythArchiveLastRunStatus",
"Running")
5208 if not os.environ[
'PATH'].endswith(
':'):
5209 os.environ[
'PATH'] +=
":"
5210 os.environ[
'PATH'] +=
"/bin:/sbin:/usr/local/bin:/usr/bin:/opt/bin:" + installPrefix +
"/bin:"
5214 videopath = defaultsettings.get(
"VideoStartupDir",
None)
5215 gallerypath = defaultsettings.get(
"GalleryDir",
None)
5216 musicpath = defaultsettings.get(
"MusicLocation",
None)
5217 videomode = defaultsettings[
"MythArchiveVideoFormat"].lower()
5218 temppath = os.path.join(defaultsettings[
"MythArchiveTempDir"],
"work")
5219 logpath = os.path.join(defaultsettings[
"MythArchiveTempDir"],
"logs")
5220 write(
"temppath: " + temppath)
5221 write(
"logpath: " + logpath)
5222 dvddrivepath = defaultsettings[
"MythArchiveDVDLocation"]
5223 dbVersion = defaultsettings[
"DBSchemaVer"]
5224 preferredlang1 = defaultsettings[
"ISO639Language0"]
5225 preferredlang2 = defaultsettings[
"ISO639Language1"]
5226 useFIFO = (defaultsettings[
"MythArchiveUseFIFO"] ==
'1')
5227 alwaysRunMythtranscode = (defaultsettings[
"MythArchiveAlwaysUseMythTranscode"] ==
'1')
5228 copyremoteFiles = (defaultsettings[
"MythArchiveCopyRemoteFiles"] ==
'1')
5229 mainmenuAspectRatio = defaultsettings[
"MythArchiveMainMenuAR"]
5230 chaptermenuAspectRatio = defaultsettings[
"MythArchiveChapterMenuAR"]
5231 dateformat = defaultsettings.get(
"MythArchiveDateFormat",
"%a %d %b %Y")
5232 timeformat = defaultsettings.get(
"MythArchiveTimeFormat",
"%I:%M %p")
5233 drivespeed = int(defaultsettings.get(
"MythArchiveDriveSpeed",
"0"))
5234 if "MythArchiveClearArchiveTable" in defaultsettings:
5235 clearArchiveTable = (defaultsettings[
"MythArchiveClearArchiveTable"] ==
'1')
5236 nicelevel = defaultsettings.get(
"JobQueueCPU",
"0")
5239 path_mplex = [defaultsettings[
"MythArchiveMplexCmd"], os.path.split(defaultsettings[
"MythArchiveMplexCmd"])[1]]
5240 path_dvdauthor = [defaultsettings[
"MythArchiveDvdauthorCmd"], os.path.split(defaultsettings[
"MythArchiveDvdauthorCmd"])[1]]
5241 path_mkisofs = [defaultsettings[
"MythArchiveMkisofsCmd"], os.path.split(defaultsettings[
"MythArchiveMkisofsCmd"])[1]]
5242 path_growisofs = [defaultsettings[
"MythArchiveGrowisofsCmd"], os.path.split(defaultsettings[
"MythArchiveGrowisofsCmd"])[1]]
5243 path_M2VRequantiser = [defaultsettings[
"MythArchiveM2VRequantiserCmd"], os.path.split(defaultsettings[
"MythArchiveM2VRequantiserCmd"])[1]]
5244 path_jpeg2yuv = [defaultsettings[
"MythArchiveJpeg2yuvCmd"], os.path.split(defaultsettings[
"MythArchiveJpeg2yuvCmd"])[1]]
5245 path_spumux = [defaultsettings[
"MythArchiveSpumuxCmd"], os.path.split(defaultsettings[
"MythArchiveSpumuxCmd"])[1]]
5246 path_mpeg2enc = [defaultsettings[
"MythArchiveMpeg2encCmd"], os.path.split(defaultsettings[
"MythArchiveMpeg2encCmd"])[1]]
5248 path_projectx = [defaultsettings[
"MythArchiveProjectXCmd"], os.path.split(defaultsettings[
"MythArchiveProjectXCmd"])[1]]
5249 useprojectx = (defaultsettings[
"MythArchiveUseProjectX"] ==
'1')
5250 addSubtitles = (defaultsettings[
"MythArchiveAddSubtitles"] ==
'1')
5253 if path_projectx[0] ==
"":
5256 if nicelevel ==
'1':
5258 elif nicelevel ==
'2':
5263 nicelevel = os.nice(nicelevel)
5264 write(
"Setting process priority to %s" % nicelevel)
5269 write(
"Cannot change ionice level")
5271 write(
"Setting ionice level to idle")
5272 p = psutil.Process(os.getpid())
5273 p.ionice(psutil.IOPRIO_CLASS_IDLE)
5280 lckpath = os.path.join(logpath,
"mythburn.lck")
5282 fd = os.open(lckpath, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
5284 os.write(fd, b
"%d\n" % os.getpid())
5289 except OSError
as e:
5290 if e.errno == errno.EEXIST:
5291 write(
"Lock file exists -- already running???")
5299 jobDOM = xml.dom.minidom.parse(jobfile)
5302 if jobDOM.documentElement.tagName !=
"mythburn":
5307 jobs=jobDOM.getElementsByTagName(
"job")
5310 write(
"Processing Mythburn job number %s." % jobcount)
5313 options = job.getElementsByTagName(
"options")
5314 if options.length > 0:
5322 if clearArchiveTable ==
True:
5325 saveSetting(
"MythArchiveLastRunStatus",
"Success")
5326 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5327 write(
"Finished processing jobs!!!")
5333 os.system(
"chmod -R a+rw-x+X %s" % defaultsettings[
"MythArchiveTempDir"])
5338 traceback.print_exc(file=sys.stdout)
5339 if progresslog !=
"":
5340 traceback.print_exc(file=progressfile)
5343 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5345 if __name__ ==
"__main__":
5348 os.putenv(
"LC_ALL", oldlocale)