3 from __future__
import unicode_literals
65 VERSION=
"0.2.20200122-1"
70 debug_keeptempfiles =
False
78 debug_secondrunthrough =
False
81 defaultEncodingProfile =
"SP"
88 addCutlistChapters =
False
103 import xml.dom.minidom
104 from PIL
import Image
105 from PIL
import ImageDraw
106 from PIL
import ImageFont
107 from PIL
import ImageColor
111 from fcntl
import ioctl
122 CDS_DRIVE_NOT_READY = 3
126 CDROM_DRIVE_STATUS = 0x5326
127 CDROM_LOCKDOOR = 0x5329
129 from shutil
import copy
132 from MythTV
import datetime
133 from MythTV.altdict
import OrdDict
146 dvdPALHalfD1=
"352x576"
147 dvdNTSCHalfD1=
"352x480"
148 dvdPALD1=
"%sx%s" % (dvdPAL[0],dvdPAL[1])
149 dvdNTSCD1=
"%sx%s" % (dvdNTSC[0],dvdNTSC[1])
158 aspectRatioThreshold = 1.4
176 alwaysRunMythtranscode =
False
177 copyremoteFiles =
False
180 clearArchiveTable =
True
185 mainmenuAspectRatio =
"16:9"
189 chaptermenuAspectRatio =
"Video"
192 chapterLength = 5 * 60;
199 progressfile = codecs.open(
"/dev/null",
'w',
'utf-8')
202 dvddrivepath =
"/dev/dvd"
227 MVID = MythTV.MythVideo(db=DB)
230 configHostname = DB.gethostname()
236 oldlocale = os.environ[
"LC_ALL"]
239 os.putenv(
"LC_ALL",
"en_US.UTF-8")
251 sys.stdout.write(
"Using simple_fix_rtl\n")
252 fix_rtl = simple_fix_rtl
254 sys.stdout.write(
"Using pyfribidi.log2vis\n")
255 fix_rtl = pyfribidi.log2vis
261 def __init__(self, name=None, fontFile=None, size=19, color="white", effect="normal", shadowColor="black", shadowSize=1):
272 if self.
font is None:
278 if self.
font is None:
286 image = Image.new(
"RGBA", (textwidth + (self.
shadowSize * 2), textheight), (0,0,0,0))
287 draw = ImageDraw.ImageDraw(image)
289 if self.
effect ==
"shadow":
291 draw.text((0,0), text, font=self.
font, fill=color)
292 elif self.
effect ==
"outline":
299 draw.text((0,0), text, font=self.
font, fill=color)
301 bbox = image.getbbox()
302 image = image.crop(bbox)
309 """Simple place to channel all text output through"""
311 if sys.version_info == 2:
312 sys.stdout.write((text +
"\n").encode(
"utf-8",
"replace"))
314 sys.stdout.write(text +
"\n")
317 if progress ==
True and progresslog !=
"":
318 progressfile.write(time.strftime(
"%Y-%m-%d %H:%M:%S ") + text +
"\n")
325 """Display an error message and exit app"""
327 write(
"ERROR: " + msg)
328 write(
"See mythburn.log for more information.")
332 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
339 """Display a warning message"""
341 write(
"WARNING: " + msg)
349 """Return the input string with single quotes escaped."""
350 return str.replace(
"'",
"'\"'\"'")
356 """This is the folder where all temporary files will be created."""
363 """return the number of CPUs"""
365 cpustat = codecs.open(
"/proc/cpuinfo",
'r',
'utf-8')
366 cpudata = cpustat.readlines()
371 tokens = line.split()
373 if tokens[0] ==
"processor":
379 write(
"Found %d CPUs" % cpucount)
387 """This is the folder where all encoder profile files are located."""
388 return os.path.join(sharepath,
"mytharchive",
"encoder_profiles")
394 """Returns true/false if a given file or path exists."""
395 return os.path.exists( file )
401 arg = arg.replace(
'"',
'\\"')
402 arg = arg.replace(
'`',
'\\`')
409 """Returns the text contents from a given XML element."""
410 if node.childNodes.length>0:
411 return node.childNodes[0].data
419 """Find a theme file - first look in the specified theme directory then look in the
420 shared music and image directories"""
421 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"themes", theme, file)):
422 return os.path.join(sharepath,
"mytharchive",
"themes", theme, file)
424 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"images", file)):
425 return os.path.join(sharepath,
"mytharchive",
"images", file)
427 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"intro", file)):
428 return os.path.join(sharepath,
"mytharchive",
"intro", file)
430 if os.path.exists(os.path.join(sharepath,
"mytharchive",
"music", file)):
431 return os.path.join(sharepath,
"mytharchive",
"music", file)
433 fatalError(
"Cannot find theme file '%s' in theme '%s'" % (file, theme))
439 return os.path.join(sharepath,
"fonts", fontname)
445 return os.path.join(
getTempPath(),
"%s" % itemnumber)
453 write(
"Looking for: " + file)
460 if videomode==
"ntsc":
461 return videoresolution==(720,480)
or videoresolution==(704,480)
or videoresolution==(352,480)
or videoresolution==(352,240)
463 return videoresolution==(720,576)
or videoresolution==(704,576)
or videoresolution==(352,576)
or videoresolution==(352,288)
469 """Does what it says on the tin!."""
470 for root, dirs, deletefiles
in os.walk(folder, topdown=
False):
471 for name
in deletefiles:
472 os.remove(os.path.join(root, name))
478 for root, dirs, files
in os.walk(folder, topdown=
False):
480 os.remove(os.path.join(root, name))
482 if os.path.islink(os.path.join(root, name)):
483 os.remove(os.path.join(root, name))
485 os.rmdir(os.path.join(root, name))
491 """Checks to see if the user has cancelled this run"""
492 if os.path.exists(os.path.join(logpath,
"mythburncancel.lck")):
493 os.remove(os.path.join(logpath,
"mythburncancel.lck"))
495 write(
"Job has been cancelled at users request")
506 result = os.system(command.encode(
'utf-8'))
508 if os.WIFEXITED(result):
509 result = os.WEXITSTATUS(result)
517 """Convert a time in seconds to a frame position"""
519 framespersecond=frameratePAL
521 framespersecond=framerateNTSC
523 frames=int(seconds * framespersecond)
529 def encodeMenu(background, tempvideo, music, musiclength, tempmovie, xmlfile, finaloutput, aspectratio):
531 framespersecond=frameratePAL
533 framespersecond=framerateNTSC
535 totalframes=int(musiclength * framespersecond)
537 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" \
541 fatalError(
"Failed while running jpeg2yuv - %s" % command)
546 fatalError(
"Failed while running mplex - %s" % command)
552 fatalError(
"Failed while running spumux - %s" % command)
554 os.rename(tempmovie, finaloutput)
556 if os.path.exists(tempvideo):
558 if os.path.exists(tempmovie):
566 """Returns the XML node for the given encoding profile"""
571 if videomode ==
"ntsc":
572 filename = os.path.expanduser(
"~/.mythtv/MythArchive/ffmpeg_dvd_ntsc.xml")
574 filename = os.path.expanduser(
"~/.mythtv/MythArchive/ffmpeg_dvd_pal.xml")
576 if not os.path.exists(filename):
578 if videomode ==
"ntsc":
583 write(
"Using encoder profiles from %s" % filename)
585 DOM = xml.dom.minidom.parse(filename)
588 if DOM.documentElement.tagName !=
"encoderprofiles":
589 fatalError(
"Profile xml file doesn't look right (%s)" % filename)
591 profiles = DOM.getElementsByTagName(
"profile")
592 for node
in profiles:
593 if getText(node.getElementsByTagName(
"name")[0]) == profile:
594 write(
"Encoding profile (%s) found" % profile)
597 write(
'WARNING: Encoding profile "' + profile +
'" not found.')
598 write(
'Using default profile "' + defaultEncodingProfile +
'".')
599 for node
in profiles:
600 if getText(node.getElementsByTagName(
"name")[0]) == defaultEncodingProfile:
601 write(
"Encoding profile (%s) found" % defaultEncodingProfile)
604 fatalError(
'Neither encoding profile "' + profile +
'" nor default enocding profile "' + defaultEncodingProfile +
'" found. Giving up.')
611 """Loads the XML file from disk for a specific theme"""
614 themeDOM = xml.dom.minidom.parse(
getThemeFile(theme,
"theme.xml") )
616 if themeDOM.documentElement.tagName !=
"mythburntheme":
617 fatalError(
"Theme xml file doesn't look right (%s)" % theme)
624 """Returns the length of a video file (in seconds)"""
627 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
630 if infoDOM.documentElement.tagName !=
"file":
632 file = infoDOM.getElementsByTagName(
"file")[0]
633 if file.attributes[
"cutduration"].value !=
'N/A':
634 duration = int(file.attributes[
"cutduration"].value)
645 """Returns the audio bitrate and no of channels for a file from its streaminfo.xml"""
648 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
651 if infoDOM.documentElement.tagName !=
"file":
652 fatalError(
"Stream info file doesn't look right (%s)" % os.path.join(folder,
'streaminfo.xml'))
653 audio = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"audio")[0]
655 samplerate = audio.attributes[
"samplerate"].value
656 channels = audio.attributes[
"channels"].value
658 return (samplerate, channels)
665 """Returns the video resolution, fps and aspect ratio for the video file from the streaminfo.xml file"""
668 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
671 if infoDOM.documentElement.tagName !=
"file":
673 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
675 if video.attributes[
"aspectratio"].value !=
'N/A':
676 aspect_ratio = video.attributes[
"aspectratio"].value
678 aspect_ratio =
"1.77778"
680 videores = video.attributes[
"width"].value +
'x' + video.attributes[
"height"].value
681 fps = video.attributes[
"fps"].value
689 if float(fr) != float(fps):
690 write(
"WARNING: frames rates do not match")
691 write(
"The frame rate for %s should be %s but the stream info file "
692 "report a fps of %s" % (videomode, fr, fps))
695 return (videores, fps, aspect_ratio)
701 """Returns the aspect ratio of the video file (1.333, 1.778, etc)"""
704 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
707 if infoDOM.documentElement.tagName !=
"file":
709 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
710 if video.attributes[
"aspectratio"].value !=
'N/A':
711 aspect_ratio = float(video.attributes[
"aspectratio"].value)
713 aspect_ratio = 1.77778;
714 write(
"aspect ratio is: %s" % aspect_ratio)
721 """Returns the sync offset between the video and first audio stream"""
725 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(index),
'streaminfo.xml'))
728 if infoDOM.documentElement.tagName !=
"file":
731 video = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"video")[0]
732 video_start = float(video.attributes[
"start_time"].value)
734 audio = infoDOM.getElementsByTagName(
"file")[0].getElementsByTagName(
"streams")[0].getElementsByTagName(
"audio")[0]
735 audio_start = float(audio.attributes[
"start_time"].value)
740 sync_offset = int((video_start - audio_start) * 1000)
751 minutes = int(duration / 60)
752 seconds = duration % 60
753 hours = int(minutes / 60)
756 return '%02d:%02d:%02d' % (hours, minutes, seconds)
762 sec = int(frame / fps)
763 frame = frame - int(sec * fps)
769 return '%02d:%02d:%02d' % (hour, mins, sec)
775 parts = formatedtime.split(
':')
783 return sec + (mins * 60) + (hour * 60 * 60)
790 """Returns numofchapters chapter marks even spaced through a certain time period"""
793 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
794 thumblistNode = infoDOM.getElementsByTagName(
"thumblist")
795 if thumblistNode.length > 0:
796 thumblist =
getText(thumblistNode[0])
797 write(
"Using user defined thumb images - %s" % thumblist)
801 segment=int(lengthofvideo / numofchapters)
803 write(
"Video length is %s seconds. Each chapter will be %s seconds" % (lengthofvideo,segment))
810 while count<=numofchapters:
811 chapters.append(time.strftime(
"%H:%M:%S",time.gmtime(starttime)))
814 if thumboffset < segment:
815 thumbList.append(str(thumboffset))
817 thumbList.append(str(starttime))
819 thumbList.append(str(starttime))
824 chapters =
','.join(chapters)
825 thumbList =
','.join(thumbList)
827 if getthumbnails==
True:
837 """Returns chapter marks at cut list ends,
838 or evenly spaced chapters 'segment' seconds through the file"""
841 if addCutlistChapters ==
True:
845 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
846 chapterlistNode = infoDOM.getElementsByTagName(
"chapterlist")
847 if chapterlistNode.length > 0:
848 chapterlist =
getText(chapterlistNode[0])
849 write(
"Using commercial end marks - %s" % chapterlist)
852 if lengthofvideo < segment:
855 numofchapters = lengthofvideo // segment + 1;
856 chapters =
"00:00:00"
859 while count <= numofchapters:
861 chapters +=
"," + time.strftime(
"%H:%M:%S", time.gmtime(starttime))
864 write(
"Fixed length chapters: %s" % chapters)
872 """Reads settings from MythTV database"""
874 write(
"Obtaining MythTV settings from MySQL database for hostname " + configHostname)
877 sqlstatement=
"""SELECT value, data FROM settings WHERE value IN(
881 OR (hostname=%s AND value IN(
885 'MythArchiveVideoFormat',
886 'MythArchiveTempDir',
887 'MythArchiveMplexCmd',
888 'MythArchiveDvdauthorCmd',
889 'MythArchiveMkisofsCmd',
890 'MythArchiveM2VRequantiserCmd',
891 'MythArchiveMpg123Cmd',
892 'MythArchiveProjectXCmd',
893 'MythArchiveDVDLocation',
894 'MythArchiveGrowisofsCmd',
895 'MythArchiveJpeg2yuvCmd',
896 'MythArchiveSpumuxCmd',
897 'MythArchiveMpeg2encCmd',
898 'MythArchiveCopyRemoteFiles',
899 'MythArchiveAlwaysUseMythTranscode',
900 'MythArchiveUseProjectX',
901 'MythArchiveAddSubtitles',
902 'MythArchiveUseFIFO',
903 'MythArchiveMainMenuAR',
904 'MythArchiveChapterMenuAR',
905 'MythArchiveDateFormat',
906 'MythArchiveTimeFormat',
907 'MythArchiveClearArchiveTable',
908 'MythArchiveDriveSpeed',
915 cursor.execute(sqlstatement, (configHostname,))
917 result = cursor.fetchall()
920 for i
in range(len(result)):
921 cfg[result[i][0]] = result[i][1]
924 if not "MythArchiveTempDir" in cfg:
925 fatalError(
"Can't find the setting for the temp directory. \nHave you run setup in the frontend?")
932 host = DB.gethostname()
933 DB.settings[host][name] = data
939 ''' Remove all archive items from the archiveitems DB table'''
941 write(
"Removing all archive items from the archiveitems DB table")
943 cursor.execute(
"DELETE FROM archiveitems")
955 if options.length == 0:
956 fatalError(
"Trying to read the options from the job file but none found?")
959 doburn = options.attributes[
"doburn"].value !=
'0'
960 docreateiso = options.attributes[
"createiso"].value !=
'0'
961 erasedvdrw = options.attributes[
"erasedvdrw"].value !=
'0'
962 mediatype = int(options.attributes[
"mediatype"].value)
963 savefilename = options.attributes[
"savefilename"].value
965 write(
"Options - mediatype = %d, doburn = %d, createiso = %d, erasedvdrw = %d" \
966 % (mediatype, doburn, docreateiso, erasedvdrw))
967 write(
" savefilename = '%s'" % savefilename)
972 def expandItemText(infoDOM, text, itemnumber, pagenumber, keynumber,chapternumber, chapterlist ):
973 """Replaces keywords in a string with variables from the XML and filesystem"""
974 text=text.replace(
"%page",
"%s" % pagenumber)
977 if getText( infoDOM.getElementsByTagName(
"coverfile")[0]) ==
"":
978 text=text.replace(
"%thumbnail", os.path.join(
getItemTempPath(itemnumber),
"title.jpg"))
980 text=text.replace(
"%thumbnail",
getText( infoDOM.getElementsByTagName(
"coverfile")[0]) )
982 text=text.replace(
"%itemnumber",
"%s" % itemnumber )
983 text=text.replace(
"%keynumber",
"%s" % keynumber )
985 text=text.replace(
"%title",
getText( infoDOM.getElementsByTagName(
"title")[0]) )
986 text=text.replace(
"%subtitle",
getText( infoDOM.getElementsByTagName(
"subtitle")[0]) )
987 text=text.replace(
"%description",
getText( infoDOM.getElementsByTagName(
"description")[0]) )
988 text=text.replace(
"%type",
getText( infoDOM.getElementsByTagName(
"type")[0]) )
990 text=text.replace(
"%recordingdate",
getText( infoDOM.getElementsByTagName(
"recordingdate")[0]) )
991 text=text.replace(
"%recordingtime",
getText( infoDOM.getElementsByTagName(
"recordingtime")[0]) )
995 text=text.replace(
"%myfolder",
getThemeFile(themeName,
""))
998 text=text.replace(
"%chapternumber",
"%s" % chapternumber )
999 text=text.replace(
"%chaptertime",
"%s" % chapterlist[chapternumber - 1] )
1000 text=text.replace(
"%chapterthumbnail", os.path.join(
getItemTempPath(itemnumber),
"chapter-%s.jpg" % chapternumber))
1008 """ Returns a value taken from attribute in node scaled for the current video mode"""
1010 if videomode ==
"pal" or attribute ==
"x" or attribute ==
"w":
1011 return int(node.attributes[attribute].value)
1013 return int(float(node.attributes[attribute].value) / 1.2)
1019 """Based on http://mail.python.org/pipermail/image-sig/2004-December/003064.html"""
1027 words = text.split()
1033 thistext = lines[line]
1035 innerFinished =
False
1036 while not innerFinished:
1040 if drawer.textsize(
' '.join(thistext),font.getFont())[0] > containerWidth:
1044 if str(thistext).
find(
' ') != -1:
1045 newline.insert(0,thistext.pop(-1))
1048 innerFinished =
True
1050 innerFinished =
True
1051 if len(newline) > 0:
1052 lines.append(newline)
1058 tmp.append(
fix_rtl(
' '.join(i) ) )
1066 if node.hasAttribute(
"bgcolor"):
1067 bgcolor = node.attributes[
"bgcolor"].value
1072 r,g,b = ImageColor.getrgb(bgcolor)
1074 if node.hasAttribute(
"bgalpha"):
1075 a = int(node.attributes[
"bgalpha"].value)
1079 image.paste((r, g, b, a), (x, y, x + w, y + h))
1085 def paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
1086 itemsonthispage, chapternumber, chapterlist):
1088 imagefilename =
getThemeFile(themeName, node.attributes[
"filename"].value)
1090 fatalError(
"Cannot find image for menu button (%s)." % imagefilename)
1091 maskimagefilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
1093 fatalError(
"Cannot find mask image for menu button (%s)." % maskimagefilename)
1095 picture = Image.open(imagefilename,
"r").resize(
1097 picture = picture.convert(
"RGBA")
1103 textnode = node.getElementsByTagName(
"textnormal")
1104 if textnode.length > 0:
1105 textnode = textnode[0]
1106 text =
expandItemText(infoDOM,textnode.attributes[
"value"].value,
1107 itemnum, page, itemsonthispage,
1108 chapternumber,chapterlist)
1111 paintText(draw, bgimage, text, textnode)
1115 write(
"Added button image %s" % imagefilename)
1117 picture = Image.open(maskimagefilename,
"r").resize(
1119 picture = picture.convert(
"RGBA")
1125 textnode = node.getElementsByTagName(
"textselected")
1126 if textnode.length > 0:
1127 textnode = textnode[0]
1128 text =
expandItemText(infoDOM, textnode.attributes[
"value"].value,
1129 itemnum, page, itemsonthispage,
1130 chapternumber, chapterlist)
1131 textImage = Image.new(
"RGBA",picture.size)
1132 textDraw = ImageDraw.Draw(textImage)
1135 paintText(textDraw, textImage, text, textnode,
"white",
1142 (width, height) = textImage.size
1143 for y
in range(height):
1144 for x
in range(width):
1145 if textImage.getpixel((x,y)) < (100, 100, 100, 255):
1146 textImage.putpixel((x,y), (0, 0, 0, 0))
1148 textImage.putpixel((x,y), (255, 255, 255, 255))
1150 if textnode.hasAttribute(
"colour"):
1151 color = textnode.attributes[
"colour"].value
1152 elif textnode.hasAttribute(
"color"):
1153 color = textnode.attributes[
"color"].value
1157 bgimagemask.paste(color,
1162 del text, textImage, textDraw
1169 x = None, y = None, width = None, height = None):
1170 """Takes a piece of text and draws it onto an image inside a bounding box."""
1179 font = themeFonts[node.attributes[
"font"].value]
1182 if node.hasAttribute(
"colour"):
1183 color = node.attributes[
"colour"].value
1184 elif node.hasAttribute(
"color"):
1185 color = node.attributes[
"color"].value
1189 if node.hasAttribute(
"halign"):
1190 halign = node.attributes[
"halign"].value
1191 elif node.hasAttribute(
"align"):
1192 halign = node.attributes[
"align"].value
1196 if node.hasAttribute(
"valign"):
1197 valign = node.attributes[
"valign"].value
1201 if node.hasAttribute(
"vindent"):
1202 vindent = int(node.attributes[
"vindent"].value)
1206 if node.hasAttribute(
"hindent"):
1207 hindent = int(node.attributes[
"hindent"].value)
1211 lines =
intelliDraw(draw, text, font, width - (hindent * 2))
1215 textImage = font.drawText(lines[0])
1216 h = int(textImage.size[1] * 1.1)
1219 if (j * h) < (height - (vindent * 2) - h):
1220 textImage = font.drawText(i, color)
1221 write(
"Wrapped text = " + i )
1223 if halign ==
"left":
1225 elif halign ==
"center" or halign ==
"centre":
1226 xoffset = (width // 2) - (textImage.size[0] // 2)
1227 elif halign ==
"right":
1228 xoffset = width - textImage.size[0] - hindent
1234 elif valign ==
"center" or halign ==
"centre":
1235 yoffset = (height // 2) - (textImage.size[1] // 2)
1236 elif valign ==
"bottom":
1237 yoffset = height - textImage.size[1] - vindent
1241 image.paste(textImage, (x + xoffset,y + yoffset + j * h), textImage)
1243 write(
"Wrapped text = " + i )
1250 def paintImage(filename, maskfilename, imageDom, destimage, stretch=True):
1251 """Paste the image specified in the filename into the specified image"""
1254 write(
"Image file (%s) does not exist" % filename)
1257 picture = Image.open(filename,
"r")
1262 (imgw, imgh) = picture.size
1263 write(
"Image (%s, %s) into space of (%s, %s) at (%s, %s)" % (imgw, imgh, w, h, xpos, ypos),
False)
1266 if imageDom.hasAttribute(
"stretch"):
1267 if imageDom.attributes[
"stretch"].value ==
"True":
1276 if float(w)/imgw < float(h)/imgh:
1280 if imageDom.hasAttribute(
"valign"):
1281 valign = imageDom.attributes[
"valign"].value
1285 if valign ==
"bottom":
1287 if valign ==
"center":
1288 ypos += (h - imgh)//2
1293 if imageDom.hasAttribute(
"halign"):
1294 halign = imageDom.attributes[
"halign"].value
1298 if halign ==
"right":
1300 if halign ==
"center":
1301 xpos += (w - imgw)//2
1303 write(
"Image resized to (%s, %s) at (%s, %s)" % (imgw, imgh, xpos, ypos),
False)
1304 picture = picture.resize((imgw, imgh))
1305 picture = picture.convert(
"RGBA")
1308 maskpicture = Image.open(maskfilename,
"r").resize((imgw, imgh))
1309 maskpicture = maskpicture.convert(
"RGBA")
1311 maskpicture = picture
1313 destimage.paste(picture, (xpos, ypos), maskpicture)
1318 write (
"Added image %s" % filename)
1330 if getText(node.attributes[
"static"]) ==
"False":
1332 boundarybox =
getScaledAttribute(node,
"x"), boundarybox[1], boundarybox[2], boundarybox[3]
1335 boundarybox = boundarybox[0],
getScaledAttribute(node,
"y"), boundarybox[2], boundarybox[3]
1342 boundarybox = boundarybox[0], boundarybox[1], boundarybox[2], \
1354 nodelistfonts = themeDOM.getElementsByTagName(
"font")
1357 for node
in nodelistfonts:
1360 if node.hasAttribute(
"name"):
1361 name = node.attributes[
"name"].value
1363 name = str(fontnumber)
1367 if node.hasAttribute(
"color"):
1368 color = node.attributes[
"color"].value
1372 if node.hasAttribute(
"effect"):
1373 effect = node.attributes[
"effect"].value
1377 if node.hasAttribute(
"shadowsize"):
1378 shadowsize = int(node.attributes[
"shadowsize"].value)
1382 if node.hasAttribute(
"shadowcolor"):
1383 shadowcolor = node.attributes[
"shadowcolor"].value
1385 shadowcolor =
"black"
1388 fontsize, color, effect, shadowcolor, shadowsize)
1397 outputfile = os.path.join(folder,
"info.xml")
1398 impl = xml.dom.minidom.getDOMImplementation()
1399 infoDOM = impl.createDocument(
None,
"fileinfo",
None)
1400 top_element = infoDOM.documentElement
1402 data = OrdDict(((
'chanid',
''),
1403 (
'type',
''), (
'filename',
''),
1404 (
'title',
''), (
'recordingdate',
''),
1405 (
'recordingtime',
''), (
'subtitle',
''),
1406 (
'description',
''), (
'rating',
''),
1407 (
'coverfile',
''), (
'cutlist',
'')))
1410 details = file.getElementsByTagName(
"details")
1411 if details.length > 0:
1412 data.type = file.attributes[
"type"].value
1413 data.filename = file.attributes[
"filename"].value
1414 data.title = details[0].attributes[
"title"].value
1415 data.recordingdate = details[0].attributes[
"startdate"].value
1416 data.recordingtime = details[0].attributes[
"starttime"].value
1417 data.subtitle = details[0].attributes[
"subtitle"].value
1418 data.description =
getText(details[0])
1421 if file.attributes[
"type"].value==
"recording":
1422 filename = file.attributes[
"filename"].value
1424 rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
1425 except StopIteration:
1426 fatalError(
"Failed to get recording details from the DB for %s" % filename)
1428 data.chanid = rec.chanid
1429 data.recordingtime = rec.starttime.isoformat()
1430 data.recordingdate = rec.starttime.isoformat()
1432 cutlist = rec.markup.getcutlist()
1434 data.hascutlist =
'yes'
1435 if file.attributes[
"usecutlist"].value ==
"0" and addCutlistChapters ==
True:
1436 chapterlist = [
'00:00:00']
1440 data.chapterlist =
','.join(chapterlist)
1442 data.hascutlist =
'no'
1444 elif file.attributes[
"type"].value==
"recording":
1445 filename = file.attributes[
"filename"].value
1447 rec = next(DB.searchRecorded(basename=os.path.basename(filename)))
1448 except StopIteration:
1449 fatalError(
"Failed to get recording details from the DB for %s" % filename)
1451 write(
" " + rec.title)
1452 data.type = file.attributes[
"type"].value
1453 data.filename = filename
1454 data.title = rec.title
1455 data.recordingdate = rec.progstart.strftime(dateformat)
1456 data.recordingtime = rec.progstart.strftime(timeformat)
1457 data.subtitle = rec.subtitle
1458 data.description = rec.description
1459 data.rating = str(rec.stars)
1460 data.chanid = rec.chanid
1461 data.starttime = rec.starttime.utcisoformat()
1463 cutlist = rec.markup.getcutlist()
1465 data.hascutlist =
'yes'
1466 if file.attributes[
"usecutlist"].value ==
"0" and addCutlistChapters ==
True:
1467 chapterlist = [
'00:00:00']
1471 data.chapterlist =
','.join(chapterlist)
1473 data.hascutlist =
'no'
1475 elif file.attributes[
"type"].value==
"video":
1476 filename = file.attributes[
"filename"].value
1478 vid = next(MVID.searchVideos(file=filename))
1479 except StopIteration:
1480 vid = Video.fromFilename(filename)
1482 data.type = file.attributes[
"type"].value
1483 data.filename = filename
1484 data.title = vid.title
1486 if vid.year != 1895:
1487 data.recordingdate =
unicode(vid.year)
1489 data.subtitle = vid.subtitle
1491 if (vid.plot
is not None)
and (vid.plot !=
'None'):
1492 data.description = vid.plot
1494 data.rating = str(vid.userrating)
1497 data.coverfile = vid.coverfile
1499 elif file.attributes[
"type"].value==
"file":
1500 data.type = file.attributes[
"type"].value
1501 data.filename = file.attributes[
"filename"].value
1502 data.title = file.attributes[
"filename"].value
1505 thumbs = file.getElementsByTagName(
"thumbimages")
1506 if thumbs.length > 0:
1508 thumbs = file.getElementsByTagName(
"thumb")
1512 for thumb
in thumbs:
1513 caption = thumb.attributes[
"caption"].value
1514 frame = thumb.attributes[
"frame"].value
1515 filename = thumb.attributes[
"filename"].value
1516 if caption !=
"Title":
1517 thumblist.append(
frameToTime(int(frame), float(fps)))
1520 copy(filename, folder)
1522 data.thumblist =
','.join(thumblist)
1524 for k,v
in list(data.items()):
1525 write(
"Node = %s, Data = %s" % (k, v))
1526 node = infoDOM.createElement(k)
1533 node.appendChild(infoDOM.createTextNode(
unicode(v)))
1534 top_element.appendChild(node)
1536 WriteXMLToFile (infoDOM, outputfile)
1544 f=open(filename,
'w')
1546 if sys.hexversion >= 0x03000000:
1547 f.write(myDOM.toprettyxml(indent=
" ", encoding=
"UTF-8").
decode())
1548 elif sys.hexversion >= 0x020703F0:
1549 f.write(myDOM.toprettyxml(indent=
" ", encoding=
"UTF-8"))
1551 f.write(myDOM.toxml(encoding=
"UTF-8"))
1560 """Pre-process a single video/recording file."""
1562 write(
"Pre-processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
1570 if file.attributes[
"type"].value ==
"recording":
1571 mediafile = file.attributes[
"filename"].value
1572 elif file.attributes[
"type"].value ==
"video":
1573 mediafile = os.path.join(videopath, file.attributes[
"filename"].value)
1574 elif file.attributes[
"type"].value ==
"file":
1575 mediafile = file.attributes[
"filename"].value
1577 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
1579 if file.hasAttribute(
"localfilename"):
1580 mediafile = file.attributes[
"localfilename"].value
1583 fatalError(
"Source file does not exist: " + mediafile)
1586 copy(os.path.join(folder,
"streaminfo.xml"), os.path.join(folder,
"streaminfo_orig.xml"))
1590 videosize =
getVideoSize(os.path.join(folder,
"streaminfo.xml"))
1592 write(
"Video resolution is %s by %s" % (videosize[0], videosize[1]))
1597 def encodeAudio(format, sourcefile, destinationfile, deletesourceafterencode):
1598 write(
"Encoding audio to "+format)
1600 cmd =
"mythffmpeg -v 0 -y "
1603 cmd +=
"-threads %d " % cpuCount
1609 fatalError(
"Failed while running mythffmpeg to re-encode the audio to ac3\n"
1610 "Command was %s" % cmd)
1612 fatalError(
"Unknown encodeAudio format " + format)
1614 if deletesourceafterencode==
True:
1615 os.remove(sourcefile)
1622 """multiplex one video and one or two audio streams together"""
1624 write(
"Multiplexing MPEG stream to %s" % destination)
1630 if useSyncOffset ==
True:
1631 write(
"Adding sync offset of %dms" % syncOffset)
1633 write(
"Using sync offset is disabled - it would be %dms" % syncOffset)
1637 os.remove(destination)
1641 audio1 = audio1 +
".ac3"
1643 audio1 = audio1 +
".mp2"
1648 audio2 = audio2 +
".ac3"
1650 audio2 = audio2 +
".mp2"
1654 if os.path.exists(os.path.dirname(destination) +
"/stream.d/spumux.xml"):
1657 localUseFIFO=useFIFO
1659 if localUseFIFO==
True:
1660 os.mkfifo(destination)
1668 write(
"Available streams - video and one audio stream")
1669 write(
"running %s -M -f 8 -v 0 --sync-offset %sms -o %s %s %s" %(path_mplex[0], syncOffset, destination, video, audio1))
1670 result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
1674 '--sync-offset',
'%sms' % syncOffset,
1679 write(
"Available streams - video and two audio streams")
1680 result=os.spawnlp(mode, path_mplex[0], path_mplex[1],
1684 '--sync-offset',
'%sms' % syncOffset,
1690 if localUseFIFO ==
True:
1691 write(
"Multiplex started PID=%s" % result)
1695 fatalError(
"mplex failed with result %d" % result)
1698 if os.path.exists(os.path.dirname(destination) +
"/stream.d/spumux.xml"):
1699 write(
"Checking integrity of subtitle pngs")
1700 command =
quoteCmdArg(os.path.join(scriptpath,
"testsubtitlepngs.sh")) +
" " +
quoteCmdArg(os.path.dirname(destination) +
"/stream.d/spumux.xml")
1703 fatalError(
"Failed while running testsubtitlepngs.sh - %s" % command)
1705 write(
"Running spumux to add subtitles")
1710 "Command was - %s.\n"
1711 "Look in the full log to see why it failed" % command)
1712 os.remove(os.path.splitext(destination)[0] +
"-sub.mpg")
1714 os.rename(os.path.splitext(destination)[0] +
"-sub.mpg", destination)
1723 """create a stream.xml file for filename"""
1725 command =
"mytharchivehelper -q -q --getfileinfo --infile %s --outfile %s --method %d" % (
quoteCmdArg(filename),
quoteCmdArg(xmlFilename), lenMethod)
1731 fatalError(
"Failed while running mytharchivehelper to get stream information.\n"
1732 "Result: %d, Command was %s" % (result, command))
1735 infoDOM = xml.dom.minidom.parse(xmlFilename)
1736 write(xmlFilename +
":-\n" + infoDOM.toprettyxml(
" ",
""),
False)
1742 """Get video width and height from stream.xml file"""
1745 infoDOM = xml.dom.minidom.parse(xmlFilename)
1748 if infoDOM.documentElement.tagName !=
"file":
1749 fatalError(
"This info file doesn't look right (%s)." % xmlFilename)
1750 nodes = infoDOM.getElementsByTagName(
"video")
1751 if nodes.length == 0:
1752 fatalError(
"Didn't find any video elements in stream info file. (%s)" % xmlFilename)
1754 if nodes.length > 1:
1755 write(
"Found more than one video element in stream info file.!!!")
1757 width = int(node.attributes[
"width"].value)
1758 height = int(node.attributes[
"height"].value)
1760 return (width, height)
1766 """Use mythtranscode to cut commercials and/or clean up an mpeg2 file"""
1769 rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
1770 cutlist = rec.markup.getcutlist()
1771 except StopIteration:
1775 if usecutlist
and len(cutlist):
1778 cutlist_s +=
' %d-%d ' % cut
1780 write(
"Using cutlist: %s" % cutlist_s)
1782 if (localfile !=
""):
1783 if usecutlist ==
True:
1784 command =
"mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s,
quoteCmdArg(localfile),
quoteCmdArg(destination))
1786 command =
"mythtranscode --mpeg2 --infile %s --outfile %s" % (
quoteCmdArg(localfile),
quoteCmdArg(destination))
1788 if usecutlist ==
True:
1789 command =
"mythtranscode --mpeg2 --honorcutlist --chanid %s --starttime %s --outfile %s" % (chanid, starttime,
quoteCmdArg(destination))
1791 command =
"mythtranscode --mpeg2 --chanid %s --starttime %s --outfile %s" % (chanid, starttime,
quoteCmdArg(destination))
1796 write(
"Failed while running mythtranscode to cut commercials and/or clean up an mpeg2 file.\n"
1797 "Result: %d, Command was %s" % (result, command))
1807 """generate cutlist_x.txt for ProjectX"""
1809 rec = next(DB.searchRecorded(chanid=chanid, starttime=starttime))
1810 starttime = rec.starttime.utcisoformat()
1811 cutlist = rec.markup.getcutlist()
1814 with codecs.open(os.path.join(folder,
"cutlist_x.txt"),
'w',
'utf-8')
as cutlist_f:
1815 cutlist_f.write(
"CollectionPanel.CutMode=2\n")
1823 cutlist_f.write(
'0\n%d\n' % cut[0])
1824 cutlist_f.write(
'%d\n' % cut[1])
1825 elif i == len(cutlist) - 1:
1826 cutlist_f.write(
'%d\n' % cut[0])
1827 if cut[1] != 9999999:
1828 cutlist_f.write(
'%d\n9999999\n' % cut[1])
1830 cutlist_f.write(
'%d\n%d\n' % cut)
1835 write(
"No cutlist in the DB for chanid %s, starttime %s" % chanid, starttime)
1842 """Use Project-X to cut commercials and demux an mpeg2 file"""
1846 write(
"Failed to generate Project-X cutlist.")
1849 if os.path.exists(file) !=
True:
1850 write(
"Error: input file doesn't exist on local filesystem")
1854 if usecutlist ==
True:
1855 command +=
" -cut %s" %
quoteCmdArg(os.path.join(folder,
"cutlist_x.txt"))
1860 write(
"Failed while running Project-X to cut commercials and/or demux an mpeg2 file.\n"
1861 "Result: %d, Command was %s" % (result, command))
1870 videoID_hex =
"0x%x" % video[VIDEO_ID]
1871 if audio1[AUDIO_ID] != -1:
1872 audio1ID_hex =
"0x%x" % audio1[AUDIO_ID]
1875 if audio2[AUDIO_ID] != -1:
1876 audio2ID_hex =
"0x%x" % audio2[AUDIO_ID]
1879 if addSubtitles
and subtitles[SUBTITLE_ID] != -1:
1880 subtitlesID_hex =
"0x%x" % subtitles[SUBTITLE_ID]
1882 subtitlesID_hex =
""
1885 files = os.listdir(folder)
1887 if file[0:9] ==
"stream{0x":
1890 if PID == videoID_hex
or SubID == videoID_hex:
1891 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.mv2"))
1892 elif PID == audio1ID_hex
or SubID == audio1ID_hex:
1893 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0." + file[-3:]))
1894 elif PID == audio2ID_hex
or SubID == audio2ID_hex:
1895 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1." + file[-3:]))
1896 elif PID == subtitlesID_hex
or SubID == subtitlesID_hex:
1897 if file[-3:] ==
"sup":
1898 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup"))
1900 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup.IFO"))
1905 files = os.listdir(folder)
1907 if file[0:9] ==
"stream{0x":
1908 if not os.path.exists(os.path.join(folder,
"stream.mv2"))
and file[-3:] ==
"m2v":
1909 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.mv2"))
1910 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":
1911 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0.ac3"))
1912 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":
1913 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream0.mp2"))
1914 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":
1915 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1.ac3"))
1916 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":
1917 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream1.mp2"))
1918 elif not os.path.exists(os.path.join(folder,
"stream.sup"))
and file[-3:] ==
"sup":
1919 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup"))
1920 elif not os.path.exists(os.path.join(folder,
"stream.sup.IFO"))
and file[-3:] ==
"IFO":
1921 os.rename(os.path.join(folder, file), os.path.join(folder,
"stream.sup.IFO"))
1927 if (os.path.exists(os.path.join(folder,
"stream.sup"))
and
1928 os.path.exists(os.path.join(folder,
"stream.sup.IFO"))):
1929 write(
"Found DVB subtitles converting to DVD subtitles")
1930 command =
"mytharchivehelper -q -q --sup2dast "
1931 command +=
" --infile %s --ifofile %s --delay 0" % (
quoteCmdArg(os.path.join(folder,
"stream.sup")),
quoteCmdArg(os.path.join(folder,
"stream.sup.IFO")))
1936 write(
"Failed while running mytharchivehelper to convert DVB subtitles to DVD subtitles.\n"
1937 "Result: %d, Command was %s" % (result, command))
1949 h = int(time[0:2]) * 3600 * 90000
1950 m = int(time[3:5]) * 60 * 90000
1951 s = int(time[6:8]) * 90000
1952 ms = int(time[9:11]) * 90
1954 return h + m + s + ms
1962 subDOM = xml.dom.minidom.parse(spumuxFile)
1965 if subDOM.documentElement.tagName !=
"subpictures":
1966 fatalError(
"This does not look like a spumux.xml file (%s)" % spumuxFile)
1968 streamNodes = subDOM.getElementsByTagName(
"stream")
1969 if streamNodes.length == 0:
1970 write(
"Didn't find any stream elements in file.!!!")
1972 streamNode = streamNodes[0]
1974 nodes = subDOM.getElementsByTagName(
"spu")
1975 if nodes.length == 0:
1976 write(
"Didn't find any spu elements in file.!!!")
1983 start =
ts2pts(node.attributes[
"start"].value)
1984 end =
ts2pts(node.attributes[
"end"].value)
1985 image = node.attributes[
"image"].value
1989 if start <= lastEnd:
1993 write(
"removing subtitle: %s to %s - (%d - %d (%d))" % (node.attributes[
"start"].value, node.attributes[
"end"].value, start, end, lastEnd),
False)
1994 streamNode.removeChild(node)
2006 write(
"Extracting thumbnail image from %s at position %s" % (source, seconds))
2007 write(
"Destination file %s" % destination)
2011 if videomode==
"pal":
2016 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (
quoteCmdArg(source), seconds,
quoteCmdArg(destination))
2019 fatalError(
"Failed while running mytharchivehelper to get thumbnails.\n"
2020 "Result: %d, Command was %s" % (result, command))
2022 myimage=Image.open(destination,
"r")
2024 if myimage.format !=
"JPEG":
2025 write(
"Something went wrong with thumbnail capture - " + myimage.format)
2036 write(
"Extracting thumbnail images from: %s - at %s" % (source, thumbList))
2037 write(
"Destination file %s" % destination)
2039 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s" % (
quoteCmdArg(source), thumbList,
quoteCmdArg(destination))
2043 fatalError(
"Failed while running mytharchivehelper to get thumbnails.\n"
2044 "Result: %d, Command was %s" % (result, command))
2050 """Encodes an unknown video source file eg. AVI to MPEG2 video and AC3 audio, use mythffmpeg"""
2054 passes = int(
getText(profileNode.getElementsByTagName(
"passes")[0]))
2056 command =
"mythffmpeg"
2059 command +=
" -threads %d" % cpuCount
2061 parameters = profileNode.getElementsByTagName(
"parameter")
2063 for param
in parameters:
2064 name = param.attributes[
"name"].value
2065 value = param.attributes[
"value"].value
2068 if value ==
"%inputfile":
2070 if value ==
"%outputfile":
2072 if value ==
"%aspect":
2076 if audio1[AUDIO_CODEC] ==
"AC3":
2077 if name ==
"-acodec":
2079 if name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2084 command +=
" " + name
2087 command +=
" " + value
2091 if audio2[AUDIO_ID] != -1:
2092 for param
in parameters:
2093 name = param.attributes[
"name"].value
2094 value = param.attributes[
"value"].value
2097 if audio1[AUDIO_CODEC] ==
"AC3":
2098 if name ==
"-acodec":
2100 if name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2104 if name ==
"-acodec" or name ==
"-ar" or name ==
"-b:a" or name ==
"-ac":
2105 command +=
" " + name +
" " + value
2108 command +=
" -map 0:%d -map 0:%d " % (video[VIDEO_INDEX], audio1[AUDIO_INDEX])
2109 if audio2[AUDIO_ID] != -1:
2110 command +=
"-map 0:%d" % (audio2[AUDIO_INDEX])
2116 fatalError(
"Failed while running mythffmpeg to re-encode video.\n"
2117 "Command was %s" % command)
2122 pass1 = command.replace(
"%passno",
"1")
2123 pass1 = pass1.replace(
"%passlogfile",
quoteCmdArg(passLog))
2124 write(
"Pass 1 - " + pass1)
2128 fatalError(
"Failed while running mythffmpeg (Pass 1) to re-encode video.\n"
2129 "Command was %s" % command)
2131 if os.path.exists(destvideofile):
2132 os.remove(destvideofile)
2134 pass2 = command.replace(
"%passno",
"2")
2135 pass2 = pass2.replace(
"%passlogfile", passLog)
2136 write(
"Pass 2 - " + pass2)
2140 fatalError(
"Failed while running mythffmpeg (Pass 2) to re-encode video.\n"
2141 "Command was %s" % command)
2145 def encodeNuvToMPEG2(chanid, starttime, mediafile, destvideofile, folder, profile, usecutlist):
2146 """Encodes a nuv video source file to MPEG2 video and AC3 audio, using mythtranscode & mythffmpeg"""
2150 fatalError(
"Something is wrong! Found one or more stale fifo's from mythtranscode\n"
2151 "Delete the fifos in '%s' and start again" % folder)
2154 parameters = profileNode.getElementsByTagName(
"parameter")
2157 outvideobitrate =
"5000k"
2158 if videomode ==
"ntsc":
2159 outvideores =
"720x480"
2161 outvideores =
"720x576"
2163 outaudiochannels = 2
2164 outaudiobitrate = 384
2165 outaudiosamplerate = 48000
2166 outaudiocodec =
"ac3"
2173 for param
in parameters:
2174 name = param.attributes[
"name"].value
2175 value = param.attributes[
"value"].value
2178 if name ==
"-acodec":
2179 outaudiocodec = value
2181 outaudiochannels = value
2183 outaudiobitrate = value
2185 outaudiosamplerate = value
2187 outvideobitrate = value
2190 if name ==
"-deinterlace":
2192 if name ==
"-filter:v":
2198 if name ==
"-qdiff":
2202 utcstarttime = datetime.duck(starttime).utcisoformat()
2203 if (usecutlist ==
True):
2204 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2207 '--starttime', utcstarttime,
2209 '--fifodir', folder)
2210 write(
"mythtranscode started (using cut list) PID = %s" % PID)
2212 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2215 '--starttime', utcstarttime,
2216 '--fifodir', folder)
2218 write(
"mythtranscode started PID = %s" % PID)
2219 elif mediafile != -1:
2220 PID=os.spawnlp(os.P_NOWAIT,
"mythtranscode",
"mythtranscode",
2222 '--infile', mediafile,
2223 '--fifodir', folder)
2224 write(
"mythtranscode started (using file) PID = %s" % PID)
2226 fatalError(
"no video source passed to encodeNuvToMPEG2.\n")
2232 command =
"mythffmpeg -y "
2235 command +=
"-threads %d " % cpuCount
2237 command +=
"-f s16le -ar %s -ac %s -i %s " % (samplerate, channels,
quoteCmdArg(os.path.join(folder,
"audout")))
2238 command +=
"-f rawvideo -pix_fmt yuv420p -s %s -aspect %s -r %s " % (videores, aspectratio, fps)
2239 command +=
"-i %s " %
quoteCmdArg(os.path.join(folder,
"vidout"))
2240 command +=
"-aspect %s -r %s " % (aspectratio, fps)
2241 if (deinterlace == 1):
2242 command +=
"-deinterlace "
2243 command +=
"%s" % filter
2244 command +=
"-s %s -b %s -vcodec mpeg2video " % (outvideores, outvideobitrate)
2245 command +=
"-qmin %s -qmax %s -qdiff %s " % (qmin, qmax, qdiff)
2246 command +=
"-ab %s -ar %s -acodec %s " % (outaudiobitrate, outaudiosamplerate, outaudiocodec)
2247 command +=
"-f dvd %s" %
quoteCmdArg(destvideofile)
2251 while (tries
and not(
doesFileExist(os.path.join(folder,
"audout"))
and
2254 write(
"Waiting for mythtranscode to create the fifos")
2258 fatalError(
"Waited too long for mythtranscode to create the fifos - giving up!!")
2260 write(
"Running mythffmpeg")
2263 os.kill(PID, signal.SIGKILL)
2264 fatalError(
"Failed while running mythffmpeg to re-encode video.\n"
2265 "Command was %s" % command)
2271 write(
"Starting dvdauthor")
2273 result=os.spawnlp(os.P_WAIT, path_dvdauthor[0],path_dvdauthor[1],
'-x',os.path.join(
getTempPath(),
'dvdauthor.xml'))
2275 fatalError(
"Failed while running dvdauthor. Result: %d" % result)
2276 write(
"Finished dvdauthor")
2282 write(
"Creating ISO image")
2284 command =
quoteCmdArg(path_mkisofs[0]) +
' -dvd-video '
2293 "Command was %s" % command)
2295 write(
"Finished creating ISO image")
2302 write(
"Burning ISO image to %s" % dvddrivepath)
2307 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2308 status = ioctl(f,CDROM.CDROM_DRIVE_STATUS, 0)
2311 def displayneededdisktype():
2312 if mediatype == DVD_SL:
2313 write(
"Please insert an empty single-layer disc (DVD+R or DVD-R).")
2314 if mediatype == DVD_DL:
2315 write(
"Please insert an empty double-layer disc (DVD+R DL or DVD-R DL).")
2316 if mediatype == DVD_RW:
2317 write(
"Please insert a rewritable disc (DVD+RW or DVD-RW).")
2318 def drive(action, value=0):
2322 if action == CDROM.CDROMEJECT:
2324 while drivestatus() != CDROM.CDS_TRAY_OPEN
and counter < 15:
2325 counter = counter + 1
2326 drive(CDROM.CDROM_LOCKDOOR, 0)
2328 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2330 ioctl(f,action, value)
2332 write(
"Sending command '0x%x' to drive failed" %action,
False)
2336 write(
'"eject" is probably not installed.',
False)
2339 if drivestatus() == CDROM.CDS_TRAY_OPEN:
2343 write(
"Failed to eject the disc! Probably drive is blocked by another program.")
2346 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2348 ioctl(f,action, value)
2351 write(
"Sending command '0x%x' to drive failed" %action,
False)
2357 while drivestatus() == CDROM.CDS_DRIVE_NOT_READY:
2359 write(
"Waiting for drive")
2365 write(
"Try a hard-reset of the device")
2366 drive(CDROM.CDROMRESET)
2383 if drivestatus() == CDROM.CDS_DISC_OK
or drivestatus() == CDROM.CDS_NO_INFO:
2390 command =
quoteCmdArg(path_growisofs[0]) +
" -input-charset=UTF-8 -dvd-compat"
2392 command +=
" -speed=%d" % drivespeed
2393 if mediatype == DVD_RW
and erasedvdrw ==
True:
2394 command +=
" -use-the-force-luke"
2397 write(
"Running growisofs to burn DVD")
2404 f = os.open(dvddrivepath, os.O_RDONLY | os.O_NONBLOCK)
2407 while busy
and tries < 10:
2410 ioctl(f, CDROM.CDROM_LOCKDOOR, 0)
2413 write(
"Drive is still busy")
2420 write(
"You probably inserted a medium of wrong type.")
2421 elif (result == 156):
2423 write(
"You probably inserted a non-empty, corrupt or too small medium.")
2424 elif (result == 144):
2426 write(
"You inserted a non-empty medium.")
2429 write(
"ERROR: Failed while running growisofs.")
2430 write(
"Result %d, Command was: %s" % (result, command))
2431 write(
"Please check mythburn.log for further information")
2434 write(
"Going to try it again until canceled by user:")
2437 displayneededdisktype()
2440 drive(CDROM.CDROMEJECT)
2443 elif drivestatus() == CDROM.CDS_TRAY_OPEN:
2444 displayneededdisktype()
2445 write(
"Waiting for tray to close.")
2447 while drivestatus() == CDROM.CDS_TRAY_OPEN:
2450 elif drivestatus() == CDROM.CDS_NO_DISC:
2451 drive(CDROM.CDROMEJECT)
2452 displayneededdisktype()
2454 write(
"Finished burning ISO image")
2463 command =
"mythreplex --demux --fix_sync -t TS -o %s " %
quoteCmdArg(folder +
"/stream")
2464 command +=
"-v %d " % (video[VIDEO_ID])
2466 if audio1[AUDIO_ID] != -1:
2467 if audio1[AUDIO_CODEC] ==
'MP2':
2468 command +=
"-a %d " % (audio1[AUDIO_ID])
2469 elif audio1[AUDIO_CODEC] ==
'AC3':
2470 command +=
"-c %d " % (audio1[AUDIO_ID])
2471 elif audio1[AUDIO_CODEC] ==
'EAC3':
2472 command +=
"-c %d " % (audio1[AUDIO_ID])
2474 if audio2[AUDIO_ID] != -1:
2475 if audio2[AUDIO_CODEC] ==
'MP2':
2476 command +=
"-a %d " % (audio2[AUDIO_ID])
2477 elif audio2[AUDIO_CODEC] ==
'AC3':
2478 command +=
"-c %d " % (audio2[AUDIO_ID])
2479 elif audio2[AUDIO_CODEC] ==
'EAC3':
2480 command +=
"-c %d " % (audio2[AUDIO_ID])
2483 command =
"mythreplex --demux --fix_sync -o %s " %
quoteCmdArg(folder +
"/stream")
2484 command +=
"-v %d " % (video[VIDEO_ID] & 255)
2486 if audio1[AUDIO_ID] != -1:
2487 if audio1[AUDIO_CODEC] ==
'MP2':
2488 command +=
"-a %d " % (audio1[AUDIO_ID] & 255)
2489 elif audio1[AUDIO_CODEC] ==
'AC3':
2490 command +=
"-c %d " % (audio1[AUDIO_ID] & 255)
2491 elif audio1[AUDIO_CODEC] ==
'EAC3':
2492 command +=
"-c %d " % (audio1[AUDIO_ID] & 255)
2495 if audio2[AUDIO_ID] != -1:
2496 if audio2[AUDIO_CODEC] ==
'MP2':
2497 command +=
"-a %d " % (audio2[AUDIO_ID] & 255)
2498 elif audio2[AUDIO_CODEC] ==
'AC3':
2499 command +=
"-c %d " % (audio2[AUDIO_ID] & 255)
2500 elif audio2[AUDIO_CODEC] ==
'EAC3':
2501 command +=
"-c %d " % (audio2[AUDIO_ID] & 255)
2504 command += mediafile
2505 write(
"Running: " + command)
2510 fatalError(
"Failed while running mythreplex. Command was %s" % command)
2517 M2Vsize0 = os.path.getsize(source)
2518 write(
"Initial M2Vsize is %.2f Mb , target is %.2f Mb" % ( (float(M2Vsize0)/mega), (float(M2Vsize0)/(factor*mega)) ))
2521 command +=
" %.5f " % factor
2522 command +=
" %s " % M2Vsize0
2526 write(
"Running: " + command)
2529 fatalError(
"Failed while running M2VRequantiser. Command was %s" % command)
2531 M2Vsize1 = os.path.getsize(destination)
2533 write(
"M2Vsize after requant is %.2f Mb " % (float(M2Vsize1)/mega))
2534 fac1=float(M2Vsize0) / float(M2Vsize1)
2535 write(
"Factor demanded %.5f, achieved %.5f, ratio %.5f " % ( factor, fac1, fac1/factor))
2541 """ Returns the sizes of all video, audio and menu files"""
2552 file=os.path.join(folder,
"stream.mv2")
2554 totalvideosize+=os.path.getsize(file)
2558 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream0.ac3"))
2560 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream0.mp2"))
2564 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream1.ac3"))
2566 totalaudiosize+=os.path.getsize(os.path.join(folder,
"stream1.mp2"))
2570 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % filecount))
2574 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"details-%s.mpg" % filecount))
2578 totalmenusize+=os.path.getsize(os.path.join(
getTempPath(),
"menu-%s.mpg" % filecount))
2581 return totalvideosize,totalaudiosize,totalmenusize
2593 file=os.path.join(folder,
"stream.mv2")
2594 progvsize=os.path.getsize(file)
2595 progvbitrate=progvsize/progduration
2596 if progvbitrate>rate :
2597 tvsize+=progduration*rate
2614 allfiles=totalvideosize+totalaudiosize+totalmenusize
2617 write(
"Total video %.2f Mb, audio %.2f Mb, menus %.2f Mb." % (totalvideosize/mega,totalaudiosize/mega,totalmenusize/mega))
2620 mv2space=((dvdrsize*mega-totalmenusize)/fudge_pack)-totalaudiosize
2623 fatalError(
"Audio and menu files are too big. No room for video. Giving up!")
2625 if totalvideosize>mv2space:
2626 write(
"Video files are %.1f Mb too big. Need to shrink." % ((totalvideosize - mv2space)/mega) )
2628 if path_M2VRequantiser[0] ==
"":
2629 fatalError(
"M2VRequantiser is not available to resize the files. Giving up!")
2637 file=os.path.join(folder,
"stream.mv2")
2638 vsize+=os.path.getsize(file)
2654 vrHi=3.0*float(vsize)/duration
2665 if (testsize<mv2space):
2668 write(
"vrate %.3f kb/s, testsize %.4f , mv2space %.4f Mb " % ((vrate)/1000.0, (testsize)/mega, (mv2space)/mega) )
2673 file=os.path.join(folder,
"stream.mv2")
2674 progvsize=os.path.getsize(file)
2676 progvbitrate=progvsize/progduration
2677 write(
"File %s, size %.2f Mb, rate %.2f, limit %.2f kb/s " %( filecount, float(progvsize)/mega, progvbitrate/1000.0, vrate/1000.0 ))
2678 if progvbitrate>vrate :
2679 scalefactor=1.0+(fudge_requant*float(progvbitrate-vrate)/float(vrate))
2680 if scalefactor>3.0 :
2681 write(
"Large shrink factor. You may not like the result! ")
2686 write(
"Unpackaged total %.2f Mb. About %.0f Mb will be unused." % ((allfiles/mega),(mv2space-totalvideosize)/mega))
2692 """Creates the xml file for dvdauthor to use the MythBurn menus."""
2695 menunode=themeDOM.getElementsByTagName(
"menu")
2696 if menunode.length!=1:
2697 fatalError(
"Cannot find the menu element in the theme file")
2698 menunode=menunode[0]
2700 menuitems=menunode.getElementsByTagName(
"item")
2702 itemsperpage = menuitems.length
2703 write(
"Menu items per page %s" % itemsperpage)
2704 autoplaymenu = 2 + ((numberofitems + itemsperpage - 1)//itemsperpage)
2708 submenunode=themeDOM.getElementsByTagName(
"submenu")
2709 if submenunode.length!=1:
2710 fatalError(
"Cannot find the submenu element in the theme file")
2712 submenunode=submenunode[0]
2714 chapteritems=submenunode.getElementsByTagName(
"chapter")
2716 chapters = chapteritems.length
2717 write(
"Chapters per recording %s" % chapters)
2728 write(
"Creating DVD XML file for dvd author")
2730 dvddom = xml.dom.minidom.parseString(
2740 dvdauthor_element=dvddom.documentElement
2741 menus_element = dvdauthor_element.childNodes[1].childNodes[1]
2743 dvdauthor_element.insertBefore( dvddom.createComment(
"""
2747 g2=title number selected on current menu page (see g4)
2748 g3=1 if intro movie has played
2749 g4=last menu page on display
2750 g5=next title to autoplay (0 or > # titles means no more autoplay)
2751 """), dvdauthor_element.firstChild )
2752 dvdauthor_element.insertBefore(dvddom.createComment(
"dvdauthor XML file created by MythBurn script"), dvdauthor_element.firstChild )
2754 menus_element.appendChild( dvddom.createComment(
"Title menu used to hold intro movie") )
2756 dvdauthor_element.setAttribute(
"dest",os.path.join(
getTempPath(),
"dvd"))
2758 video = dvddom.createElement(
"video")
2759 video.setAttribute(
"format",videomode)
2762 if mainmenuAspectRatio ==
"4:3":
2763 video.setAttribute(
"aspect",
"4:3")
2765 video.setAttribute(
"aspect",
"16:9")
2766 video.setAttribute(
"widescreen",
"nopanscan")
2768 menus_element.appendChild(video)
2770 pgc=menus_element.childNodes[1]
2774 pre = dvddom.createElement(
"pre")
2775 pgc.appendChild(pre)
2779 node = themeDOM.getElementsByTagName(
"intro")[0]
2780 introFile = node.attributes[
"filename"].value
2783 vob = dvddom.createElement(
"vob")
2784 vob.setAttribute(
"file",os.path.join(
getThemeFile(themeName, videomode +
'_' + introFile)))
2785 pgc.appendChild(vob)
2790 post = dvddom.createElement(
"post")
2791 post .appendChild(dvddom.createTextNode(
"{g3=1;g2=1;jump menu 2;}"))
2792 pgc.appendChild(post)
2796 post = dvddom.createElement(
"post")
2797 post .appendChild(dvddom.createTextNode(
"{g3=1;g2=1;jump menu 2;}"))
2798 pgc.appendChild(post)
2801 while itemnum <= numberofitems:
2802 write(
"Menu page %s" % page)
2805 menupgc = dvddom.createElement(
"pgc")
2806 menus_element.appendChild(menupgc)
2808 menupgc.appendChild( dvddom.createComment(
"Menu Page %s" % page) )
2812 pre = dvddom.createElement(
"pre")
2813 pre.appendChild(dvddom.createTextNode(
"{button=g2*1024;g4=%s;}" % page))
2814 menupgc.appendChild(pre)
2816 vob = dvddom.createElement(
"vob")
2817 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"menu-%s.mpg" % page))
2818 menupgc.appendChild(vob)
2821 post = dvddom.createElement(
"post")
2822 post.appendChild(dvddom.createTextNode(
"jump cell 1;"))
2823 menupgc.appendChild(post)
2832 while itemnum <= numberofitems
and itemsonthispage < itemsperpage:
2833 menuitem=menuitems[ itemsonthispage ]
2838 infoDOM = xml.dom.minidom.parse( os.path.join(
getItemTempPath(itemnum),
"info.xml") )
2840 if infoDOM.documentElement.tagName !=
"fileinfo":
2846 button=dvddom.createElement(
"button")
2847 button.setAttribute(
"name",
"%s" % itemnum)
2848 button.appendChild(dvddom.createTextNode(
"{g2=" +
"%s" % itemsonthispage +
"; g5=0; jump title %s;}" % itemnum))
2849 menupgc.appendChild(button)
2853 titleset = dvddom.createElement(
"titleset")
2854 dvdauthor_element.appendChild(titleset)
2857 comment =
getText(infoDOM.getElementsByTagName(
"title")[0]).replace(
'--',
'-')
2858 titleset.appendChild( dvddom.createComment(comment))
2860 menus= dvddom.createElement(
"menus")
2861 titleset.appendChild(menus)
2863 video = dvddom.createElement(
"video")
2864 video.setAttribute(
"format",videomode)
2867 if chaptermenuAspectRatio ==
"4:3":
2868 video.setAttribute(
"aspect",
"4:3")
2869 elif chaptermenuAspectRatio ==
"16:9":
2870 video.setAttribute(
"aspect",
"16:9")
2871 video.setAttribute(
"widescreen",
"nopanscan")
2875 video.setAttribute(
"aspect",
"16:9")
2876 video.setAttribute(
"widescreen",
"nopanscan")
2878 video.setAttribute(
"aspect",
"4:3")
2880 menus.appendChild(video)
2883 mymenupgc = dvddom.createElement(
"pgc")
2884 menus.appendChild(mymenupgc)
2886 pre = dvddom.createElement(
"pre")
2887 mymenupgc.appendChild(pre)
2889 pre.appendChild(dvddom.createTextNode(
"{button=s7 - 1 * 1024;}"))
2891 pre.appendChild(dvddom.createTextNode(
"{button=s7 * 1024;}"))
2893 vob = dvddom.createElement(
"vob")
2894 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % itemnum))
2895 mymenupgc.appendChild(vob)
2898 post = dvddom.createElement(
"post")
2899 post.appendChild(dvddom.createTextNode(
"jump cell 1;"))
2900 mymenupgc.appendChild(post)
2907 chapterlist = thumblist.split(
",")
2908 if chapterlist[0] !=
'00:00:00':
2911 while x <= chapters:
2913 button = dvddom.createElement(
"button")
2914 button.setAttribute(
"name",
"%s" % x)
2916 button.appendChild(dvddom.createTextNode(
"jump title %s chapter %s;" % (1, firstChapter + x + 1)))
2918 button.appendChild(dvddom.createTextNode(
"jump title %s chapter %s;" % (1, firstChapter + x)))
2920 mymenupgc.appendChild(button)
2925 submenunode = themeDOM.getElementsByTagName(
"submenu")
2926 submenunode = submenunode[0]
2927 titlemenunodes = submenunode.getElementsByTagName(
"titlemenu")
2928 if titlemenunodes.length > 0:
2929 button = dvddom.createElement(
"button")
2930 button.setAttribute(
"name",
"titlemenu")
2931 button.appendChild(dvddom.createTextNode(
"{jump vmgm menu;}"))
2932 mymenupgc.appendChild(button)
2935 titles = dvddom.createElement(
"titles")
2936 titleset.appendChild(titles)
2939 title_video = dvddom.createElement(
"video")
2940 title_video.setAttribute(
"format",videomode)
2943 title_video.setAttribute(
"aspect",
"16:9")
2944 title_video.setAttribute(
"widescreen",
"nopanscan")
2946 title_video.setAttribute(
"aspect",
"4:3")
2948 titles.appendChild(title_video)
2952 title_audio = dvddom.createElement(
"audio")
2953 title_audio.setAttribute(
"format",
"mp2")
2955 title_audio = dvddom.createElement(
"audio")
2956 title_audio.setAttribute(
"format",
"ac3")
2958 titles.appendChild(title_audio)
2960 pgc = dvddom.createElement(
"pgc")
2961 titles.appendChild(pgc)
2965 vob = dvddom.createElement(
"vob")
2966 vob.setAttribute(
"file",os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum))
2967 pgc.appendChild(vob)
2969 vob = dvddom.createElement(
"vob")
2972 chapterlist = thumblist.split(
",")
2973 if chapterlist[0] !=
'00:00:00':
2974 thumblist =
'00:00:00,' + thumblist
2975 vob.setAttribute(
"chapters", thumblist)
2977 vob.setAttribute(
"chapters",
2982 vob.setAttribute(
"file",os.path.join(
getItemTempPath(itemnum),
"final.vob"))
2983 pgc.appendChild(vob)
2985 post = dvddom.createElement(
"post")
2986 post.appendChild(dvddom.createTextNode(
"if (g5 eq %s) call vmgm menu %s; call vmgm menu %s;" % (itemnum + 1, autoplaymenu, page + 1)))
2987 pgc.appendChild(post)
2999 for node
in menuitem.childNodes:
3001 if node.nodeName==
"previous":
3003 button=dvddom.createElement(
"button")
3004 button.setAttribute(
"name",
"previous")
3005 button.appendChild(dvddom.createTextNode(
"{g2=1;jump menu %s;}" % page ))
3006 endbuttons.append(button)
3009 elif node.nodeName==
"next":
3010 if itemnum < numberofitems:
3011 button=dvddom.createElement(
"button")
3012 button.setAttribute(
"name",
"next")
3013 button.appendChild(dvddom.createTextNode(
"{g2=1;jump menu %s;}" % (page + 2)))
3014 endbuttons.append(button)
3016 elif node.nodeName==
"playall":
3017 button=dvddom.createElement(
"button")
3018 button.setAttribute(
"name",
"playall")
3019 button.appendChild(dvddom.createTextNode(
"{g5=1; jump menu %s;}" % autoplaymenu))
3020 endbuttons.append(button)
3028 for button
in endbuttons:
3029 menupgc.appendChild(button)
3032 menupgc = dvddom.createElement(
"pgc")
3033 menus_element.appendChild(menupgc)
3034 menupgc.setAttribute(
"pause",
"inf")
3035 menupgc.appendChild( dvddom.createComment(
"Autoplay hack") )
3038 while (itemnum > 1):
3040 dvdcode +=
"if (g5 eq %s) {g5 = %s; jump title %s;} " % (itemnum, itemnum + 1, itemnum)
3041 dvdcode +=
"g5 = 0; jump menu 1;"
3043 pre = dvddom.createElement(
"pre")
3044 pre.appendChild(dvddom.createTextNode(dvdcode))
3045 menupgc.appendChild(pre)
3050 dvdcode=
"if (g3 eq 1) {"
3053 dvdcode+=
"if (g4 eq %s) " % page
3054 dvdcode+=
"jump menu %s;" % (page + 1)
3058 vmgm_pre_node.appendChild(dvddom.createTextNode(dvdcode))
3062 WriteXMLToFile (dvddom,os.path.join(
getTempPath(),
"dvdauthor.xml"))
3071 """Creates the xml file for dvdauthor to use the MythBurn menus."""
3077 write(
"Creating DVD XML file for dvd author (No Main Menu)")
3085 """Creates the xml file for dvdauthor containing no menus."""
3091 write(
"Creating DVD XML file for dvd author (No Menus)")
3093 dvddom = xml.dom.minidom.parseString(
3098 <pgc entry="title" pause="0">
3104 dvdauthor_element = dvddom.documentElement
3105 menus = dvdauthor_element.childNodes[1].childNodes[1]
3106 menu_pgc = menus.childNodes[1]
3108 dvdauthor_element.insertBefore(dvddom.createComment(
"dvdauthor XML file created by MythBurn script"), dvdauthor_element.firstChild )
3109 dvdauthor_element.setAttribute(
"dest",os.path.join(
getTempPath(),
"dvd"))
3113 video = dvddom.createElement(
"video")
3114 video.setAttribute(
"format", videomode)
3117 if mainmenuAspectRatio ==
"4:3":
3118 video.setAttribute(
"aspect",
"4:3")
3120 video.setAttribute(
"aspect",
"16:9")
3121 video.setAttribute(
"widescreen",
"nopanscan")
3122 menus.appendChild(video)
3124 pre = dvddom.createElement(
"pre")
3125 pre.appendChild(dvddom.createTextNode(
"if (g2==1) jump menu 2;"))
3126 menu_pgc.appendChild(pre)
3128 node = themeDOM.getElementsByTagName(
"intro")[0]
3129 introFile = node.attributes[
"filename"].value
3131 vob = dvddom.createElement(
"vob")
3132 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' + introFile))
3133 menu_pgc.appendChild(vob)
3135 post = dvddom.createElement(
"post")
3136 post.appendChild(dvddom.createTextNode(
"g2=1; jump menu 2;"))
3137 menu_pgc.appendChild(post)
3143 pre = dvddom.createElement(
"pre")
3144 pre.appendChild(dvddom.createTextNode(
"g2=1;jump menu 2;"))
3145 menu_pgc.appendChild(pre)
3147 vob = dvddom.createElement(
"vob")
3148 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3149 menu_pgc.appendChild(vob)
3156 menu_pgc = dvddom.createElement(
"pgc")
3158 preText =
"if (g1==0) g1=1;"
3159 for i
in range(numberofitems):
3160 preText +=
"if (g1==%d) jump titleset %d menu;" % (i + 1, i + 1)
3162 pre = dvddom.createElement(
"pre")
3163 pre.appendChild(dvddom.createTextNode(preText))
3164 menu_pgc.appendChild(pre)
3166 vob = dvddom.createElement(
"vob")
3167 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3168 menu_pgc.appendChild(vob)
3169 menus.appendChild(menu_pgc)
3173 while itemNum <= numberofitems:
3174 write(
"Adding item %s" % itemNum)
3176 titleset = dvddom.createElement(
"titleset")
3177 dvdauthor_element.appendChild(titleset)
3180 menu = dvddom.createElement(
"menus")
3181 menupgc = dvddom.createElement(
"pgc")
3182 menu.appendChild(menupgc)
3183 titleset.appendChild(menu)
3187 vob = dvddom.createElement(
"vob")
3188 vob.setAttribute(
"file", os.path.join(
getTempPath(),
"details-%s.mpg" % itemNum))
3189 menupgc.appendChild(vob)
3191 post = dvddom.createElement(
"post")
3192 post.appendChild(dvddom.createTextNode(
"jump title 1;"))
3193 menupgc.appendChild(post)
3197 pre = dvddom.createElement(
"pre")
3198 pre.appendChild(dvddom.createTextNode(
"jump title 1;"))
3199 menupgc.appendChild(pre)
3202 vob = dvddom.createElement(
"vob")
3203 vob.setAttribute(
"file",
getThemeFile(themeName, videomode +
'_' +
"blank.mpg"))
3204 menupgc.appendChild(vob)
3206 titles = dvddom.createElement(
"titles")
3209 title_video = dvddom.createElement(
"video")
3210 title_video.setAttribute(
"format", videomode)
3214 title_video.setAttribute(
"aspect",
"16:9")
3215 title_video.setAttribute(
"widescreen",
"nopanscan")
3217 title_video.setAttribute(
"aspect",
"4:3")
3219 titles.appendChild(title_video)
3221 pgc = dvddom.createElement(
"pgc")
3223 vob = dvddom.createElement(
"vob")
3224 vob.setAttribute(
"file", os.path.join(
getItemTempPath(itemNum),
"final.vob"))
3228 pgc.appendChild(vob)
3233 post = dvddom.createElement(
"post")
3234 if itemNum == numberofitems:
3235 post.appendChild(dvddom.createTextNode(
"exit;"))
3237 post.appendChild(dvddom.createTextNode(
"g1=%d;call vmgm menu 2;" % (itemNum + 1)))
3239 pgc.appendChild(post)
3241 titles.appendChild(pgc)
3242 titleset.appendChild(titles)
3253 WriteXMLToFile (dvddom,os.path.join(
getTempPath(),
"dvdauthor.xml"))
3263 if os.path.exists(previewfolder):
3265 os.rmdir (previewfolder)
3266 os.makedirs(previewfolder)
3267 return previewfolder
3273 """generate thumbnails for a preview in a menu"""
3282 for node
in menuitem.childNodes:
3283 if node.nodeName==
"graphic":
3284 if node.attributes[
"filename"].value ==
"%movie":
3287 outputfile = os.path.join(previewfolder,
"preview-i%d-t%%1-f%%2.jpg" % itemonthispage)
3292 command =
"mytharchivehelper -q -q --createthumbnail --infile %s --thumblist '%s' --outfile %s --framecount %d" % (
quoteCmdArg(inputfile), starttime,
quoteCmdArg(outputfile), frames)
3295 write(
"mytharchivehelper failed with code %d. Command = %s" % (result, command) )
3301 if node.hasAttribute(
"mask"):
3302 imagemaskfilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
3303 if node.attributes[
"mask"].value !=
"" and doesFileExist(imagemaskfilename):
3304 maskpicture = Image.open(imagemaskfilename,
"r").resize((width, height))
3305 maskpicture = maskpicture.convert(
"RGBA")
3307 return (positionx, positiony, width, height, maskpicture)
3313 bgimagemask, drawmask, highlightcolor, spumuxdom, spunode,
3314 numberofitems, chapternumber, chapterlist):
3315 """Draws text and graphics onto a dvd menu, called by
3316 createMenu and createChapterMenu"""
3319 infoDOM = xml.dom.minidom.parse(os.path.join(
getItemTempPath(itemnum),
"info.xml"))
3322 if infoDOM.documentElement.tagName !=
"fileinfo":
3323 fatalError(
"The info.xml file (%s) doesn't look right" %
3328 boundarybox = 9999,9999,0,0
3329 wantHighlightBox =
True
3332 for node
in menuitem.childNodes:
3335 if node.nodeName==
"graphic":
3342 if node.attributes[
"filename"].value ==
"%movie":
3347 node.attributes[
"filename"].value,
3348 itemnum, page, itemsonthispage,
3349 chapternumber, chapterlist)
3352 if imagefilename == node.attributes[
"filename"].value:
3354 node.attributes[
"filename"].value)
3358 if node.hasAttribute(
"mask")
and node.attributes[
"mask"].value !=
"":
3359 maskfilename =
getThemeFile(themeName, node.attributes[
"mask"].value)
3363 if (node.attributes[
"filename"].value ==
"%thumbnail"
3364 and getText(infoDOM.getElementsByTagName(
"coverfile")[0]) !=
""):
3369 if paintImage(imagefilename, maskfilename, node, bgimage, stretch):
3372 write(
"Image file does not exist '%s'" % imagefilename)
3374 elif node.nodeName ==
"text":
3381 itemnum, page, itemsonthispage,
3382 chapternumber, chapterlist)
3390 elif node.nodeName==
"previous":
3397 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3398 itemnum, page, itemsonthispage, chapternumber,
3401 button = spumuxdom.createElement(
"button")
3402 button.setAttribute(
"name",
"previous")
3409 spunode.appendChild(button)
3411 write(
"Added previous page button")
3414 elif node.nodeName ==
"next":
3415 if itemnum < numberofitems:
3421 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3422 itemnum, page, itemsonthispage, chapternumber,
3425 button = spumuxdom.createElement(
"button")
3426 button.setAttribute(
"name",
"next")
3433 spunode.appendChild(button)
3435 write(
"Added next page button")
3437 elif node.nodeName==
"playall":
3443 paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
3444 itemsonthispage, chapternumber, chapterlist)
3446 button = spumuxdom.createElement(
"button")
3447 button.setAttribute(
"name",
"playall")
3454 spunode.appendChild(button)
3456 write(
"Added playall button")
3458 elif node.nodeName ==
"titlemenu":
3459 if itemnum < numberofitems:
3465 paintButton(draw, bgimage, bgimagemask, node, infoDOM,
3466 itemnum, page, itemsonthispage, chapternumber,
3469 button = spumuxdom.createElement(
"button")
3470 button.setAttribute(
"name",
"titlemenu")
3477 spunode.appendChild(button)
3479 write(
"Added titlemenu button")
3481 elif node.nodeName==
"button":
3487 wantHighlightBox =
False
3489 paintButton(draw, bgimage, bgimagemask, node, infoDOM, itemnum, page,
3490 itemsonthispage, chapternumber, chapterlist)
3495 elif node.nodeName==
"#text" or node.nodeName==
"#comment":
3499 write(
"Dont know how to process %s" % node.nodeName)
3501 if drawmask
is None:
3505 if wantHighlightBox ==
True:
3507 boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
3508 drawmask.rectangle(boundarybox,outline=highlightcolor)
3511 boundarybox=boundarybox[0]-1,boundarybox[1]-1,boundarybox[2]+1,boundarybox[3]+1
3512 drawmask.rectangle(boundarybox,outline=highlightcolor)
3514 node = spumuxdom.createElement(
"button")
3517 node.setAttribute(
"name",
"%s" % chapternumber)
3519 node.setAttribute(
"name",
"%s" % itemnum)
3520 node.setAttribute(
"x0",
"%d" % int(boundarybox[0]))
3521 node.setAttribute(
"y0",
"%d" % int(boundarybox[1]))
3522 node.setAttribute(
"x1",
"%d" % int(boundarybox[2] + 1))
3523 node.setAttribute(
"y1",
"%d" % int(boundarybox[3] + 1))
3524 spunode.appendChild(node)
3530 """Creates all the necessary menu images and files for the MythBurn menus."""
3533 menunode=themeDOM.getElementsByTagName(
"menu")
3534 if menunode.length!=1:
3535 fatalError(
"Cannot find menu element in theme file")
3536 menunode=menunode[0]
3538 menuitems=menunode.getElementsByTagName(
"item")
3540 itemsperpage = menuitems.length
3541 write(
"Menu items per page %s" % itemsperpage)
3544 backgroundfilename = menunode.attributes[
"background"].value
3545 if backgroundfilename==
"":
3546 fatalError(
"Background image is not set in theme file")
3548 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3549 write(
"Background image file is %s" % backgroundfilename)
3551 fatalError(
"Background image not found (%s)" % backgroundfilename)
3554 highlightcolor =
"red"
3555 if menunode.hasAttribute(
"highlightcolor"):
3556 highlightcolor = menunode.attributes[
"highlightcolor"].value
3559 menumusic =
"menumusic.ac3"
3560 if menunode.hasAttribute(
"music"):
3561 menumusic = menunode.attributes[
"music"].value
3565 if menunode.hasAttribute(
"length"):
3566 menulength = int(menunode.attributes[
"length"].value)
3568 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3576 write(
"Creating DVD menus")
3578 while itemnum <= numberofitems:
3579 write(
"Menu page %s" % page)
3584 write(
"Creating Preview Video")
3585 previewitem = itemnum
3595 while previewitem <= numberofitems
and itemsonthispage < itemsperpage:
3596 menuitem=menuitems[ itemsonthispage ]
3603 px, py, pw, ph, maskimage =
generateVideoPreview(previewitem, itemsonthispage, menuitem, 0, menulength, previewfolder)
3608 previewmask.append(maskimage)
3615 savedpreviewitem = itemnum
3626 overlayimage=Image.new(
"RGBA",screensize)
3627 draw=ImageDraw.Draw(overlayimage)
3630 bgimagemask=Image.new(
"RGBA",overlayimage.size)
3631 drawmask=ImageDraw.Draw(bgimagemask)
3633 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
3634 spunode = spumuxdom.documentElement.firstChild.firstChild
3637 while itemnum <= numberofitems
and itemsonthispage < itemsperpage:
3638 menuitem=menuitems[ itemsonthispage ]
3643 itemnum, menuitem, overlayimage,
3644 draw, bgimagemask, drawmask, highlightcolor,
3645 spumuxdom, spunode, numberofitems, 0,
"")
3651 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
3652 bgimage.paste(overlayimage, (0,0), overlayimage)
3655 rgb_bgimage=bgimage.convert(
'RGB')
3656 rgb_bgimage.save(os.path.join(
getTempPath(),
"background-%s.jpg" % page),
"JPEG", quality=99)
3658 bgimagemask.save(os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page),
"PNG",quality=99,optimize=0,dpi=screendpi)
3671 if haspreview ==
True:
3672 write(
"Generating the preview images" )
3674 while framenum < numframes:
3675 previewitem = savedpreviewitem
3677 while previewitem <= numberofitems
and itemsonthispage < itemsperpage:
3679 if previewx[itemsonthispage-1] != 9999:
3681 previewfile =
"preview-i%d-t1-f%d.jpg" % (itemsonthispage, framenum)
3682 imagefile = os.path.join(previewpath, previewfile)
3685 picture = Image.open(imagefile,
"r").resize((previeww[itemsonthispage-1], previewh[itemsonthispage-1]))
3686 picture = picture.convert(
"RGBA")
3687 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % itemsonthispage)
3688 if previewmask[itemsonthispage-1]
is not None:
3689 bgimage.paste(picture, (previewx[itemsonthispage-1], previewy[itemsonthispage-1]), previewmask[itemsonthispage-1])
3691 bgimage.paste(picture, (previewx[itemsonthispage-1], previewy[itemsonthispage-1]))
3695 rgb_bgimage=bgimage.convert(
'RGB')
3696 rgb_bgimage.save(os.path.join(
getTempPath(),
"background-%s-f%06d.jpg" % (page, framenum)),
"JPEG",quality=99)
3700 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"select",os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page))
3701 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"highlight",os.path.join(
getTempPath(),
"backgroundmask-%s.png" % page))
3713 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"spumux-%s.xml" % page))
3715 if mainmenuAspectRatio ==
"4:3":
3720 write(
"Encoding Menu Page %s using aspect ratio '%s'" % (page, mainmenuAspectRatio))
3721 if haspreview ==
True:
3727 os.path.join(
getTempPath(),
"spumux-%s.xml" % page),
3736 os.path.join(
getTempPath(),
"spumux-%s.xml" % page),
3747 """Creates all the necessary menu images and files for the MythBurn menus."""
3750 menunode=themeDOM.getElementsByTagName(
"submenu")
3751 if menunode.length!=1:
3752 fatalError(
"Cannot find submenu element in theme file")
3753 menunode=menunode[0]
3755 menuitems=menunode.getElementsByTagName(
"chapter")
3757 itemsperpage = menuitems.length
3758 write(
"Chapter items per page %s " % itemsperpage)
3761 backgroundfilename = menunode.attributes[
"background"].value
3762 if backgroundfilename==
"":
3763 fatalError(
"Background image is not set in theme file")
3764 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3765 write(
"Background image file is %s" % backgroundfilename)
3767 fatalError(
"Background image not found (%s)" % backgroundfilename)
3770 highlightcolor =
"red"
3771 if menunode.hasAttribute(
"highlightcolor"):
3772 highlightcolor = menunode.attributes[
"highlightcolor"].value
3775 menumusic =
"menumusic.ac3"
3776 if menunode.hasAttribute(
"music"):
3777 menumusic = menunode.attributes[
"music"].value
3781 if menunode.hasAttribute(
"length"):
3782 menulength = int(menunode.attributes[
"length"].value)
3784 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3789 write(
"Creating DVD sub-menus")
3791 while page <= numberofitems:
3792 write(
"Sub-menu %s " % page)
3800 overlayimage=Image.new(
"RGBA",screensize, (0,0,0,0))
3801 draw=ImageDraw.Draw(overlayimage)
3804 bgimagemask=Image.new(
"RGBA",overlayimage.size, (0,0,0,0))
3805 drawmask=ImageDraw.Draw(bgimagemask)
3807 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
3808 spunode = spumuxdom.documentElement.firstChild.firstChild
3812 chapterlist=chapterlist.split(
",")
3831 while previewchapter < itemsperpage:
3832 menuitem=menuitems[ previewchapter ]
3837 px, py, pw, ph, maskimage =
generateVideoPreview(page, previewchapter, menuitem, previewtime, menulength, previewfolder)
3842 previewmask.append(maskimage)
3851 while chapter < itemsperpage:
3852 menuitem=menuitems[ chapter ]
3857 bgimagemask, drawmask, highlightcolor,
3859 999, chapter, chapterlist)
3862 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
3863 bgimage.paste(overlayimage, (0,0), overlayimage)
3864 rgb_bgimage=bgimage.convert(
'RGB')
3865 rgb_bgimage.save(os.path.join(
getTempPath(),
"chaptermenu-%s.jpg" % page),
"JPEG", quality=99)
3868 bgimagemask.save(os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page),
"PNG",quality=90,optimize=0)
3870 if haspreview ==
True:
3875 write(
"Generating the preview images" )
3877 while framenum < numframes:
3879 while previewchapter < itemsperpage:
3880 if previewx[previewchapter] != 9999:
3882 previewfile =
"preview-i%d-t1-f%d.jpg" % (previewchapter, framenum)
3883 imagefile = os.path.join(previewpath, previewfile)
3886 picture = Image.open(imagefile,
"r").resize((previeww[previewchapter], previewh[previewchapter]))
3887 picture = picture.convert(
"RGBA")
3888 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % previewchapter)
3889 if previewmask[previewchapter]
is not None:
3890 bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]), previewmask[previewchapter])
3892 bgimage.paste(picture, (previewx[previewchapter], previewy[previewchapter]))
3895 rgb_bgimage=bgimage.convert(
'RGB')
3896 rgb_bgimage.save(os.path.join(
getTempPath(),
"chaptermenu-%s-f%06d.jpg" % (page, framenum)),
"JPEG",quality=99)
3900 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"select",os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page))
3901 spumuxdom.documentElement.firstChild.firstChild.setAttribute(
"highlight",os.path.join(
getTempPath(),
"chaptermenumask-%s.png" % page))
3914 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page))
3916 if chaptermenuAspectRatio ==
"4:3":
3918 elif chaptermenuAspectRatio ==
"16:9":
3926 write(
"Encoding Chapter Menu Page %s using aspect ratio '%s'" % (page, chaptermenuAspectRatio))
3928 if haspreview ==
True:
3934 os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page),
3935 os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % page),
3943 os.path.join(
getTempPath(),
"chapterspumux-%s.xml" % page),
3944 os.path.join(
getTempPath(),
"chaptermenu-%s.mpg" % page),
3954 """Creates all the necessary images and files for the details page."""
3956 write(
"Creating details pages")
3959 detailnode=themeDOM.getElementsByTagName(
"detailspage")
3960 if detailnode.length!=1:
3961 fatalError(
"Cannot find detailspage element in theme file")
3962 detailnode=detailnode[0]
3965 backgroundfilename = detailnode.attributes[
"background"].value
3966 if backgroundfilename==
"":
3967 fatalError(
"Background image is not set in theme file")
3968 backgroundfilename =
getThemeFile(themeName,backgroundfilename)
3969 write(
"Background image file is %s" % backgroundfilename)
3971 fatalError(
"Background image not found (%s)" % backgroundfilename)
3974 menumusic =
"menumusic.ac3"
3975 if detailnode.hasAttribute(
"music"):
3976 menumusic = detailnode.attributes[
"music"].value
3980 if detailnode.hasAttribute(
"length"):
3981 menulength = int(detailnode.attributes[
"length"].value)
3983 write(
"Music is %s, length is %s seconds" % (menumusic, menulength))
3988 while itemnum <= numberofitems:
3989 write(
"Creating details page for %s" % itemnum)
3996 previewx, previewy, previeww, previewh, previewmask =
generateVideoPreview(itemnum, 1, detailnode, 0, menulength, previewfolder)
3997 if previewx != 9999:
4006 overlayimage=Image.new(
"RGBA",screensize, (0,0,0,0))
4007 draw=ImageDraw.Draw(overlayimage)
4009 spumuxdom = xml.dom.minidom.parseString(
'<subpictures><stream><spu force="yes" start="00:00:00.0" highlight="" select="" ></spu></stream></subpictures>')
4010 spunode = spumuxdom.documentElement.firstChild.firstChild
4012 drawThemeItem(0, 0, itemnum, detailnode, overlayimage, draw,
None,
None,
4013 "", spumuxdom, spunode, numberofitems, 0,
"")
4016 bgimage=Image.open(backgroundfilename,
"r").resize(screensize)
4017 bgimage.paste(overlayimage, (0,0), overlayimage)
4018 rgb_bgimage=bgimage.convert(
'RGB')
4019 rgb_bgimage.save(os.path.join(
getTempPath(),
"details-%s.jpg" % itemnum),
"JPEG", quality=99)
4022 if haspreview ==
True:
4026 write(
"Generating the detail preview images" )
4028 while framenum < numframes:
4029 if previewx != 9999:
4031 previewfile =
"preview-i%d-t1-f%d.jpg" % (1, framenum)
4032 imagefile = os.path.join(previewpath, previewfile)
4035 picture = Image.open(imagefile,
"r").resize((previeww, previewh))
4036 picture = picture.convert(
"RGBA")
4037 imagemaskfile = os.path.join(previewpath,
"mask-i%d.png" % 1)
4038 if previewmask
is not None:
4039 bgimage.paste(picture, (previewx, previewy), previewmask)
4041 bgimage.paste(picture, (previewx, previewy))
4043 rgb_bgimage=bgimage.convert(
'RGB')
4044 rgb_bgimage.save(os.path.join(
getTempPath(),
"details-%s-f%06d.jpg" % (itemnum, framenum)),
"JPEG",quality=99)
4059 WriteXMLToFile (spumuxdom,os.path.join(
getTempPath(),
"detailsspumux-%s.xml" % itemnum))
4061 write(
"Encoding Details Page %s" % itemnum)
4062 if haspreview ==
True:
4069 os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum),
4078 os.path.join(
getTempPath(),
"details-%s.mpg" % itemnum),
4088 fh = open(file,
'rb')
4091 return Magic==
"RIFF"
4097 """encode audio to ac3 for better compression and compatability with NTSC players"""
4100 if not encodetoac3
and doesFileExist(os.path.join(folder,
'stream0.mp2')):
4102 write(
"Audio track 1 is in mp2 format - NOT re-encoding to ac3")
4103 elif doesFileExist(os.path.join(folder,
'stream0.mp2'))==
True:
4104 write(
"Audio track 1 is in mp2 format - re-encoding to ac3")
4105 encodeAudio(
"ac3",os.path.join(folder,
'stream0.mp2'), os.path.join(folder,
'stream0.ac3'),
True)
4106 elif doesFileExist(os.path.join(folder,
'stream0.mpa'))==
True:
4107 write(
"Audio track 1 is in mpa format - re-encoding to ac3")
4108 encodeAudio(
"ac3",os.path.join(folder,
'stream0.mpa'), os.path.join(folder,
'stream0.ac3'),
True)
4109 elif doesFileExist(os.path.join(folder,
'stream0.ac3'))==
True:
4110 write(
"Audio is already in ac3 format")
4112 fatalError(
"Track 1 - Unknown audio format or de-multiplex failed!")
4115 if not encodetoac3
and doesFileExist(os.path.join(folder,
'stream1.mp2')):
4117 write(
"Audio track 2 is in mp2 format - NOT re-encoding to ac3")
4118 elif doesFileExist(os.path.join(folder,
'stream1.mp2'))==
True:
4119 write(
"Audio track 2 is in mp2 format - re-encoding to ac3")
4120 encodeAudio(
"ac3",os.path.join(folder,
'stream1.mp2'), os.path.join(folder,
'stream1.ac3'),
True)
4121 elif doesFileExist(os.path.join(folder,
'stream1.mpa'))==
True:
4122 write(
"Audio track 2 is in mpa format - re-encoding to ac3")
4123 encodeAudio(
"ac3",os.path.join(folder,
'stream1.mpa'), os.path.join(folder,
'stream1.ac3'),
True)
4124 elif doesFileExist(os.path.join(folder,
'stream1.ac3'))==
True:
4125 write(
"Audio is already in ac3 format")
4141 """Choose the streams we want from the source file"""
4143 video = (-1,
'N/A', -1)
4144 audio1 = (-1,
'N/A', -1,
'N/A')
4145 audio2 = (-1,
'N/A', -1,
'N/A')
4148 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4150 if infoDOM.documentElement.tagName !=
"file":
4151 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4155 nodes = infoDOM.getElementsByTagName(
"video")
4156 if nodes.length == 0:
4157 write(
"Didn't find any video elements in stream info file.!!!")
4160 if nodes.length > 1:
4161 write(
"Found more than one video element in stream info file.!!!")
4163 video = (int(node.attributes[
"ffmpegindex"].value), node.attributes[
"codec"].value, int(node.attributes[
"id"].value))
4172 write(
"Preferred audio languages %s and %s" % (preferredlang1, preferredlang2))
4174 nodes = infoDOM.getElementsByTagName(
"audio")
4176 if nodes.length == 0:
4177 write(
"Didn't find any audio elements in stream info file.!!!")
4184 index = int(node.attributes[
"ffmpegindex"].value)
4185 lang = node.attributes[
"language"].value
4186 format = node.attributes[
"codec"].value.upper()
4187 pid = int(node.attributes[
"id"].value)
4188 if lang == preferredlang1
and format ==
"AC3":
4190 if pid < audio1[AUDIO_ID]:
4191 audio1 = (index, format, pid, lang)
4193 audio1 = (index, format, pid, lang)
4199 index = int(node.attributes[
"ffmpegindex"].value)
4200 lang = node.attributes[
"language"].value
4201 format = node.attributes[
"codec"].value.upper()
4202 pid = int(node.attributes[
"id"].value)
4203 if lang == preferredlang1
and format ==
"MP2":
4205 if pid < audio1[AUDIO_ID]:
4206 audio1 = (index, format, pid, lang)
4208 audio1 = (index, format, pid, lang)
4214 index = int(node.attributes[
"ffmpegindex"].value)
4215 format = node.attributes[
"codec"].value.upper()
4216 pid = int(node.attributes[
"id"].value)
4218 audio1 = (index, format, pid, lang)
4221 if format ==
"AC3" and audio1[AUDIO_CODEC] ==
"MP2":
4222 audio1 = (index, format, pid, lang)
4224 if pid < audio1[AUDIO_ID]:
4225 audio1 = (index, format, pid, lang)
4228 if preferredlang1 != preferredlang2
and nodes.length > 1:
4232 index = int(node.attributes[
"ffmpegindex"].value)
4233 lang = node.attributes[
"language"].value
4234 format = node.attributes[
"codec"].value.upper()
4235 pid = int(node.attributes[
"id"].value)
4236 if lang == preferredlang2
and format ==
"AC3":
4238 if pid < audio2[AUDIO_ID]:
4239 audio2 = (index, format, pid, lang)
4241 audio2 = (index, format, pid, lang)
4247 index = int(node.attributes[
"ffmpegindex"].value)
4248 lang = node.attributes[
"language"].value
4249 format = node.attributes[
"codec"].value.upper()
4250 pid = int(node.attributes[
"id"].value)
4251 if lang == preferredlang2
and format ==
"MP2":
4253 if pid < audio2[AUDIO_ID]:
4254 audio2 = (index, format, pid, lang)
4256 audio2 = (index, format, pid, lang)
4262 index = int(node.attributes[
"ffmpegindex"].value)
4263 format = node.attributes[
"codec"].value.upper()
4264 pid = int(node.attributes[
"id"].value)
4267 if pid != audio1[AUDIO_ID]:
4268 audio2 = (index, format, pid, lang)
4271 if format ==
"AC3" and audio2[AUDIO_CODEC] ==
"MP2" and pid != audio1[AUDIO_ID]:
4272 audio2 = (index, format, pid, lang)
4274 if pid < audio2[AUDIO_ID]
and pid != audio1[AUDIO_ID]:
4275 audio2 = (index, format, pid, lang)
4277 write(
"Video id: 0x%x, Audio1: [%d] 0x%x (%s, %s), Audio2: [%d] - 0x%x (%s, %s)" % \
4278 (video[VIDEO_ID], audio1[AUDIO_INDEX], audio1[AUDIO_ID], audio1[AUDIO_CODEC], audio1[AUDIO_LANG], \
4279 audio2[AUDIO_INDEX], audio2[AUDIO_ID], audio2[AUDIO_CODEC], audio2[AUDIO_LANG]))
4281 return (video, audio1, audio2)
4293 """Choose the subtitle stream we want from the source file"""
4295 subtitle = (-1,
'N/A', -1,
'N/A')
4298 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4300 if infoDOM.documentElement.tagName !=
"file":
4301 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4305 nodes = infoDOM.getElementsByTagName(
"subtitle")
4306 if nodes.length == 0:
4307 write(
"Didn't find any subtitle elements in stream info file.")
4310 write(
"Preferred languages %s and %s" % (preferredlang1, preferredlang2))
4315 index = int(node.attributes[
"ffmpegindex"].value)
4316 lang = node.attributes[
"language"].value
4317 format = node.attributes[
"codec"].value.upper()
4318 pid = int(node.attributes[
"id"].value)
4319 if not found
and lang == preferredlang1
and format ==
"dvbsub":
4320 subtitle = (index, format, pid, lang)
4326 index = int(node.attributes[
"ffmpegindex"].value)
4327 lang = node.attributes[
"language"].value
4328 format = node.attributes[
"codec"].value.upper()
4329 pid = int(node.attributes[
"id"].value)
4330 if not found
and lang == preferredlang2
and format ==
"dvbsub":
4331 subtitle = (index, format, pid, lang)
4337 index = int(node.attributes[
"ffmpegindex"].value)
4338 format = node.attributes[
"codec"].value.upper()
4339 pid = int(node.attributes[
"id"].value)
4341 subtitle = (index, format, pid, lang)
4344 write(
"Subtitle id: 0x%x" % (subtitle[SUBTITLE_ID]))
4352 """figure out what aspect ratio we want from the source file"""
4358 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4360 if infoDOM.documentElement.tagName !=
"file":
4361 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4365 nodes = infoDOM.getElementsByTagName(
"video")
4366 if nodes.length == 0:
4367 write(
"Didn't find any video elements in stream info file.!!!")
4370 if nodes.length > 1:
4371 write(
"Found more than one video element in stream info file.!!!")
4374 ar = float(node.attributes[
"aspectratio"].value)
4375 if ar > float(4.0/3.0 - 0.01)
and ar < float(4.0/3.0 + 0.01):
4377 write(
"Aspect ratio is 4:3")
4378 elif ar > float(16.0/9.0 - 0.01)
and ar < float(16.0/9.0 + 0.01):
4379 aspectratio =
"16:9"
4380 write(
"Aspect ratio is 16:9")
4382 write(
"Unknown aspect ratio %f - Using 16:9" % ar)
4383 aspectratio =
"16:9"
4385 aspectratio =
"16:9"
4393 """Get the video codec from the streaminfo.xml for the file"""
4396 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4398 if infoDOM.documentElement.tagName !=
"file":
4399 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4401 nodes = infoDOM.getElementsByTagName(
"video")
4402 if nodes.length == 0:
4403 write(
"Didn't find any video elements in stream info file!!!")
4406 if nodes.length > 1:
4407 write(
"Found more than one video element in stream info file!!!")
4409 return node.attributes[
"codec"].value
4415 """Get the overall file type from the streaminfo.xml for the file"""
4418 infoDOM = xml.dom.minidom.parse(os.path.join(folder,
'streaminfo.xml'))
4420 if infoDOM.documentElement.tagName !=
"file":
4421 fatalError(
"This does not look like a stream info file (%s)" % os.path.join(folder,
'streaminfo.xml'))
4423 nodes = infoDOM.getElementsByTagName(
"file")
4424 if nodes.length == 0:
4425 write(
"Didn't find any file elements in stream info file!!!")
4428 if nodes.length > 1:
4429 write(
"Found more than one file element in stream info file!!!")
4432 return node.attributes[
"type"].value
4442 streamList =
"0x%x" % video[VIDEO_ID]
4444 if audio1[AUDIO_ID] != -1:
4445 streamList +=
",0x%x" % audio1[AUDIO_ID]
4447 if audio2[AUDIO_ID] != -1:
4448 streamList +=
",0x%x" % audio2[AUDIO_ID]
4453 if subtitles[SUBTITLE_ID] != -1:
4454 streamList +=
",0x%x" % subtitles[SUBTITLE_ID]
4463 """return true if the file is dvd compliant"""
4465 if not getVideoCodec(folder).lower().startswith(
"mpeg2video"):
4472 videosize =
getVideoSize(os.path.join(folder,
"streaminfo.xml"))
4475 if file.hasAttribute(
"encodingprofile"):
4476 if file.attributes[
"encodingprofile"].value !=
"NONE":
4477 write(
"File will be re-encoded using profile %s" % file.attributes[
"encodingprofile"].value)
4482 if file.hasAttribute(
"encodingprofile"):
4483 if file.attributes[
"encodingprofile"].value ==
"NONE":
4484 write(
"WARNING: File does not have a DVD compliant resolution but "
4485 "you have selected not to re-encode the file")
4497 """Process a single video/recording file ready for burning."""
4509 """Process a single video/recording file ready for burning."""
4511 write(
"*************************************************************")
4512 write(
"Processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
4513 write(
"*************************************************************")
4523 if file.hasAttribute(
"localfilename"):
4524 mediafile=file.attributes[
"localfilename"].value
4525 elif file.attributes[
"type"].value==
"recording":
4526 mediafile = file.attributes[
"filename"].value
4527 elif file.attributes[
"type"].value==
"video":
4528 mediafile=os.path.join(videopath, file.attributes[
"filename"].value)
4529 elif file.attributes[
"type"].value==
"file":
4530 mediafile=file.attributes[
"filename"].value
4532 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
4535 infoDOM = xml.dom.minidom.parse( os.path.join(folder,
"info.xml") )
4537 if infoDOM.documentElement.tagName !=
"fileinfo":
4538 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
4542 if file.attributes[
"type"].value ==
"recording":
4546 if (
getVideoCodec(folder)).lower().startswith(
"mpeg2video"):
4547 if file.attributes[
"usecutlist"].value ==
"1" and getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes":
4549 if file.hasAttribute(
"localfilename"):
4550 localfile = file.attributes[
"localfilename"].value
4553 write(
"File has a cut list - running mythtranscode to remove unwanted segments")
4554 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4555 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4556 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
True, localfile):
4557 mediafile = os.path.join(folder,
'newfile.mpg')
4559 write(
"Failed to run mythtranscode to remove unwanted segments")
4563 if (alwaysRunMythtranscode ==
True or
4566 if file.hasAttribute(
"localfilename"):
4567 localfile = file.attributes[
"localfilename"].value
4570 write(
"Running mythtranscode --mpeg2 to fix any errors")
4571 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4572 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4573 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
False, localfile):
4574 mediafile = os.path.join(folder,
'newfile.mpg')
4576 write(
"Failed to run mythtranscode to fix any errors")
4583 if (alwaysRunMythtranscode ==
True and
4586 if file.hasAttribute(
"localfilename"):
4587 localfile = file.attributes[
"localfilename"].value
4589 localfile = file.attributes[
"filename"].value
4590 write(
"Running mythtranscode --mpeg2 to fix any errors")
4593 if runMythtranscode(chanid, starttime, os.path.join(folder,
'newfile.mpg'),
False, localfile):
4594 mediafile = os.path.join(folder,
'newfile.mpg')
4596 write(
"Failed to run mythtranscode to fix any errors")
4614 write(
"Re-encoding audio and video from nuv file")
4617 if file.hasAttribute(
"encodingprofile"):
4618 profile = file.attributes[
"encodingprofile"].value
4620 profile = defaultEncodingProfile
4622 if file.hasAttribute(
"localfilename"):
4623 mediafile = file.attributes[
"localfilename"].value
4627 elif file.attributes[
"type"].value ==
"recording":
4629 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4630 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4631 usecutlist = (file.attributes[
"usecutlist"].value ==
"1" and
4632 getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes")
4638 encodeNuvToMPEG2(chanid, starttime, mediafile, os.path.join(folder,
"newfile2.mpg"), folder,
4639 profile, usecutlist)
4640 mediafile = os.path.join(folder,
'newfile2.mpg')
4652 write(
"Re-encoding audio and video")
4655 if file.hasAttribute(
"localfilename"):
4656 mediafile = file.attributes[
"localfilename"].value
4659 if file.hasAttribute(
"encodingprofile"):
4660 profile = file.attributes[
"encodingprofile"].value
4662 profile = defaultEncodingProfile
4666 audio1, audio2, aspectratio, profile)
4667 mediafile = os.path.join(folder,
'newfile2.mpg')
4671 if debug_keeptempfiles==
False:
4672 if os.path.exists(os.path.join(folder,
"newfile.mpg")):
4673 os.remove(os.path.join(folder,
'newfile.mpg'))
4684 write(
"Splitting MPEG stream into audio and video parts")
4688 if debug_keeptempfiles==
False:
4689 if os.path.exists(os.path.join(folder,
"newfile.mpg")):
4690 os.remove(os.path.join(folder,
'newfile.mpg'))
4691 if os.path.exists(os.path.join(folder,
"newfile2.mpg")):
4692 os.remove(os.path.join(folder,
'newfile2.mpg'))
4699 titleImage = os.path.join(folder,
"title.jpg")
4700 if not os.path.exists(titleImage):
4702 if file.attributes[
"type"].value ==
"recording":
4703 previewImage = file.attributes[
"filename"].value +
".png"
4704 if usebookmark ==
True and os.path.exists(previewImage):
4705 copy(previewImage, titleImage)
4711 write(
"*************************************************************")
4712 write(
"Finished processing '%s'" % file.attributes[
"filename"].value)
4713 write(
"*************************************************************")
4721 """Process a single video/recording file ready for burning."""
4723 write(
"*************************************************************")
4724 write(
"Processing %s %d: '%s'" % (file.attributes[
"type"].value, count, file.attributes[
"filename"].value))
4725 write(
"*************************************************************")
4735 if file.hasAttribute(
"localfilename"):
4736 mediafile=file.attributes[
"localfilename"].value
4737 elif file.attributes[
"type"].value==
"recording":
4738 mediafile = file.attributes[
"filename"].value
4739 elif file.attributes[
"type"].value==
"video":
4740 mediafile=os.path.join(videopath, file.attributes[
"filename"].value)
4741 elif file.attributes[
"type"].value==
"file":
4742 mediafile=file.attributes[
"filename"].value
4744 fatalError(
"Unknown type of video file it must be 'recording', 'video' or 'file'.")
4747 infoDOM = xml.dom.minidom.parse( os.path.join(folder,
"info.xml") )
4749 if infoDOM.documentElement.tagName !=
"fileinfo":
4750 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
4768 write(
"Re-encoding audio and video from nuv file")
4771 if file.hasAttribute(
"encodingprofile"):
4772 profile = file.attributes[
"encodingprofile"].value
4774 profile = defaultEncodingProfile
4776 if file.hasAttribute(
"localfilename"):
4777 mediafile = file.attributes[
"localfilename"].value
4781 elif file.attributes[
"type"].value ==
"recording":
4783 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4784 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4785 usecutlist = (file.attributes[
"usecutlist"].value ==
"1" and
4786 getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes")
4792 encodeNuvToMPEG2(chanid, starttime, mediafile, os.path.join(folder,
"newfile2.mpg"), folder,
4793 profile, usecutlist)
4794 mediafile = os.path.join(folder,
'newfile2.mpg')
4806 write(
"Re-encoding audio and video")
4809 if file.hasAttribute(
"localfilename"):
4810 mediafile = file.attributes[
"localfilename"].value
4813 if file.hasAttribute(
"encodingprofile"):
4814 profile = file.attributes[
"encodingprofile"].value
4816 profile = defaultEncodingProfile
4820 audio1, audio2, aspectratio, profile)
4821 mediafile = os.path.join(folder,
'newfile2.mpg')
4824 if os.path.exists(os.path.join(folder,
"newfile1.mpg")):
4825 os.remove(os.path.join(folder,
'newfile1.mpg'))
4841 if file.attributes[
"type"].value ==
"recording":
4842 if file.attributes[
"usecutlist"].value ==
"1" and getText(infoDOM.getElementsByTagName(
"hascutlist")[0]) ==
"yes":
4843 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4844 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4845 write(
"File has a cut list - running Project-X to remove unwanted segments")
4846 if not runProjectX(chanid, starttime, folder,
True, mediafile):
4847 fatalError(
"Failed to run Project-X to remove unwanted segments and demux")
4850 chanid =
getText(infoDOM.getElementsByTagName(
"chanid")[0])
4851 starttime =
getText(infoDOM.getElementsByTagName(
"starttime")[0])
4852 write(
"Using Project-X to demux file")
4853 if not runProjectX(chanid, starttime, folder,
False, mediafile):
4854 fatalError(
"Failed to run Project-X to demux file")
4859 write(
"Running Project-X to demux file")
4860 if not runProjectX(chanid, starttime, folder,
False, mediafile):
4861 fatalError(
"Failed to run Project-X to demux file")
4868 titleImage = os.path.join(folder,
"title.jpg")
4869 if not os.path.exists(titleImage):
4871 if file.attributes[
"type"].value ==
"recording":
4872 previewImage = file.attributes[
"filename"].value +
".png"
4873 if usebookmark ==
True and os.path.exists(previewImage):
4874 copy(previewImage, titleImage)
4880 write(
"*************************************************************")
4881 write(
"Finished processing file '%s'" % file.attributes[
"filename"].value)
4882 write(
"*************************************************************")
4888 '''go through the list of files looking for files on remote filesytems
4889 and copy them to a local file for quicker processing'''
4890 localTmpPath = os.path.join(tmpPath,
"localcopy")
4892 tmpfile = node.attributes[
"filename"].value
4893 filename = os.path.basename(tmpfile)
4897 if res == 2
and copyremoteFiles==
True:
4899 write(
"Copying file from " + tmpfile)
4900 write(
"to " + os.path.join(localTmpPath, filename))
4904 copy(tmpfile, os.path.join(localTmpPath, filename))
4907 node.setAttribute(
"localfilename", os.path.join(localTmpPath, filename))
4910 write(
"Copying file from " + tmpfile)
4911 localfile = os.path.join(localTmpPath, filename)
4912 write(
"to " + localfile)
4919 node.setAttribute(
"localfilename", localfile)
4926 """Starts processing a MythBurn job, expects XML nodes to be passed as input."""
4927 global wantIntro, wantMainMenu, wantChapterMenu, wantDetailsPage
4928 global themeDOM, themeName, themeFonts
4931 media=job.getElementsByTagName(
"media")
4935 themeName=job.attributes[
"theme"].value
4939 fatalError(
"Failed to validate theme (%s)" % themeName)
4947 nodes=themeDOM.getElementsByTagName(
"intro")
4948 wantIntro = (nodes.length > 0)
4950 nodes=themeDOM.getElementsByTagName(
"menu")
4951 wantMainMenu = (nodes.length > 0)
4953 nodes=themeDOM.getElementsByTagName(
"submenu")
4954 wantChapterMenu = (nodes.length > 0)
4956 nodes=themeDOM.getElementsByTagName(
"detailspage")
4957 wantDetailsPage = (nodes.length > 0)
4959 write(
"wantIntro: %d, wantMainMenu: %d, wantChapterMenu: %d, wantDetailsPage: %d" \
4960 % (wantIntro, wantMainMenu, wantChapterMenu, wantDetailsPage))
4962 if videomode==
"ntsc":
4965 elif videomode==
"pal":
4969 fatalError(
"Unknown videomode is set (%s)" % videomode)
4971 write(
"Final DVD Video format will be " + videomode)
4975 files=media[0].getElementsByTagName(
"file")
4977 if files.length > 0:
4978 write(
"There are %s file(s) to process" % files.length)
4980 if debug_secondrunthrough==
False:
4983 localCopyFolder=os.path.join(
getTempPath(),
"localcopy")
4984 os.makedirs(localCopyFolder)
4996 if debug_secondrunthrough==
False:
5001 if debug_secondrunthrough==
False:
5027 if not wantMainMenu
and not wantChapterMenu:
5029 elif not wantMainMenu:
5035 if mediatype == DVD_DL:
5050 os.path.join(folder,
'stream0'),
5051 os.path.join(folder,
'stream1'),
5052 os.path.join(folder,
'final.vob'),
5059 if debug_keeptempfiles==
False:
5064 if os.path.exists(os.path.join(folder,
"stream.mv2")):
5065 os.remove(os.path.join(folder,
'stream.mv2'))
5066 if os.path.exists(os.path.join(folder,
"stream0.mp2")):
5067 os.remove(os.path.join(folder,
'stream0.mp2'))
5068 if os.path.exists(os.path.join(folder,
"stream1.mp2")):
5069 os.remove(os.path.join(folder,
'stream1.mp2'))
5070 if os.path.exists(os.path.join(folder,
"stream0.ac3")):
5071 os.remove(os.path.join(folder,
'stream0.ac3'))
5072 if os.path.exists(os.path.join(folder,
"stream1.ac3")):
5073 os.remove(os.path.join(folder,
'stream1.ac3'))
5077 infoDOM = xml.dom.minidom.parse( os.path.join(
getItemTempPath(1),
"info.xml") )
5079 if infoDOM.documentElement.tagName !=
"fileinfo":
5080 fatalError(
"The info.xml file (%s) doesn't look right" % os.path.join(folder,
"info.xml"))
5083 title = title.encode(
'ascii',
'replace').
decode(
'ascii',
'replace')
5084 title = title.strip()
5089 while (index < len(title))
and (index < 32):
5090 if title[index].isalnum
and title[index] !=
' ':
5091 title_new += title[index]
5096 title = title_new.upper()
5102 if docreateiso ==
True or mediatype == FILE:
5106 if doburn ==
True and mediatype != FILE:
5110 if mediatype == FILE
and savefilename !=
"":
5111 write(
"Moving ISO image to: %s" % savefilename)
5113 os.rename(os.path.join(
getTempPath(),
'mythburn.iso'), savefilename)
5115 f1 = open(os.path.join(
getTempPath(),
'mythburn.iso'),
'rb')
5116 f2 = open(savefilename,
'wb')
5117 data = f1.read(1024 * 1024)
5120 data = f1.read(1024 * 1024)
5123 os.unlink(os.path.join(
getTempPath(),
'mythburn.iso'))
5125 write(
"Nothing to do! (files)")
5127 write(
"Nothing to do! (media)")
5135 -h/--help (Show this usage)
5136 -j/--jobfile file (use file as the job file)
5137 -l/--progresslog file (log file to output progress messages)
5145 global sharepath, scriptpath, cpuCount, videopath, gallerypath, musicpath
5146 global videomode, temppath, logpath, dvddrivepath, dbVersion, preferredlang1
5147 global preferredlang2, useFIFO, encodetoac3, alwaysRunMythtranscode
5148 global copyremoteFiles, mainmenuAspectRatio, chaptermenuAspectRatio, dateformat
5149 global timeformat, clearArchiveTable, nicelevel, drivespeed, path_mplex
5150 global path_dvdauthor, path_mkisofs, path_growisofs, path_M2VRequantiser, addSubtitles
5151 global path_jpeg2yuv, path_spumux, path_mpeg2enc, path_projectx, useprojectx, progresslog
5152 global progressfile, jobfile
5154 write(
"mythburn.py (%s) starting up..." % VERSION)
5157 if not hasattr(sys,
"hexversion")
or sys.hexversion < 0x20305F0:
5158 sys.stderr.write(
"Sorry, your Python is too old. Please upgrade at least to 2.3.5\n")
5162 scriptpath = os.path.dirname(sys.argv[0])
5163 scriptpath = os.path.abspath(scriptpath)
5164 write(
"script path:" + scriptpath)
5167 sharepath = os.path.split(scriptpath)[0]
5168 sharepath = os.path.split(sharepath)[0]
5169 write(
"myth share path:" + sharepath)
5173 opts, args = getopt.getopt(sys.argv[1:],
"j:hl:", [
"jobfile=",
"help",
"progresslog="])
5174 except getopt.GetoptError:
5180 if o
in (
"-h",
"--help"):
5183 if o
in (
"-j",
"--jobfile"):
5185 write(
"passed job file: " + a)
5186 if o
in (
"-l",
"--progresslog"):
5187 progresslog = str(a)
5188 write(
"passed progress log file: " + a)
5191 if progresslog !=
"":
5192 if os.path.exists(progresslog):
5193 os.remove(progresslog)
5194 progressfile = codecs.open(progresslog,
'w',
'utf-8')
5195 write(
"mythburn.py (%s) starting up..." % VERSION)
5200 saveSetting(
"MythArchiveLastRunStart", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5202 saveSetting(
"MythArchiveLastRunStatus",
"Running")
5209 if not os.environ[
'PATH'].endswith(
':'):
5210 os.environ[
'PATH'] +=
":"
5211 os.environ[
'PATH'] +=
"/bin:/sbin:/usr/local/bin:/usr/bin:/opt/bin:" + installPrefix +
"/bin:"
5215 videopath = defaultsettings.get(
"VideoStartupDir",
None)
5216 gallerypath = defaultsettings.get(
"GalleryDir",
None)
5217 musicpath = defaultsettings.get(
"MusicLocation",
None)
5218 videomode = defaultsettings[
"MythArchiveVideoFormat"].lower()
5219 temppath = os.path.join(defaultsettings[
"MythArchiveTempDir"],
"work")
5220 logpath = os.path.join(defaultsettings[
"MythArchiveTempDir"],
"logs")
5221 write(
"temppath: " + temppath)
5222 write(
"logpath: " + logpath)
5223 dvddrivepath = defaultsettings[
"MythArchiveDVDLocation"]
5224 dbVersion = defaultsettings[
"DBSchemaVer"]
5225 preferredlang1 = defaultsettings[
"ISO639Language0"]
5226 preferredlang2 = defaultsettings[
"ISO639Language1"]
5227 useFIFO = (defaultsettings[
"MythArchiveUseFIFO"] ==
'1')
5228 alwaysRunMythtranscode = (defaultsettings[
"MythArchiveAlwaysUseMythTranscode"] ==
'1')
5229 copyremoteFiles = (defaultsettings[
"MythArchiveCopyRemoteFiles"] ==
'1')
5230 mainmenuAspectRatio = defaultsettings[
"MythArchiveMainMenuAR"]
5231 chaptermenuAspectRatio = defaultsettings[
"MythArchiveChapterMenuAR"]
5232 dateformat = defaultsettings.get(
"MythArchiveDateFormat",
"%a %d %b %Y")
5233 timeformat = defaultsettings.get(
"MythArchiveTimeFormat",
"%I:%M %p")
5234 drivespeed = int(defaultsettings.get(
"MythArchiveDriveSpeed",
"0"))
5235 if "MythArchiveClearArchiveTable" in defaultsettings:
5236 clearArchiveTable = (defaultsettings[
"MythArchiveClearArchiveTable"] ==
'1')
5237 nicelevel = defaultsettings.get(
"JobQueueCPU",
"0")
5240 path_mplex = [defaultsettings[
"MythArchiveMplexCmd"], os.path.split(defaultsettings[
"MythArchiveMplexCmd"])[1]]
5241 path_dvdauthor = [defaultsettings[
"MythArchiveDvdauthorCmd"], os.path.split(defaultsettings[
"MythArchiveDvdauthorCmd"])[1]]
5242 path_mkisofs = [defaultsettings[
"MythArchiveMkisofsCmd"], os.path.split(defaultsettings[
"MythArchiveMkisofsCmd"])[1]]
5243 path_growisofs = [defaultsettings[
"MythArchiveGrowisofsCmd"], os.path.split(defaultsettings[
"MythArchiveGrowisofsCmd"])[1]]
5244 path_M2VRequantiser = [defaultsettings[
"MythArchiveM2VRequantiserCmd"], os.path.split(defaultsettings[
"MythArchiveM2VRequantiserCmd"])[1]]
5245 path_jpeg2yuv = [defaultsettings[
"MythArchiveJpeg2yuvCmd"], os.path.split(defaultsettings[
"MythArchiveJpeg2yuvCmd"])[1]]
5246 path_spumux = [defaultsettings[
"MythArchiveSpumuxCmd"], os.path.split(defaultsettings[
"MythArchiveSpumuxCmd"])[1]]
5247 path_mpeg2enc = [defaultsettings[
"MythArchiveMpeg2encCmd"], os.path.split(defaultsettings[
"MythArchiveMpeg2encCmd"])[1]]
5249 path_projectx = [defaultsettings[
"MythArchiveProjectXCmd"], os.path.split(defaultsettings[
"MythArchiveProjectXCmd"])[1]]
5250 useprojectx = (defaultsettings[
"MythArchiveUseProjectX"] ==
'1')
5251 addSubtitles = (defaultsettings[
"MythArchiveAddSubtitles"] ==
'1')
5254 if path_projectx[0] ==
"":
5257 if nicelevel ==
'1':
5259 elif nicelevel ==
'2':
5264 nicelevel = os.nice(nicelevel)
5265 write(
"Setting process priority to %s" % nicelevel)
5270 write(
"Cannot change ionice level")
5272 write(
"Setting ionice level to idle")
5273 p = psutil.Process(os.getpid())
5274 p.ionice(psutil.IOPRIO_CLASS_IDLE)
5281 lckpath = os.path.join(logpath,
"mythburn.lck")
5283 fd = os.open(lckpath, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
5285 os.write(fd, b
"%d\n" % os.getpid())
5290 except OSError
as e:
5291 if e.errno == errno.EEXIST:
5292 write(
"Lock file exists -- already running???")
5300 jobDOM = xml.dom.minidom.parse(jobfile)
5303 if jobDOM.documentElement.tagName !=
"mythburn":
5308 jobs=jobDOM.getElementsByTagName(
"job")
5311 write(
"Processing Mythburn job number %s." % jobcount)
5314 options = job.getElementsByTagName(
"options")
5315 if options.length > 0:
5323 if clearArchiveTable ==
True:
5326 saveSetting(
"MythArchiveLastRunStatus",
"Success")
5327 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5328 write(
"Finished processing jobs!!!")
5334 os.system(
"chmod -R a+rw-x+X %s" % defaultsettings[
"MythArchiveTempDir"])
5339 traceback.print_exc(file=sys.stdout)
5340 if progresslog !=
"":
5341 traceback.print_exc(file=progressfile)
5344 saveSetting(
"MythArchiveLastRunEnd", time.strftime(
"%Y-%m-%d %H:%M:%S "))
5346 if __name__ ==
"__main__":
5349 os.putenv(
"LC_ALL", oldlocale)