[Cvs-annodex] commit (annodex): keystroke/trunk/keystroke.py
keystroke/trunk/scriptview.py keystroke/trunk/textsrc.py
scott
nobody at lists.annodex.net
Wed Nov 15 08:43:01 UTC 2006
Update of /var/local/lib/svn/annodex (new revision 2547)
Modified files:
keystroke/trunk/keystroke.py
keystroke/trunk/scriptview.py
keystroke/trunk/textsrc.py
Log Message:
Fixed transcription. The transition from reviewing to transcribing is nearly seamless. What is still need is a way to change the 'active' clip according to the media playing.
Modified: keystroke/trunk/keystroke.py
===================================================================
--- keystroke/trunk/keystroke.py 2006-11-14 10:20:46 UTC (rev 2546)
+++ keystroke/trunk/keystroke.py 2006-11-15 08:42:58 UTC (rev 2547)
@@ -46,6 +46,7 @@
import gst
import mimetypes
import sys
+import locale
#Import custom element
import gobject
@@ -61,6 +62,75 @@
MODE_REVIEW = 0
MODE_TRANSCRIBE = 1
+ INSTRUCTIONS = """Welcome to Keystroke.
+
+Everything in Keystroke is run through a keystroke or
+hotkey, if you will. This method of control is ideal
+for the transcription of media because it allows for
+easy control of the media while never taking your
+fingers off of the keys. To get you started here is
+a list of all the keystrokes.
+
+Additionally, you will need to know two formats for
+differing between dialog and chapter 'tracks'. These
+formats will allow for the simultaneous chapter and
+dialog inputting. For dialog it allows a speaker to
+be defined.
+
+WARNING: This text will disappear upon import or open.
+
+Keystroke - Action:
+ctrl-o - Launches a file select to open a media file.
+ctrl-i - Launches a file select to open previous data.
+ctrl-s - Launches a file select to save the data.
+ NOTE: You can select an output type via the file type.
+enter - Pauses/plays media and submits new text on pause->play.
+ctrl-r - Seeks back to the current clip start time.
+ctrl-t - Switches the current track playing over the video.
+ctrl-b - Seeks to the previous clip in the current track.
+ctrl-n - Seeks to the next clip in the current track.
+
+Input formats:
+ NOTE: Replace everything inbetween <> inclusive.
+ 1) ') <chapter name>' Ex: ') Creative Commons'
+ 2) '<speaker>: <dialog>' Ex: 'Scott:Whee!'
+ 3) Neither, inherited from last defined.
+
+Bugs and Oddities:
+ To continue transcribing after reviewing pause after
+ the last clip to set the new start point. Things will
+ inherit from last entry.
+
+Credits:
+ Scott Shawcroft - Author - scotts4 at u.washington.edu
+ Jason Kivlighn - Roommate
+
+License:
+This program allows annotating without taking your fingers off of the keyboard.
+Copyright (C) 2006 Scott Shawcroft
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor
+Boston, MA 02110-1301, USA.
+
+This program will allow annotating without taking your fingers
+off of the keyboard. It will automatically store start and stop
+times along with the text.
+"""
+
+ TITLE = "Keystroke - Martini Alpha"
+
#Below are all of our callbacks.
def delete_event(self,widget,event,data=None):
# Closes the window smoothly.
@@ -94,6 +164,7 @@
self.pipeline.set_state(gst.STATE_PAUSED);
self.pipeline_duration = 1000
self.push_text()
+ self.scriptview.clear()
self.mode = self.MODE_TRANSCRIBE
dialog.destroy()
@@ -123,6 +194,7 @@
self.progress.props.text = "Importing " + filename
self.start_time.set_text("xx:xx:xx.xxx")
self.end_time.set_text("xx:xx:xx.xxx")
+ self.scriptview.clear()
if format.get_name() == "CMML":
self.import_cmml(filename)
elif format.get_name() == "SMIL":
@@ -182,11 +254,15 @@
if previous:
self.seek(previous.get_start())
self.scriptview.highlight(previous)
+
self.mode = self.MODE_REVIEW
self.start_time.set_text(format_time(previous.get_start()))
self.end_time.set_text(format_time(previous.get_end()))
- self.clip_text.set_text(previous.get_text())
+ if previous.get_text()!=None:
+ self.clip_text.set_text(previous.get_text())
+ else:
+ self.clip_text.set_text("")
self.progress.props.fraction = float(previous.get_start())/self.pipeline_duration
else:
print "No previous clips in the current track."
@@ -250,11 +326,15 @@
# Update all fields.
elif self.mode==self.MODE_REVIEW:
current = self.scriptview.current_clip(current_time)
- if current!=-2:
+ if current!=-2 and current!=None:
self.scriptview.highlight(current)
self.start_time.set_text(format_time(current.get_start()))
self.end_time.set_text(format_time(current.get_end()))
self.clip_text.set_text(current.get_text())
+ else:
+ self.mode=self.MODE_TRANSCRIBE
+ self.start_time.set_text(format_time(current_time))
+ self.clip_text.set_text("")
# Update progress bar.
self.progress.props.text = self.current_file + ": Paused."
@@ -268,12 +348,16 @@
# If transcribing.
if self.mode==self.MODE_TRANSCRIBE:
text = self.clip_text.get_text()
- if text[:1] == ")" or (text.find(":")==-1 and text != "") and self.start_time.get_text() != 'xx:xx:xx.xxx':
- print "Chapter.";
- self.scriptview.append(clip.clip(to_ms(self.start_time.get_text()),to_ms(self.end_time.get_text()),text.strip().strip(")"),track="default"))
- elif text != "" and self.start_time.get_text() != 'xx:xx:xx.xxx':
- # If using the last type def make sure doesn't have ';' instead of intended ':'
- if text.find(":")==-1 and text.find(";")!=-1:
+ if text!='':
+ # Check if entry is chapter.
+ if text[:1] == ")":
+ track = 'default'
+ text = text[1:]
+ else:
+ track = None
+
+ # Check for possible mistype of ; in place of :
+ if track==None and text.find(":")==-1 and text.find(";")!=-1:
dialog = gtk.Dialog("Did you mean...", self.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_NO, gtk.RESPONSE_NO, gtk.STOCK_YES, gtk.RESPONSE_YES))
label = gtk.Label("It looks like you may have intended to have a new speaker but mistakenly typed a semi-colon (;) instead of a colon (:). Would you like to change the semi-colon to a colon in, '"+text+"'?")
label.set_line_wrap(True)
@@ -282,16 +366,19 @@
label.show()
if dialog.run() == gtk.RESPONSE_YES:
text = text.replace(";", ":", 1)
- dialog.destroy()
+ dialog.destroy()
+
+ # Check if entry is dialog.
if text.find(":")!=-1:
- speaker = text[:text.find(":")+1]
+ speaker = text[:text.find(":")]
+ text = text[text.find(":")+1:]
+ loc = locale.getlocale(locale.LC_ALL)[0]
+ if loc==None: loc="en_US"
+ track = "subtitle-" + loc
else:
- speaker = None
- print "Dialog"
- self.scriptview.append(clip.clip(to_ms(self.start_time.get_text()),to_ms(self.end_time.get_text()),text[text.find(":")+1:],speaker=speaker))
- elif text != "":
- self.scriptview.append(clip.clip(to_ms(self.start_time.get_text()),to_ms(self.end_time.get_text()),text.strip()))
- self.clip_text.set_text("")
+ speaker = ""
+ self.scriptview.append(clip.clip(to_ms(self.start_time.get_text()),to_ms(self.end_time.get_text()),text.strip(),track,speaker))
+ self.clip_text.set_text("")
self.start_time.set_text(format_time(self.pipeline.query_position(gst.FORMAT_TIME)[0]/gst.MSECOND))
self.end_time.set_text("xx:xx:xx.xxx")
self.scriptview.scroll_to_bottom()
@@ -343,9 +430,9 @@
# generate header.
cmml_file = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n\n<cmml>\n\n'
if (self.current_file.find('/') != -1):
- stream_id = self.current_file.rsplit("/")[1].rsplit(".")[0]
+ stream_id = self.current_file.rsplit("/",1)[1].rsplit(".",1)[0]
else:
- stream_id = self.current_file.rsplit(".")[0]
+ stream_id = self.current_file.rsplit(".",1)[0]
stream_type = mimetypes.guess_type(self.current_file)[0]
cmml_file += '<stream id="%s" timebase="npt:0">\n\t<import contenttype="%s" src="%s" start="npt:0">\n\t</import>\n</stream>\n\n' % (stream_id,stream_type,self.current_file)
# Add each clip.
@@ -356,7 +443,7 @@
cmml_file += '<clip id="%s" title="%s" start="%s" end="%s" track="%s">\n' % (x,clip.get_speaker().capitalize(),format_time(clip.get_start()),format_time(clip.get_end()),clip.get_track())
else:
cmml_file += '<clip id="%s" start="%s" end="%s">\n' % (x,format_time(clip.get_start()),format_time(clip.get_end()))
- cmml_file += '\t<desc>%s</desc>\n' % (clip[2].strip())
+ cmml_file += '\t<desc>%s</desc>\n' % (clip.get_text())
cmml_file += '</clip>\n\n'
x += 1
cmml_file += '</cmml>'
@@ -443,12 +530,12 @@
return True
#Below are functions generally called once.
- def __init__(self):
+ def __init__(self):
# Setup the program. The gui and gstreamer pipeline.
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
- self.window.set_title("Keystroke - Martini Alpha")
+ self.window.set_title(self.TITLE)
self.window.set_default_size(500,300)
self.vbox = gtk.VBox()
@@ -469,7 +556,7 @@
self.sw = gtk.ScrolledWindow()
self.sw.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC)
self.sw.set_shadow_type(gtk.SHADOW_IN)
- self.scriptview = ScriptView()
+ self.scriptview = ScriptView(self.INSTRUCTIONS)
self.sw.add(self.scriptview)
self.hbox = gtk.HBox()
Modified: keystroke/trunk/scriptview.py
===================================================================
--- keystroke/trunk/scriptview.py 2006-11-14 10:20:46 UTC (rev 2546)
+++ keystroke/trunk/scriptview.py 2006-11-15 08:42:58 UTC (rev 2547)
@@ -29,9 +29,11 @@
"""This class handles both a gtk.textBuffer and a gtk.textView. It wraps all
data storage and display functions of clip information."""
- def __init__(self):
+ def __init__(self,instructions):
""" This constructor returns the textview to be packed into the window."""
self.__text = gtk.TextBuffer()
+
+ self.__text.props.text = instructions
gtk.TextView.__init__(self)
self.__tag_clip = self.__text.create_tag("clip",
underline=pango.UNDERLINE_SINGLE)
@@ -46,9 +48,9 @@
self.__last_track = "subtitle-en"
self.__last_speaker = None
self.__current_track = "default"
- self.__visible_marks = True
+ self.__visible_marks = False
self.__ended_previous = True
-
+
def append(self, clip):
"""This adds text at the end of the buffer."""
if not clip.get_track():
@@ -105,12 +107,17 @@
last_clip = current_clip
else:
break
+ if last_clip != None and time>last_clip.get_end():
+ return None
+
if last_clip != None:
return last_clip
- elif self.__tracks[self.__current_track].get_last_clip()!=last_clip and time>=current_clip.get_start():
+
+ if self.__tracks[self.__current_track].get_last_clip()!=last_clip and time<=current_clip.get_end():
return current_clip
- else:
- return -2
+
+ #Upon error.
+ return -2
def next(self,time):
"""This returns the beginning timestamp of the next clip after the current
@@ -125,20 +132,25 @@
"""This returns the beginning timestamp of the previous clip relative to the
given time. If the current clip is the first then return None."""
current = self.current_clip(time)
- return self.__tracks[self.__current_track].previous(current)
+ if current!=None and self.__tracks[self.__current_track].previous(current):
+ return self.__tracks[self.__current_track].previous(current)
+ elif current==None:
+ return self.__tracks[self.__current_track].get_last_clip()
+ return clip.clip(0,10,None)
def highlight(self,clip):
"""This highlights the text for the clip with the given start time. Also
note that it will remove any other highlights."""
self.__text.remove_tag(self.__tag_current, self.__text.get_start_iter(),self.__text.get_end_iter())
- mark = self.__text.get_mark(clip.get_track() + "-" + str(clip.get_start()))
- start_iter = self.__text.get_iter_at_mark(mark)
- if not start_iter.begins_tag(self.__tag_clip):
- start_iter.forward_to_tag_toggle(self.__tag_clip)
- end_iter = start_iter.copy()
- end_iter.forward_to_tag_toggle(self.__tag_clip)
- self.__text.apply_tag(self.__tag_current, start_iter, end_iter)
- self.scroll_to_mark(mark,0.1)
+ if clip.get_text()!=None and clip.get_text()!="":
+ mark = self.__text.get_mark(clip.get_track() + "-" + str(clip.get_start()))
+ start_iter = self.__text.get_iter_at_mark(mark)
+ if not start_iter.begins_tag(self.__tag_clip):
+ start_iter.forward_to_tag_toggle(self.__tag_clip)
+ end_iter = start_iter.copy()
+ end_iter.forward_to_tag_toggle(self.__tag_clip)
+ self.__text.apply_tag(self.__tag_current, start_iter, end_iter)
+ self.scroll_to_mark(mark,0.1)
def export_buffer(self, end="01:30:00.000"):
# Returns cliplist. This function now just updates the clip's text for clips in the cliplists.
Modified: keystroke/trunk/textsrc.py
===================================================================
--- keystroke/trunk/textsrc.py 2006-11-14 10:20:46 UTC (rev 2546)
+++ keystroke/trunk/textsrc.py 2006-11-15 08:42:58 UTC (rev 2547)
@@ -43,8 +43,8 @@
return True
def do_create(self, offset, length):
- if self.__cliplist and self.__cliplist.has_next():
- clip = self.__cliplist.next()
+ if self.__iter and self.__iter.has_next():
+ clip = self.__iter.next()
buf = gst.Buffer(clip.get_text())
buf.timestamp = clip.get_start()*gst.MSECOND
buf.duration = clip.get_duration()*gst.MSECOND
@@ -62,7 +62,7 @@
return gst.FLOW_OK, buf
def do_do_seek(self, segment):
- self.__cliplist.reset_iter()
+ self.__iter.reset_iter()
return True
def do_is_seekable(self):
@@ -72,4 +72,5 @@
return self.__cliplist
def set_cliplist(self,cliplist):
- self.__cliplist = cliplistiter(cliplist)
+ self.__iter = cliplistiter(cliplist)
+ self.__cliplist = cliplist
--
scott
More information about the cvs-annodex
mailing list