Added:
/odp2wts/objects.py
/odp2wts/scriptParser.py
Modified:
/odp2wts/odp2wts.py
/wikitospeech/Wiki-to-Speech.py
/wikitospeech/scriptParser.py
=======================================
--- /dev/null
+++ /odp2wts/objects.py Mon Sep 26 00:58:04 2011
@@ -0,0 +1,42 @@
+class Sequence(object):
+ """Object containing a series of questions/statements"""
+ def __init__(self):
+ self.sequence = []
+ self.onQuestion = 0
+ self.questionTagMap = {}
+ self.rules = []
+
+class Question(object):
+ """Object containing a question/statement with optional answers"""
+ def __init__(self):
+ self.tag = ""
+ self.questionTexts = []
+ self.answers = []
+ self.language = ""
+ self.linkToShow = ""
+ self.pathToImageFiles= ""
+
+class Answer(object):
+ """Object containing an answer with optional response"""
+ def __init__(self):
+ self.answerText = ""
+ self.answerSideLink = ""
+ self.sticky = False
+ self.input = False
+ self.token = ""
+ self.responseText = ""
+ self.responseSideLink = ""
+ self.action = 0
+ self.visited = False
+ self.answerLanguage = ""
+ self.responseLanguage = ""
+
+class Rule(object):
+ """Object containing a rule"""
+ def __init__(self):
+ self.rulePattern = None
+ self.ruleType = ""
+ self.ruleName = ""
+ self.ruleResponse = ""
+
+
=======================================
--- /dev/null
+++ /odp2wts/scriptParser.py Mon Sep 26 00:58:04 2011
@@ -0,0 +1,306 @@
+#-------------------------------------------------------------------------------
+# Name: scriptParser.py
+# Purpose: extract Wiki-to-Speech sequence from script text
+#
+# Author: John Graves
+#
+# Created: 17 April 2011
+# Modified: 13 September 2011
+# Copyright: (c) John 2011
+# Licence: MIT license
+#-------------------------------------------------------------------------------
+from BeautifulSoup import BeautifulSoup
+import htmlentitydefs
+import objects
+import os
+import re
+import subprocess
+import sys
+import urllib
+from time import gmtime, strftime
+
+def unescape(text):
+ def fixup(m):
+ text = m.group(0)
+ if text[:2] == "&#":
+ # character reference
+ try:
+ if text[:3] == "&#x":
+ return unichr(int(text[3:-1], 16))
+ else:
+ return unichr(int(text[2:-1]))
+ except ValueError:
+ pass
+ else:
+ # named entity
+ try:
+ text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
+ except KeyError:
+ pass
+ return text # leave as is
+ return re.sub("&#?\w+;", fixup, text)
+
+def parseScript(name):
+ if name.startswith("http"):
+ if name.find("etherpad")>0:
+ sequence = parseEtherpad(name)
+ else:
+ sequence = parseHtml(name)
+ else:
+ if name.endswith(".txt"):
+ sequence = parseTxtFile(name)
+ else:
+ sequence = None
+## # No parsing of .html
+## # Set up dummy sequence
+## seq = objects.Sequence()
+## seq.sequence = []
+## question = objects.Question()
+## question.questionTexts = []
+## question.questionTexts.append("Opening "+name)
+## question.linkToShow = name
+## seq.sequence.append(question)
+## sequence = seq.sequence
+## dumpSequence(seq, False)
+ return sequence
+
+def parseEtherpad(name):
+ # download Etherpad and extract script
+ # http://ietherpad.com/mieeiphS5# J
+ try:
+ proxy = os.environ["HTTP_PROXY"]
+ except:
+ proxy = ''
+ if proxy=="http://cache.aut.ac.nz:3128":
+ proxies = {'http': 'http://cache.aut.ac.nz:3128'}
+ urlOpen = urllib.urlopen( name , proxies=proxies )
+ else:
+ urlOpen = urllib.urlopen( name, proxies={} )
+ soup = BeautifulSoup(urlOpen.read())
+ postbody = soup.find("div", { "class" : "postbody" })
+ soupString = ""
+ try:
+ soupString = str(soup)
+ except UnicodeDecodeError:
+ # no luck here, give up
+ return None
+ if len(soupString) > 0:
+ cleanUnicodeTextStr = \
+ soupString[
soupString.find(u'"initialAttributedText":{"text"')+33 : \
+ soupString.find(u',"attribs":')-1 ]
+ text = unescape(cleanUnicodeTextStr).split('\\n')
+ else:
+ return None
+ sequence = parseText(text)
+ return sequence
+
+def parseHtml(name):
+ # download and extract script from wiki page, for example:
+ # http://dl.dropbox.com/u/12838403/dropbox.txt
+ try:
+ proxy = os.environ["HTTP_PROXY"]
+ except:
+ proxy = ''
+ if proxy=="http://cache.aut.ac.nz:3128":
+ proxies = {'http': 'http://cache.aut.ac.nz:3128'}
+ urlOpen = urllib.urlopen( name , proxies=proxies )
+ else:
+ urlOpen = urllib.urlopen( name, proxies={} )
+ if name.endswith(".txt"):
+ urlText = urlOpen.read().split("\n")
+ else:
+ # extract text marked with <pre> from wiki or blog page
+ soup = BeautifulSoup(urlOpen.read())
+ taggedPre = soup.pre
+ if taggedPre != None:
+ taggedPreStr = str(taggedPre).replace('<br />\n','\n')
+ taggedPreStr = taggedPreStr.replace('<br />','\n')
+ soup = BeautifulSoup(taggedPreStr)
+ urlText =
unescape(''.join(soup.pre.findAll(text=True))).splitlines()
+ else:
+ return None
+
+ f = open('debug.txt','w')
+ f.write("test run at " + strftime("%d %b %Y %H:%M", gmtime()) + "\n")
+ f.write(str(type(urlText))+ "\n")
+ f.write(str(len(urlText))+ "\n")
+ for l in urlText:
+ f.write(l.strip()+"\n")
+ f.close()
+
+ sequence = parseText(urlText)
+ return sequence
+
+def parseTxtFile(name):
+ # open txt file
+ try:
+ f = open(name)
+ except:
+ # No parsing of .txt
+ return None
+ text = f.readlines()
+
+# if not sys.platform.startswith("win"):
+# # find slide images in .txt file and make symbolic links if
possible
+# pngs = [item.strip() for item in text if item.endswith(".png\n")]
+# # script source directory
+# scriptDir, scriptFile = os.path.split(name)
+# savePath = os.getcwd()
+# os.chdir('static')
+# staticDir = os.listdir(".")
+# pngsInStatic = [file for file in staticDir if
file.endswith(".png")]
+# for png in pngs:
+# if png in pngsInStatic:
+# subprocess.Popen(["rm",png])
+# subprocess.Popen(["ln","-s",scriptDir+os.sep+png,png])
+# os.chdir(savePath)
+
+ sequence = parseText(text)
+ return sequence
+
+def parseText(text):
+ # guess at questionMode based on first line
+ if text[0].lower().endswith(".png") or text[0].startswith("[path="):
+ questionMode = False
+ else:
+ questionMode = True
+ seq = objects.Sequence()
+ seq.sequence = []
+ pathToImageFiles = ""
+ question = objects.Question()
+ answer = objects.Answer()
+ for line in text:
+ line = line.strip()
+ if not line.startswith("#"): # ignore comment lines
+ if (line.startswith("[") and not line.endswith(";")):
+ if len(question.questionTexts)>0:
+ seq.sequence.append(question)
+ question = objects.Question()
+ question.pathToImageFiles = pathToImageFiles
+ equalsAt = line.find("=")
+ if equalsAt>1: # set parameters
+ parameterName = line[1:equalsAt].strip().lower()
+ parameterValue =
line[equalsAt+1:line.find("]")].strip().lower()
+ if parameterName == "questions":
+ if parameterValue == "on":
+ questionMode = True
+ if parameterValue == "off":
+ questionMode = False
+ continue
+ elif parameterName == "path":
+ if(not parameterValue.endswith(os.sep)):
+ parameterValue += os.sep
+ pathToImageFiles = parameterValue
+ question.pathToImageFiles = pathToImageFiles
+ continue
+ else: # question tag
+ question.tag = line[1:line.find("]")]
+
+ else:
+ line = line.strip()
+ if questionMode == False:
+ # In default mode, expected arrangement of links and
text
+ # is
+ # LINK (ending in http/html/jpg)
+ # TEXT FOR VOICE OVER
+ # (optionally several lines long)
+ #
+ if len(line)>0:
+ if (line.startswith("http") or
+ line.endswith(".html") or
+ line.endswith(".jpg") or
+ line.endswith(".JPG") or
+ line.endswith(".png") or
+ line.endswith(".PNG")):
+ if len(question.questionTexts)>0:
+ seq.sequence.append(question)
+ question = objects.Question()
+ question.pathToImageFiles =
pathToImageFiles
+ question.linkToShow = line
+ else:
+ question.questionTexts.append(line)
+ else:
+ # questionMode == True
+ # In question mode, expected arrangement
+ # is
+ # (optional image to show)
+ # QUESTION
+ # (optionally several lines long)
+ # ANSWER ;[ACTION] [RESPONSE]
+ # (optionally repeated)
+ #
+ if len(line)>0:
+ if (line.endswith(".jpg") or
+ line.endswith(".JPG") or
+ line.endswith(".png") or
+ line.endswith(".PNG")):
+ if len(question.questionTexts)>0:
+ seq.sequence.append(question)
+ question = objects.Question()
+ question.pathToImageFiles =
pathToImageFiles
+ question.linkToShow = line
+ else:
+ semicolonAt = line.find(";")
+ if -1 == semicolonAt:
+ question.questionTexts.append(line)
+ else: # parse answer
+ answer.answerText =
line[0:semicolonAt].strip()
+ responseSide = line[semicolonAt+1:].strip()
+ if len(responseSide)>0:
+ while responseSide.startswith(";"):
+ answer.action += 1
+ responseSide =
responseSide[1:].strip()
+ if responseSide.startswith("["):
+ rightbracketAt =
responseSide.find("]")
+ answer.responseSideLink =
responseSide[1:rightbracketAt]
+ responseSide =
responseSide[rightbracketAt+1:].strip()
+ answer.responseText = responseSide
+ if answer.answerText == "[next]":
+ answer.action = 1
+ question.answers.append(answer)
+ answer = objects.Answer()
+
+ else: # blank line
+ if len(question.questionTexts)>0:
+ seq.sequence.append(question)
+ question = objects.Question()
+ question.pathToImageFiles = pathToImageFiles
+
+ if len(question.questionTexts)>0:
+ seq.sequence.append(question)
+
+ # second pass to match responseSideLinks to tags and adjust actions
+ tags = [ question.tag.lower() for question in seq.sequence ]
+ for qnum, question in enumerate( seq.sequence ):
+ for answer in question.answers:
+ if answer.responseSideLink != "":
+ if answer.responseSideLink.lower() in tags:
+ # remove link
+ answer.action = tags.index(answer.responseSideLink) -
qnum
+ answer.responseSideLink = ""
+
+ dumpSequence(seq, questionMode)
+
+ return seq.sequence
+
+def dumpSequence(seq, questionMode):
+ if True:
+ f = open('debug2.txt','w')
+ f.write("test run at " + strftime("%d %b %Y %H:%M", gmtime()))
+ f.write("\nquestionMode is "+ str(questionMode))
+ for i, q in enumerate(seq.sequence):
+ f.write("\nQuestion "+str(i)+"-"*30)
+ f.write("\n tag: "+q.tag)
+ f.write("\n linkToShow: "+q.linkToShow)
+ f.write("\n pathToImageFiles: "+q.pathToImageFiles)
+ for l in q.questionTexts:
+ f.write("\n questionText: "+l)
+ for j, a in enumerate(q.answers):
+ f.write("\n answerText"+str(j)+": "+a.answerText)
+ f.write("\n
responseSideLink"+str(j)+": "+a.responseSideLink)
+ f.write("\n responseText"+str(j)+": "+a.responseText)
+ f.write("\n action"+str(j)+": "+str(a.action))
+ f.close()
+
+if __name__ == "__main__":
+ parseTxtFile("script.txt")
=======================================
--- /odp2wts/odp2wts.py Thu Sep 15 22:30:54 2011
+++ /odp2wts/odp2wts.py Mon Sep 26 00:58:04 2011
@@ -19,8 +19,21 @@
20110913 Remove [] from script output and wrap ctypes import with win32
test
20110915 Added boilerplate script comments including version number
20110916 Read Unicode
+20110917 Write out bits of Question/Answer/Response
+
+img1.png > img1.htm > img1.mp3
+[questions=on]
+How many slides have we seen? > q/img1q1.htm > q/img1q1.mp3
+One ;; > q/img1q1a1.mp3
+Two ;; > q/img1q1a1.mp3
+
+What slide is next? > q/img1q2.htm > q/img1q2.mp3
+Third ;; > q/img1q2a1.mp3
+Fourth; No, just the third. > q/img1q2a2.mp3, > q/img1q2r2.mp3
+
+[questions=off]
"""
-__version__ = "0.1.21"
+__version__ = "0.1.22"
import BeautifulSoup
from BeautifulSoup import BeautifulStoneSoup
@@ -31,6 +44,7 @@
import os
import os.path
import shutil
+import scriptParser
import stat
import subprocess
import sys
@@ -307,17 +321,11 @@
os.chdir(savePath)
easygui.msgbox("Zipped script.txt and image files
to "+odpFileDirectory+os.sep+odpName+".zip")
-## Step 2 - Make and run convert.bat
-
-# Make convert.bat to convert questionText into audio files
-f = codecs.open(odpFileDirectory+os.sep+"convert.bat", encoding='utf-8',
mode='w+')
-os.chmod(odpFileDirectory+os.sep+"convert.bat",stat.S_IRWXU)
-onImg = minNum
-for item in noteText:
-
+## Step 2 - Sequence script and make and run convert.bat
+def convertItem(f,item,onImgStr):
if sys.platform.startswith("win"):
# For Windows
-
f.write('"'+savePath+os.sep+'sapi2wav.exe" '+imageFilePrefix+str(onImg)+'.wav
1 -t "')
+
f.write('"'+savePath+os.sep+'sapi2wav.exe" '+imageFilePrefix+onImgStr+'.wav
1 -t "')
lines = item.split("\n")
for linenum, line in enumerate(lines):
if not line.startswith("["):
@@ -327,14 +335,14 @@
elif linenum>0:
break
f.write('"\n')
- f.write('"'+savePath+os.sep+'lame.exe"
-h '+imageFilePrefix+str(onImg)+'.wav '+ '"' + \
-
odpFileSubdirectory+os.sep+imageFilePrefix+str(onImg)+'.mp3"\n')
-
f.write('"'+savePath+os.sep+'sox.exe" '+imageFilePrefix+str(onImg)+'.wav '+ '"'
+ \
-
odpFileSubdirectory+os.sep+imageFilePrefix+str(onImg)+'.ogg"\n')
- f.write('del '+imageFilePrefix+str(onImg)+'.wav\n')
+ f.write('"'+savePath+os.sep+'lame.exe"
-h '+imageFilePrefix+onImgStr+'.wav '+ '"' + \
+
odpFileSubdirectory+os.sep+imageFilePrefix+onImgStr+'.mp3"\n')
+
f.write('"'+savePath+os.sep+'sox.exe" '+imageFilePrefix+onImgStr+'.wav '+ '"'
+ \
+
odpFileSubdirectory+os.sep+imageFilePrefix+onImgStr+'.ogg"\n')
+ f.write('del '+imageFilePrefix+onImgStr+'.wav\n')
else:
# For Mac OSX
- f.write("/usr/bin/say -o "+imageFilePrefix+str(onImg)+'.aiff "')
+ f.write("/usr/bin/say -o "+imageFilePrefix+onImgStr+'.aiff "')
lines = item.split("\n")
for linenum, line in enumerate(lines):
line.replace('"',' ').replace('`',' ').replace(';',' ')
@@ -344,15 +352,362 @@
break
# f.write(item)
f.write('"\n')
- f.write("~/bin/sox "+imageFilePrefix+str(onImg)+'.aiff "'+
- odpFileSubdirectory+os.sep+imageFilePrefix+str(onImg)+'.ogg"\n')
- f.write("~/bin/sox "+imageFilePrefix+str(onImg)+'.aiff "'+
- odpFileSubdirectory+os.sep+imageFilePrefix+str(onImg)+'.mp3"\n')
- onImg += 1
-f.close()
-
+ f.write("~/bin/sox "+imageFilePrefix+onImgStr+'.aiff "'+
+ odpFileSubdirectory+os.sep+imageFilePrefix+onImgStr+'.ogg"\n')
+ f.write("~/bin/sox "+imageFilePrefix+onImgStr+'.aiff "'+
+ odpFileSubdirectory+os.sep+imageFilePrefix+onImgStr+'.mp3"\n')
+ f.write("rm "+imageFilePrefix+onImgStr+'.aiff\n')
+
+def writeHtmlHeader(htmlFile):
+ htmlFile.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN"' + "\n")
+ htmlFile.write('"http://www.w3.org/TR/html4/transitional.dtd">' + "\n")
+ htmlFile.write("<html>\n<head>\n")
+ htmlFile.write('<meta HTTP-EQUIV=CONTENT-TYPE CONTENT="text/html;
charset=utf-8">' + "\n")
+ htmlFile.write('<title>Wiki-to-Speech</title>\n')
+
+def writeHtmlHeader2(htmlFile):
+ htmlFile.write('</head>\n')
+ htmlFile.write('<body text="#000000" bgcolor="#FFFFFF" link="#000080"
vlink="#0000CC" alink="#000080">' + "\n")
+ htmlFile.write('<center>' + "\n")
+
+def writeHtmlFileNavigation(htmlFile, questionFileNames, maxNum,
position):
+ # First page and Back navigation
+ # First page
+ if position==0:
+ htmlFile.write("""First page Back """)
+ # Second page
+ elif position==1:
+ htmlFile.write("""<a href="../""" + odpName +""".htm">First
page</a> <a href="../""" +
+ odpName +""".htm">Back</a> """)
+ # Rest of pages
+ else:
+ htmlFile.write("""<a href="../""" + odpName +""".htm">First
page</a> <a href=""" + '"' +
+
questionFileNames[position-1]+""".htm">Back</a> """)
+
+ # Continue and Last Page navigation
+ # Last page
+ if position==maxNum:
+ htmlFile.write('Continue Last page<br>\n')
+ # First page
+ elif position==0:
+ htmlFile.write( \
+ '<a href="'+
+ odpName+"/"+questionFileNames[position+1]+
+ '.htm">Continue</a> ')
+ htmlFile.write( \
+ '<a href="'+
+ odpName+"/"+questionFileNames[-1]+
+ '.htm">Last page</a><br>\n')
+ # Rest of pages
+ else:
+ htmlFile.write( \
+ '<a href="'+
+ questionFileNames[position+1]+
+ '.htm">Continue</a> ')
+ htmlFile.write( \
+ '<a href="' +
+ questionFileNames[-1] +
+ '.htm">Last page</a><br>\n')
+
+def writeHtmlJavascript(htmlFile,
+ questionFileNames,
+ question,
+ position,
+ audioFileTimes):
+ """
+ <script language="javascript" type="text/javascript">
+ function respond0()
+ {
+ document.getElementById('a0').innerHTML = 'Third'
+ document.getElementById('a0').style.color = 'grey';
+ location.href = "img3.htm"
+ }
+ function respond1()
+ {
+ document.getElementById('a1').innerHTML = 'Fourth'
+ document.getElementById('a1').style.color = 'grey';
+ document.getElementById('playaudio').innerHTML = '<audio
controls autoplay><source src="img2q2r1.mp3" /><source src="img2q2r1.ogg"
/>Your browser does not support the <code>audio</code> element.</audio>'
+ var t=setTimeout("advance1()",2000);
+ }
+ function advance1() {
+ location.href = "img3.htm"
+ }
+
+ </script>
+ """
+ htmlFile.write('<script language="javascript"
type="text/javascript">\n')
+ for answerNum, answer in enumerate(question.answers):
+ if len(answer.answerText)>0:
+ htmlFile.write('function respond'+
+ str(answerNum)+
+ '()\n{\n')
+ htmlFile.write(' document.getElementById("a'+
+ str(answerNum)+'").innerHTML = "'+
+ answer.answerText+
+ '";\n')
+ htmlFile.write(' document.getElementById("a'+
+ str(answerNum)+
+ '").style.color = "grey";\n')
+
+ if len(answer.responseText)>0:
+ if position==0:
+ pathToAudio =
odpName+'/'+questionFileNames[position]+'r'+str(answerNum)
+ else:
+ pathToAudio =
questionFileNames[position]+'r'+str(answerNum)
+
+ htmlFile.write( \
+ " document.getElementById('playaudio').innerHTML=" +
+ "'<audio controls autoplay><source src=" +
+ '"' + pathToAudio +
+ '.mp3" />')
+ htmlFile.write('<source src="' +
+ pathToAudio +
+ '.ogg" />')
+ htmlFile.write( \
+ "Your browser does not support the <code>audio</code>
element.</audio>';\n")
+ if answer.action > 0:
+ htmlFile.write(' var t=setTimeout("advance'+
+ str(answerNum)+
+ '()",'+
+ str(audioFileTimes[pathToAudio]+1000)+
+ ');\n')
+ elif answer.action > 0:
+ htmlFile.write(" advance"+
+ str(answerNum)+
+ '();\n')
+ htmlFile.write('}\n')
+
+ if answer.action > 0:
+ htmlFile.write('function advance'+
+ str(answerNum)+
+ '()\n{\n')
+ htmlFile.write(' location.href="'+
+ questionFileNames[position+answer.action]+
+ '.htm";\n}\n')
+ htmlFile.write('</script>\n')
+
+
+def makeConvert(sequence):
+ # Make list of question file names for navigation
+ questionFileNames = []
+ onImg = minNum
+ onImgStr = str(onImg)
+ onQ = 0
+ for question in sequence:
+ if len(question.answers)==0:
+ questionFileNames.append(imageFilePrefix+onImgStr)
+ onImg += 1
+ onImgStr = str(onImg)
+ onQ = 0
+ else:
+ onQ += 1
+ questionFileNames.append(imageFilePrefix+onImgStr+"q"+str(onQ))
+ maxNum = len(questionFileNames)-1
+
+ # Make convert.bat to convert questionText into audio files
+ f = codecs.open(odpFileDirectory+os.sep+"convert.bat",
encoding='utf-8', mode='w+')
+ os.chmod(odpFileDirectory+os.sep+"convert.bat",stat.S_IRWXU)
+ onImg = minNum
+ onImgStr = str(onImg)
+ onQ = 0
+ for position, question in enumerate(sequence):
+
+ # write convert.bat
+ if len(question.answers)==0:
+ convertItem(f," ".join(question.questionTexts),onImgStr)
+ onImg += 1
+ onImgStr = str(onImg)
+ onQ = 0
+ else:
+ onQ += 1
+
convertItem(f," ".join(question.questionTexts),onImgStr+"q"+str(onQ))
+ onAns = 0
+ for answer in question.answers:
+
convertItem(f,answer.answerText,onImgStr+"q"+str(onQ)+"a"+str(onAns))
+ if len(answer.responseText)>0:
+
convertItem(f,answer.responseText,onImgStr+"q"+str(onQ)+"r"+str(onAns))
+ onAns += 1
+ f.close()
+
+def fetchAudioFileTimes():
+ os.chdir(odpFileSubdirectory)
+ dir = os.listdir(odpFileSubdirectory)
+ ogg = [file for file in dir if file.lower().endswith(".ogg")]
+ oggDict = {}
+
+ for file in ogg:
+ # Parse out file name stem
+ (stem, audioFileSuffix) = file.split(".")
+ # soxi -D returns the duration in seconds of the audio file as a
float
+ if sys.platform.startswith("win"):
+ # Unfortunately, there is a requirement that soxi (with an
implict .exe)
+ # be the command to check audio file duration in Win32
+ # but soxi is the name of the unix version of this utility
+ # So we need to delete the (unix) file called soxi so the
command line call
+ # to soxi will run soxi.exe
+ if os.path.isfile(savePath+os.sep+"soxi"):
+ os.remove(savePath+os.sep+"soxi")
+ command =
[savePath+os.sep+"soxi","-D",odpFileSubdirectory+os.sep+file]
+ else:
+ if os.path.isfile(savePath+os.sep+"soxi"):
+ command =
[savePath+os.sep+"soxi","-D",odpFileSubdirectory+os.sep+file]
+ elif os.path.isfile(savePath+os.sep+"Contents/Resources/soxi"):
+ command =
[savePath+os.sep+"Contents/Resources/soxi","-D",odpFileSubdirectory+os.sep+file]
+ else:
+ command = ["soxi","-D",odpFileSubdirectory+os.sep+file]
+ process = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
+ output = process.communicate()
+ retcode = process.poll()
+ if retcode:
+ print "No time available"
+ oggDict[stem]=int(float(output[0].strip())*1000)
+ return oggDict
+
+def writeHtml(sequence, audioFileTimes):
+
+ # Make list of question file names for navigation
+ questionFileNames = []
+ onImg = minNum
+ onImgStr = str(onImg)
+ onQ = 0
+ for question in sequence:
+ if len(question.answers)==0:
+ questionFileNames.append(imageFilePrefix+onImgStr)
+ onImg += 1
+ onImgStr = str(onImg)
+ onQ = 0
+ else:
+ onQ += 1
+ questionFileNames.append(imageFilePrefix+onImgStr+"q"+str(onQ))
+ maxNum = len(questionFileNames)-1
+
+ onImg = minNum
+ onImgStr = str(onImg)
+ onQ = 0
+ for position, question in enumerate(sequence):
+
+ if position==0:
+ # Create first .htm file in same directory as odpFile
+ htmlFile = codecs.open(odpFileDirectory+os.sep+odpName+".htm",
encoding='utf-8', mode='w+')
+ else:
+ # Create subsequent .htm files in folder in same directory as
odpFile
+ htmlFile =
codecs.open(odpFileSubdirectory+os.sep+questionFileNames[position]+".htm",
encoding='utf-8', mode='w+')
+
+ writeHtmlHeader(htmlFile)
+
+ if len(question.answers)==0:
+ writeHtmlHeader2(htmlFile)
+ writeHtmlFileNavigation(htmlFile, questionFileNames, maxNum,
position)
+ else:
+ writeHtmlJavascript(htmlFile, questionFileNames, question,
position,
+ audioFileTimes)
+ writeHtmlHeader2(htmlFile)
+ writeHtmlFileNavigation(htmlFile, questionFileNames, maxNum,
position)
+
+ if len(question.answers)==0:
+ # image src and link to next slide
+ # Last page which is not (also) the first page
+ if (position==maxNum and position>0):
+ # src but no link
+ htmlFile.write( \
+ '<img src="' +
+ questionFileNames[position] + '.' + imageFileSuffix +
+ '" style="border:0px"><br>\n')
+ # Last page which is also the first page
+ elif (position==maxNum and position==0):
+ # src but no link
+ htmlFile.write( \
+ '<img src="' +
+ odpName+"/"+questionFileNames[position] + '.' +
imageFileSuffix +
+ '" style="border:0px"><br>\n')
+ # First page
+ elif position==0:
+ htmlFile.write( \
+ '<a href="' +
+ odpName+"/"+questionFileNames[position+1] +
+ '.htm">')
+ htmlFile.write( \
+ '<img src="' +
+ odpName +"/" + questionFileNames[position] + '.' +
imageFileSuffix +
+ '" style="border:0px"></a><br>\n')
+ # Rest of pages
+ else:
+ htmlFile.write( \
+ '<a href="' +
+ questionFileNames[position+1] +
+ '.htm">')
+ htmlFile.write( \
+ '<img src="' +
+ questionFileNames[position] + '.' + imageFileSuffix +
+ '" style="border:0px"></a><br>\n')
+
+ else:
+ htmlFile.write("""<br><br><hr><br><center>
+<table width="400" style="text-align:left"><tbody>
+<tr><td>""")
+
htmlFile.write(" ".join(question.questionTexts)+ "</td></tr>\n" )
+
+ for answerNumber, answer in enumerate(question.answers):
+ if len(answer.answerText)>0:
+ htmlFile.write('<tr><td><div id="a'+
+ str(answerNumber)+
+ '"><a href="javascript:respond'+
+ str(answerNumber)+
+ '();">'+
+ answer.answerText +
+ '</a></div></td></tr>\n')
+ htmlFile.write("""</tbody>
+</table>
+</center><br><hr>""")
+
+ # include audio
+ # First page
+ if position==0:
+ pathToAudio = odpName+'/'+questionFileNames[position]
+ else:
+ pathToAudio = questionFileNames[position]
+ # For Safari
+ htmlFile.write( \
+ '<p id="playaudio">' +
+ '<audio controls autoplay><source src="' +
+ pathToAudio +
+ '.mp3" />')
+ # For Firefox
+ htmlFile.write( \
+ '<source src="' +
+ pathToAudio +
+ '.ogg" />\n')
+ # For others
+ htmlFile.write( \
+ 'Your browser does not support the <code>audio</code>
element.\n</audio>\n')
+ htmlFile.write( \
+ '</p>\n')
+ # For Internet Explorer
+ htmlFile.write( \
+ '<!--[if lte IE 8]>\n' +
+ '<script>\n' +
+ 'document.getElementById("playaudio").innerHTML=' + "'" +
+ '<embed src="' +
+ pathToAudio +
+ '.mp3" autostart="true">' + "'" + ';\n' +
+ '</script>\n' +
+ '<![endif]-->\n')
+
+ htmlFile.write('</center>' + "\n")
+ htmlFile.write('</body>\n</html>\n')
+ htmlFile.close()
+
+
+sequence =
scriptParser.parseTxtFile(odpFileSubdirectory+os.sep+"script.txt")
+makeConvert(sequence)
os.chdir(odpFileDirectory)
p =
subprocess.Popen('"'+odpFileDirectory+os.sep+'convert.bat"',shell=True).wait()
+audioFileTimes = fetchAudioFileTimes()
+writeHtml(sequence, audioFileTimes)
+
## Step 3 - create makeVid.bat
os.chdir(odpFileSubdirectory)
@@ -365,10 +720,14 @@
# Parse out just number (num) and imageFilePrefix
if stem.startswith("Slide"):
- oggDict[int(file[5:].split(".")[0])] = file
+ numberPart = file[5:].split(".")[0]
+ if numberPart.isdigit():
+ oggDict[int(numberPart)] = file
else:
# imgXX.ogg
- oggDict[int(file[3:].split(".")[0])] = file
+ numberPart = file[3:].split(".")[0]
+ if numberPart.isdigit():
+ oggDict[int(file[3:].split(".")[0])] = file
sortedOgg = oggDict.values()
times = []
for file in sortedOgg:
@@ -515,150 +874,6 @@
f.write('rm '+file+"\n")
f.close()
-## Step 4 - create HTML wrapper
-maxImgHtml = imageFilePrefix + str(maxNum) + '.htm'
-
-def writeHtmlHeader():
- htmlFile.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN"' + "\n")
- htmlFile.write('"http://www.w3.org/TR/html4/transitional.dtd">' + "\n")
- htmlFile.write("<html>\n<head>\n")
- htmlFile.write('<meta HTTP-EQUIV=CONTENT-TYPE CONTENT="text/html;
charset=utf-8">' + "\n")
- htmlFile.write('<title>Wiki-to-Speech</title>\n</head>\n')
- htmlFile.write('<body text="#000000" bgcolor="#FFFFFF" link="#000080"
vlink="#0000CC" alink="#000080">' + "\n")
- htmlFile.write('<center>' + "\n")
-
-for file in imageFileList:
-
- # Parse out file name stem (which includes number)
- stem = file.split(".")[0]
-
- # Parse out just number (num)
- if stem.startswith("Slide"):
- number = stem[5:]
- else:
- number = stem[3:]
- num = int(number)
-
- if num-minNum==0:
- # Create first .htm file in same directory as odpFile
- htmlFile = codecs.open(odpFileDirectory+os.sep+odpName+".htm",
encoding='utf-8', mode='w+')
- else:
- # Create subsequent .htm files in folder in same directory as
odpFile
- htmlFile = codecs.open(odpFileSubdirectory+os.sep+stem+".htm",
encoding='utf-8', mode='w+')
-
- writeHtmlHeader()
-
- # First page and Back navigation
- # First page
- if num-minNum==0:
- htmlFile.write("""First page Back """)
- # Second page
- elif num-minNum==1:
- htmlFile.write("""<a href="../""" + odpName +""".htm">First
page</a> <a href="../""" +
- odpName +""".htm">Back</a> """)
- # Rest of pages
- else:
- htmlFile.write("""<a href="../""" + odpName +""".htm">First
page</a> <a href=""" + '"' +
- imageFilePrefix + str(num-1)+""".htm">Back</a> """)
-
- # Continue and Last Page navigation
- # Last page
- if num==maxNum:
- htmlFile.write('Continue Last page<br>\n')
- # First page
- elif num-minNum==0:
- htmlFile.write( \
- '<a href="'+
- odpName+"/"+imageFilePrefix+str(num+1)+
- '.htm">Continue</a> ')
- htmlFile.write( \
- '<a href="'+
- odpName+"/"+maxImgHtml+
- '">Last page</a><br>\n')
- # Rest of pages
- else:
- htmlFile.write( \
- '<a href="'+
- imageFilePrefix + str(num+1) +
- '.htm">Continue</a> ')
- htmlFile.write( \
- '<a href="' +
- maxImgHtml +
- '">Last page</a><br>\n')
-
- # image src and link to next slide
- # Last page which is not (also) the first page
- if (num==maxNum and num-minNum>0):
- # src but no link
- htmlFile.write( \
- '<img src="' +
- file +
- '" style="border:0px"><br>\n')
- # Last page which is also the first page
- elif (num==maxNum and num-minNum==0):
- # src but no link
- htmlFile.write( \
- '<img src="' +
- odpName+"/"+file +
- '" style="border:0px"><br>\n')
- # First page
- elif num-minNum==0:
- htmlFile.write( \
- '<a href="' +
- odpName+"/"+imageFilePrefix+str(num+1) +
- '.htm">')
- htmlFile.write( \
- '<img src="' +
- odpName +"/" + file +
- '" style="border:0px"></a><br>\n')
- # Rest of pages
- else:
- htmlFile.write( \
- '<a href="' +
- imageFilePrefix+str(num+1) +
- '.htm">')
- htmlFile.write( \
- '<img src="' +
- file +
- '" style="border:0px"></a><br>\n')
-
- # include audio
- # First page
- if num-minNum==0:
- pathToAudio = odpName+'/'+stem
- else:
- pathToAudio = stem
- # For Safari
- htmlFile.write( \
- '<p id="playaudio">' +
- '<audio controls autoplay><source src="' +
- pathToAudio +
- '.mp3" />')
- # For Firefox
- htmlFile.write( \
- '<source src="' +
- pathToAudio +
- '.ogg" />\n')
- # For others
- htmlFile.write( \
- 'Your browser does not support the <code>audio</code>
element.\n</audio>\n')
- htmlFile.write( \
- '</p>\n')
- # For Internet Explorer
- htmlFile.write( \
- '<!--[if lte IE 8]>\n' +
- '<script>\n' +
- 'document.getElementById("playaudio").innerHTML=' + "'" +
- '<embed src="' +
- pathToAudio +
- '.mp3" autostart="true">' + "'" + ';\n' +
- '</script>\n' +
- '<![endif]-->\n')
-
- htmlFile.write('</center>' + "\n")
- htmlFile.write('</body>\n</html>\n')
- htmlFile.close()
-
# Run the makeVid.bat file with %0 as the first parameter
os.chdir(odpFileSubdirectory)
if sys.platform.startswith("win"):
@@ -668,3 +883,5 @@
p =
subprocess.Popen([odpFileDirectory+os.sep+"makeVid.bat"],shell=True).wait()
p = subprocess.Popen('open "'+odpFileDirectory+os.sep+odpName+'.htm"',
shell=True).pid
os.chdir(savePath)
+
+
=======================================
--- /wikitospeech/Wiki-to-Speech.py Tue Sep 13 01:58:05 2011
+++ /wikitospeech/Wiki-to-Speech.py Mon Sep 26 00:58:04 2011
@@ -34,7 +34,7 @@
import sys
import voice
-__version__ = "0.1.19"
+__version__ = "0.1.21"
if not os.path.exists('static'):
os.makedirs('static')
=======================================
--- /wikitospeech/scriptParser.py Tue Sep 13 01:58:05 2011
+++ /wikitospeech/scriptParser.py Mon Sep 26 00:58:04 2011
@@ -147,9 +147,11 @@
scriptDir, scriptFile = os.path.split(name)
savePath = os.getcwd()
os.chdir('static')
+ staticDir = os.listdir(".")
+ pngsInStatic = [file for file in staticDir if
file.endswith(".png")]
for png in pngs:
- if os.path.isfile(png):
- subprocess.Popen(["rm",png],shell=True)
+ if png in pngsInStatic:
+ subprocess.Popen(["rm",png])
subprocess.Popen(["ln","-s",scriptDir+os.sep+png,png])
os.chdir(savePath)