[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