summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO18
-rw-r--r--PKGBUILD27
-rw-r--r--pyvnc2swf-0.9.5-setup.diff1299
3 files changed, 1344 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 00000000000..dbebfd10325
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,18 @@
+pkgbase = pyvnc2swf
+ pkgdesc = A screen recording tool for swf and flv formats
+ pkgver = 0.9.5
+ pkgrel = 2
+ url = http://www.unixuser.org/~euske/vnc2swf/pyvnc2swf.html
+ arch = i686
+ arch = x86_64
+ license = GPL
+ depends = python2-pygame>=1.6
+ depends = x11vnc
+ optdepends = python2-pymedia>=1.3.5: MPEG encoding
+ source = http://www.unixuser.org/~euske/vnc2swf/pyvnc2swf-0.9.5.tar.gz
+ source = pyvnc2swf-0.9.5-setup.diff
+ md5sums = af9737400d605b16f7283b4d2615f207
+ md5sums = 3577219348e31ac99d746cb1ccf2269c
+
+pkgname = pyvnc2swf
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 00000000000..9de7ae0dbc5
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,27 @@
+# Maintainer: TDY <tdy@gmx.com>
+# Contributor: Giovanni Scafora <linuxmania@gmail.com>
+
+pkgname=pyvnc2swf
+pkgver=0.9.5
+pkgrel=2
+pkgdesc="A screen recording tool for swf and flv formats"
+arch=('i686' 'x86_64')
+url="http://www.unixuser.org/~euske/vnc2swf/pyvnc2swf.html"
+license=('GPL')
+depends=('python2-pygame>=1.6' 'x11vnc')
+optdepends=('python2-pymedia>=1.3.5: MPEG encoding')
+source=(http://www.unixuser.org/~euske/vnc2swf/$pkgname-$pkgver.tar.gz
+ $pkgname-$pkgver-setup.diff)
+md5sums=('af9737400d605b16f7283b4d2615f207'
+ '3577219348e31ac99d746cb1ccf2269c')
+
+build() {
+ cd "$srcdir/$pkgname-$pkgver"
+ patch -Np1 -i ../$pkgname-$pkgver-setup.diff
+ python2 setup.py build
+}
+
+package() {
+ cd "$srcdir/$pkgname-$pkgver"
+ python2 setup.py install --prefix=/usr --root="$pkgdir"
+}
diff --git a/pyvnc2swf-0.9.5-setup.diff b/pyvnc2swf-0.9.5-setup.diff
new file mode 100644
index 00000000000..9d856c5100f
--- /dev/null
+++ b/pyvnc2swf-0.9.5-setup.diff
@@ -0,0 +1,1299 @@
+diff -Naur pyvnc2swf-0.9.5.old/setup.py pyvnc2swf-0.9.5/setup.py
+--- pyvnc2swf-0.9.5.old/setup.py 1969-12-31 18:00:00.000000000 -0600
++++ pyvnc2swf-0.9.5/setup.py 2008-12-18 06:10:12.000000000 -0600
+@@ -0,0 +1,21 @@
++#!/usr/bin/env python
++# -*- coding: ISO-8859-1 -*-
++
++from distutils.core import setup, Extension
++
++pkgs = ['pyvnc2swf']
++docs = ['docs/pyvnc2swf.html', 'docs/recordwin.html']
++data = [('share/doc/pyvnc2swf', docs)]
++bins = ['bin/recordwin', 'bin/pyvnc2swf', 'bin/pyvnc2swf-edit', 'bin/pyvnc2swf-play']
++
++setup(
++ name = 'pyvnc2swf',
++ version = '0.9.5',
++ author = 'Yusuke Shinyama',
++ author_email = 'yusuke at cs dot nyu dot edu',
++ license = 'GPL',
++ url = 'http://www.unixuser.org/~euske/vnc2swf/pyvnc2swf.html',
++ packages = pkgs,
++ data_files = data,
++ scripts = bins
++)
+diff -Naur pyvnc2swf-0.9.5.old/bin/pyvnc2swf pyvnc2swf-0.9.5/bin/pyvnc2swf
+--- pyvnc2swf-0.9.5.old/bin/pyvnc2swf 1969-12-31 18:00:00.000000000 -0600
++++ pyvnc2swf-0.9.5/bin/pyvnc2swf 2008-12-18 06:07:48.000000000 -0600
+@@ -0,0 +1,611 @@
++#!/usr/bin/env python
++##
++## pyvnc2swf - vnc2swf.py
++##
++## $Id: vnc2swf.py,v 1.7 2008/11/16 02:39:40 euske Exp $
++##
++## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
++## All Rights Reserved.
++##
++## This 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 software 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 software; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++## USA.
++##
++
++import sys, os, os.path, time, socket, re
++import Tkinter, tkFileDialog, tkMessageBox, tempfile, shutil
++from tkSimpleDialog import Dialog
++from struct import pack, unpack
++import threading
++
++from pyvnc2swf.movie import SWFInfo
++from pyvnc2swf.output import StreamFactory
++from pyvnc2swf.rfb import RFBError, RFBNetworkClient, RFBFileParser, RFBNetworkClientForRecording, RFBStreamConverter
++stderr = sys.stderr
++
++
++## tkPasswordDialog
++##
++class tkPasswordDialog(Dialog):
++
++ def __init__(self, title, prompt, master=None):
++ if not master:
++ master = Tkinter._default_root
++ self.prompt = prompt
++ Dialog.__init__(self, master, title)
++ return
++
++ def destroy(self):
++ self.entry = None
++ Dialog.destroy(self)
++ return
++
++ def body(self, master):
++ w = Tkinter.Label(master, text=self.prompt, justify=Tkinter.LEFT)
++ w.grid(row=0, padx=5, sticky=Tkinter.W)
++ self.entry = Tkinter.Entry(master, name="entry", show="*")
++ self.entry.grid(row=1, padx=5, sticky=Tkinter.W+Tkinter.E)
++ return self.entry
++
++ def validate(self):
++ self.result = self.entry.get()
++ return 1
++
++
++## tkEntryDialog
++##
++class tkEntryDialog(Dialog):
++
++ def __init__(self, title, prompt, pattern=None, default=None, master=None):
++ if not master:
++ master = Tkinter._default_root
++ self.prompt = prompt
++ self.default = default
++ self.pattern = re.compile(pattern)
++ Dialog.__init__(self, master, title)
++ return
++
++ def destroy(self):
++ self.entry = None
++ Dialog.destroy(self)
++ return
++
++ def body(self, master):
++ w = Tkinter.Label(master, text=self.prompt, justify=Tkinter.LEFT)
++ w.grid(row=0, padx=5, sticky=Tkinter.W)
++ self.entry = Tkinter.Entry(master, name="entry")
++ self.entry.grid(row=1, padx=5, sticky=Tkinter.W+Tkinter.E)
++ if self.default:
++ self.entry.insert(0, self.default)
++ return self.entry
++
++ def validate(self):
++ self.result = self.entry.get()
++ if self.pattern and not self.pattern.match(self.result):
++ return 0
++ return 1
++
++
++## RFBNetworkClientWithTkMixin
++##
++class RFBNetworkClientWithTkMixin:
++
++ def tk_init(self, root):
++ self.root = root
++ self.doloop = True
++ return
++
++ def interrupt(self):
++ self.doloop = False
++ return
++
++ def loop(self):
++ self.doloop = True
++ while self.doloop:
++ self.root.update()
++ if not self.loop1(): break
++ self.finish_update()
++ return self
++
++ def getpass(self):
++ return tkPasswordDialog('Login',
++ 'Password for %s:%d' % (self.host, self.port),
++ self.root).result
++
++class RFBNetworkClientWithTk(RFBNetworkClientWithTkMixin, RFBNetworkClient): pass
++class RFBNetworkClientForRecordingWithTk(RFBNetworkClientWithTkMixin, RFBNetworkClientForRecording): pass
++
++
++## VNC2SWFWithTk
++##
++class VNC2SWFWithTk:
++
++ FILE_TYPES = [
++ ('Flash(v5)', 'swf5', 'Macromedia Flash Files', '.swf'), # 0
++ ('Flash(v7)', 'swf7', 'Macromedia Flash Files', '.swf'), # 1
++ ('FLV', 'flv', 'Macromedia Flash Video Files', '.flv'), # 3
++ ('MPEG', 'mpeg', 'MPEG Files', '.mpeg'), # 2
++ ('VNCRec', 'vnc', 'VNCRec Files', '.vnc'), # 4
++ ]
++
++ def __init__(self, tempdir, info,
++ outtype='swf5', host='localhost', port=5900,
++ preferred_encoding=(0,), subprocess=None, pwdfile=None,
++ debug=0):
++ self.tempdir = tempdir
++ self.moviefile = info.filename
++ self.info = info
++ self.debug = debug
++ self.preferred_encoding = preferred_encoding
++ self.subprocess = subprocess
++ self.pwdfile = pwdfile
++ self.outtype = outtype
++ self.host = host
++ self.port = port
++ self.recording = False
++ self.exit_immediately = False
++ self.root = Tkinter.Tk()
++ self.root.title('vnc2swf.py')
++ self.root.wm_protocol('WM_DELETE_WINDOW', self.file_exit)
++ self.toggle_button = Tkinter.Button(master=self.root)
++ self.toggle_button.pack(side=Tkinter.LEFT)
++ self.status_label = Tkinter.Label(master=self.root, justify=Tkinter.LEFT)
++ self.status_label.pack(side=Tkinter.LEFT)
++ self.setup_menubar()
++ self.file_new(True)
++ return
++
++ def frames(self):
++ return self.stream and self.stream.output_frames
++
++ # Set up the GUI components.
++ def setup_menubar(self):
++
++ def option_server():
++ x = tkEntryDialog('Server', 'Server? (host:port)', pattern='^([^:/]+(:\d+)?|)$',
++ default='%s:%d' % (self.host, self.port), master=self.root).result
++ if not x: return
++ m = re.match(r'^([^:/]*)(:(\d+))?', x)
++ if not m:
++ tkMessageBox.showerror('Invalid address: %s' % x)
++ return
++ (host, port) = (m.group(1) or 'localhost', int(m.group(3) or '5900'))
++ if host != self.host or port != self.port and self.file_new_ask():
++ (self.host, self.port) = (host, port)
++ self.file_new(True)
++ return
++
++ def option_framerate():
++ x = tkEntryDialog('Framerate', 'Framerate? (fps)', pattern='^([1-9][.0-9]+|)$',
++ default=self.info.framerate, master=self.root).result
++ if not x: return
++ framerate = float(x)
++ if framerate != self.info.framerate and self.file_new_ask():
++ self.info.framerate = framerate
++ self.file_new(True)
++ return
++
++ def option_clipping():
++ try:
++ s = self.info.get_clipping()
++ except ValueError:
++ s = ''
++ x = tkEntryDialog('Clipping', 'Clipping? (ex. 640x480+0+0)',
++ pattern='^(\d+x\d+\+\d+\+\d+|)$',
++ default=s, master=self.root).result
++ if not x: return
++ if x != s and self.file_new_ask():
++ self.info.set_clipping(x)
++ self.file_new(True)
++ return
++
++ record_type = Tkinter.StringVar(self.root)
++ record_type.set(self.outtype)
++ def option_type():
++ if record_type.get() != self.outtype and self.file_new_ask():
++ self.outtype = record_type.get()
++ self.file_new()
++ else:
++ record_type.set(self.outtype)
++ return
++
++ menubar = Tkinter.Menu(self.root)
++ self.file_menu = Tkinter.Menu(menubar, tearoff=0)
++ self.file_menu.add_command(label="New...", underline=0, command=self.file_new, accelerator='Alt-N')
++ self.file_menu.add_command(label="Save as...", underline=0, command=self.file_saveas, accelerator='Alt-S')
++ self.file_menu.add_separator()
++ self.file_menu.add_command(label="Exit", underline=1, command=self.file_exit)
++ self.option_menu = Tkinter.Menu(menubar, tearoff=0)
++ self.option_menu.add_command(label="Server...", underline=0, command=option_server)
++ self.option_menu.add_command(label="Clipping...", underline=0, command=option_clipping)
++ self.option_menu.add_command(label="Framerate...", underline=0, command=option_framerate)
++ type_submenu = Tkinter.Menu(self.option_menu, tearoff=0)
++ for (k,v,_,_) in self.FILE_TYPES:
++ type_submenu.add_radiobutton(label=k, value=v, variable=record_type, command=option_type)
++ self.option_menu.add_cascade(label="Type", underline=0, menu=type_submenu)
++ menubar.add_cascade(label="File", underline=0, menu=self.file_menu)
++ menubar.add_cascade(label="Option", underline=0, menu=self.option_menu)
++ self.root.config(menu=menubar)
++ self.root.bind('<Alt-n>', lambda e: self.file_new())
++ self.root.bind('<Alt-s>', lambda e: self.file_saveas())
++ return
++
++ # Change the current status of UI.
++ def set_status(self):
++
++ def enable_menus(state):
++ self.file_menu.entryconfig(0, state=state) # "File->New..."
++ self.option_menu.entryconfig(0, state=state) # "Option->Server..."
++ self.option_menu.entryconfig(1, state=state) # "Option->Clipping..."
++ self.option_menu.entryconfig(2, state=state) # "Option->Framerate..."
++ self.option_menu.entryconfig(3, state=state) # "Option->Type"
++ return
++
++ # "File->Save As..."
++ if not self.recording and self.frames():
++ self.file_menu.entryconfig(1, state='normal')
++ else:
++ self.file_menu.entryconfig(1, state='disabled')
++
++ s = []
++ if not self.recording:
++ s.append('Ready (%d frames recorded).' % (self.frames() or 0))
++ self.toggle_button.config(text='Start', underline=0)
++ self.toggle_button.config(background='#80ff80', activebackground='#00ff00')
++ self.toggle_button.config(command=self.record)
++ self.root.bind('<s>', lambda e: self.record())
++ self.root.bind('<space>', lambda e: self.record())
++ enable_menus('normal')
++ else:
++ s.append('Recording.')
++ self.toggle_button.config(text='Stop', underline=0)
++ self.toggle_button.config(background='#ff8080', activebackground='#ff0000')
++ self.toggle_button.config(command=self.client.interrupt)
++ self.root.bind('<s>', lambda e: self.client.interrupt())
++ self.root.bind('<space>', lambda e: self.client.interrupt())
++ enable_menus('disabled')
++ if self.host != 'localhost' or self.port != 5900:
++ s.append('Server: %s:%d' % (self.host, self.port))
++ if self.info.clipping:
++ s.append('Clipping: %s' % self.info.get_clipping())
++ if self.info.framerate:
++ s.append('Framerate: %s' % self.info.framerate)
++ self.status_label.config(text='\n'.join(s))
++ return
++
++ # File->New
++ def file_new_ask(self):
++ if self.frames():
++ if not tkMessageBox.askokcancel('New file', 'Discard the current session?'):
++ return False
++ return True
++
++ def file_new(self, force=False):
++ if self.recording or (not force and not self.file_new_ask()): return
++ ext = dict([ (t,ext) for (_,t,desc,ext) in self.FILE_TYPES ])[self.outtype]
++ if self.moviefile:
++ moviefile = self.moviefile
++ else:
++ moviefile = os.path.join(self.tempdir, 'pyvnc2swf-%d%s' % (os.getpid(), ext))
++ self.info.filename = moviefile
++ self.fp = None
++ if self.outtype == 'vnc':
++ self.fp = file(self.info.filename, 'wb')
++ self.client = RFBNetworkClientForRecordingWithTk(
++ self.host, self.port, self.fp, pwdfile=self.pwdfile,
++ preferred_encoding=self.preferred_encoding)
++ self.stream = None
++ else:
++ self.stream = StreamFactory(self.outtype)(self.info)
++ self.client = RFBNetworkClientWithTk(
++ self.host, self.port, RFBStreamConverter(self.info, self.stream),
++ pwdfile=self.pwdfile,
++ preferred_encoding=self.preferred_encoding)
++ self.set_status()
++ return True
++
++ # File->SaveAs
++ def file_saveas(self):
++ if self.recording or not self.frames(): return
++ (ext,desc) = dict([ (t,(ext,desc)) for (_,t,desc,ext) in self.FILE_TYPES ])[self.outtype]
++ filename = tkFileDialog.asksaveasfilename(
++ master=self.root, title='Vnc2swf Save As', defaultextension=ext,
++ filetypes=[(desc,'*'+ext), ("All Files", "*")]
++ )
++ if not filename: return
++ if self.stream:
++ # Finish the movie.
++ self.stream.close()
++ self.stream = None
++ if self.fp:
++ self.fp.close()
++ self.fp = None
++ shutil.move(self.info.filename, filename)
++ self.info.write_html(filename=filename)
++ self.set_status()
++ return
++
++ # File->Exit
++ def file_exit(self):
++ if self.recording:
++ self.client.interrupt()
++ self.exit_immediately = True
++ else:
++ if self.frames():
++ if not tkMessageBox.askokcancel('Exit', 'Discard the current session?'):
++ return
++ self.root.destroy()
++ return
++
++ # Do recording.
++ def record(self):
++ self.client.tk_init(self.root)
++ try:
++ self.client.init().auth().start()
++ except socket.error, e:
++ return self.error('Socket error', e)
++ except RFBError, e:
++ return self.error('RFB protocol error', e)
++ if self.debug:
++ print >>stderr, 'start recording'
++ self.recording = True
++ self.set_status()
++ if self.subprocess:
++ self.subprocess.start()
++ try:
++ self.client.loop()
++ except socket.error, e:
++ return self.error('Socket error', e)
++ except RFBError, e:
++ return self.error('RFB protocol error', e)
++ if self.debug:
++ print >>stderr, 'stop recording'
++ if self.subprocess:
++ self.subprocess.stop()
++ self.client.close()
++ self.recording = False
++ self.set_status()
++ if self.exit_immediately:
++ self.file_exit()
++ return
++
++ # Displays an error message.
++ def error(self, msg, arg):
++ print >>stderr, arg
++ tkMessageBox.showerror('vnc2swf: %s' % msg, str(arg))
++ return
++
++ # Runs Tk mainloop.
++ def run(self):
++ self.root.mainloop()
++ return
++
++
++## vnc2swf - CLI routine
++##
++def vnc2swf(info, outtype='swf5', host='localhost', port=5900,
++ preferred_encoding=(0,), subprocess=None, pwdfile=None, vncfile=None,
++ debug=0, merge=False):
++ fp = None
++ if outtype == 'vnc':
++ if info.filename == '-':
++ fp = sys.stdout
++ else:
++ fp = file(info.filename, 'wb')
++ client = RFBNetworkClientForRecording(host, port, fp, pwdfile=pwdfile,
++ preferred_encoding=preferred_encoding, debug=debug)
++ else:
++ stream = StreamFactory(outtype)(info, debug=debug)
++ converter = RFBStreamConverter(info, stream, debug=debug)
++ if vncfile:
++ client = RFBFileParser(vncfile, converter, debug=debug)
++ else:
++ client = RFBNetworkClient(host, port, converter, pwdfile=pwdfile,
++ preferred_encoding=preferred_encoding, debug=debug)
++ try:
++ client.init().auth().start()
++ except socket.error, e:
++ print >>stderr, 'Socket error:', e
++ except RFBError, e:
++ print >>stderr, 'RFB error:', e
++ if debug:
++ print >>stderr, 'start recording'
++ if subprocess:
++ subprocess.start()
++ try:
++ client.loop()
++ except KeyboardInterrupt:
++ pass
++ except socket.error, e:
++ print >>stderr, 'Socket error:', e
++ except RFBError, e:
++ print >>stderr, 'RFB error:', e
++ if debug:
++ print >>stderr, 'stop recording'
++ if subprocess:
++ subprocess.stop()
++ client.close()
++ stream.close()
++ info.write_html()
++ if fp:
++ fp.close()
++ # Contributed by David Fraser
++ if merge:
++ tmpfile = os.tempnam(os.path.dirname(info.filename), "vncmerge-") + os.path.basename(info.filename)
++ print >>stderr, "renaming %s to %s for merge" % (info.filename, tmpfile)
++ if os.path.exists(tmpfile):
++ os.remove(tmpfile)
++ os.rename( info.filename, tmpfile )
++ try:
++ # TODO: sort out getting outputfilename properly
++ audiofilename = subprocess.outputfile
++ import edit
++ args = ["-d", "-o", info.filename, "-a", audiofilename, tmpfile]
++ if not edit.main(args):
++ print >>stderr, "Error doing merge..."
++ finally:
++ origexists, tmpexists = os.path.exists(info.filename), os.path.exists(tmpfile)
++ print >>stderr, "origexists %r, tmpexists %r" % (origexists, tmpexists)
++ if origexists and tmpexists:
++ try:
++ os.remove(tmpfile)
++ except OSError, e:
++ print >>stderr, "Could not remove temporary file: %s" % e
++ elif tmpexists:
++ print >>stderr, "only tmpfile remains after merge, renaming to original (but will not contain sound)"
++ os.rename( tmpfile, info.filename )
++ return
++
++
++# Thread management
++class RecordingThread:
++ def __init__(self, outputfile):
++ try:
++ import record_sound
++ except ImportError, e:
++ print >>stderr, "unable to use pymedia?:", e
++ raise
++ self.outputfile = outputfile
++ self.recorder = record_sound.voiceRecorder(self.outputfile)
++ self.thread = threading.Thread(target=self.recorder.run)
++
++ def start(self):
++ self.thread.start()
++
++ def stop(self):
++ self.recorder.finished = True
++ self.thread.join()
++
++# Subprocess management
++class Subprocess:
++
++ def __init__(self, s):
++ try:
++ import subprocess
++ except ImportError:
++ print >>stderr, '-S option requires Python 2.4 or newer.'
++ sys.exit(111)
++ if not hasattr(os, 'kill'):
++ print >>stderr, '-S option works only on Unix or Mac OS X.'
++ sys.exit(111)
++ self.args = s.split(' ')
++ self.popen = None
++ return
++
++ def start(self):
++ import subprocess
++ self.popen = subprocess.Popen(self.args)
++ return
++
++ def stop(self):
++ import signal
++ os.kill(self.popen.pid, signal.SIGINT)
++ self.popen.wait()
++ return
++
++
++# main
++# ./vnc2swf.py -S 'arecord -t wav -c 1 -r 22050 out.wav' -n -o out.swf
++def main(argv):
++ import getopt
++ def usage():
++ print ('usage: %s [-d] [-n] [-o filename] [-t {flv|mpeg|swf5|swf7|vnc}]'
++ ' [-e encoding] [-N] [-C clipping] [-r framerate] [-s scaling] [-z] [-m] [-a] [-V]'
++ ' [-S subprocess] [-P pwdfile] [host[:display] [port]]' % argv[0])
++ return 100
++ try:
++ (opts, args) = getopt.getopt(argv[1:], 'dno:t:e:NC:r:S:P:s:zmaV')
++ except getopt.GetoptError:
++ return usage()
++ (debug, console, outtype, subprocess, merge, pwdfile, isfile) = (0, False, None, None, False, None, False)
++ (cursor, host, port, preferred_encoding) = (True, 'localhost', 5900, (0,))
++ info = SWFInfo()
++ for (k, v) in opts:
++ if k == '-d': debug += 1
++ elif k == '-n': console = True
++ elif k == '-t': outtype = v
++ elif k == '-e': preferred_encoding = tuple([ int(i) for i in v.split(',') ])
++ elif k == '-N': cursor = False
++ elif k == '-S': subprocess = Subprocess(v)
++ elif k == '-a': subprocess = RecordingThread(v)
++ elif k == '-m': merge = True
++ elif k == '-P': pwdfile = v
++ elif k == '-V': isfile = True
++ elif k == '-o':
++ info.filename = v
++ elif k == '-C':
++ try:
++ info.set_clipping(v)
++ except ValueError:
++ print 'Invalid clipping specification:', v
++ return usage()
++ elif k == "-r":
++ info.framerate = int(v)
++ elif k == "-z":
++ info.set_scalable(True)
++ elif k == '-s':
++ info.scaling = float(v)
++ assert 0 < info.scaling and info.scaling <= 1.0, 'Invalid scaling.'
++ if not outtype:
++ if info.filename:
++ if info.filename.endswith('.vnc'):
++ outtype = 'vnc'
++ elif info.filename.endswith('.swf'):
++ outtype = 'swf5'
++ elif info.filename.endswith('.mpg') or info.filename.endswith('.mpeg'):
++ outtype = 'mpeg'
++ elif info.filename.endswith('.flv'):
++ outtype = 'flv'
++ else:
++ outtype = 'swf5'
++ if outtype not in ('swf5','swf7','vnc','mpeg','flv'):
++ print 'Please specify the output type or file extension.'
++ return usage()
++ if cursor:
++ preferred_encoding += (-232,-239,)
++ if 1 <= len(args):
++ if ':' in args[0]:
++ i = args[0].index(':')
++ host = args[0][:i] or 'localhost'
++ port = int(args[0][i+1:])+5900
++ else:
++ host = args[0]
++ if 2 <= len(args):
++ port = int(args[1])
++ if console:
++ if not info.filename:
++ print 'Please specify the output filename.'
++ return usage()
++ vncfile = None
++ if isfile:
++ vncfile = sys.stdin
++ if args:
++ vncfile = file(args[0], 'rb')
++ vnc2swf(info, outtype, host, port,
++ preferred_encoding=preferred_encoding,
++ subprocess=subprocess, pwdfile=pwdfile, vncfile=vncfile,
++ merge=merge, debug=debug)
++ else:
++ tempdir = os.path.join(tempfile.gettempdir(), 'pyvnc2swf')
++ try:
++ os.mkdir(tempdir)
++ except OSError:
++ pass
++ VNC2SWFWithTk(tempdir, info, outtype, host, port,
++ preferred_encoding=preferred_encoding,
++ subprocess=subprocess, pwdfile=pwdfile,
++ debug=debug).run()
++ return
++
++if __name__ == "__main__": sys.exit(main(sys.argv))
+diff -Naur pyvnc2swf-0.9.5.old/bin/pyvnc2swf-edit pyvnc2swf-0.9.5/bin/pyvnc2swf-edit
+--- pyvnc2swf-0.9.5.old/bin/pyvnc2swf-edit 1969-12-31 18:00:00.000000000 -0600
++++ pyvnc2swf-0.9.5/bin/pyvnc2swf-edit 2008-12-18 06:07:56.000000000 -0600
+@@ -0,0 +1,248 @@
++#!/usr/bin/env python
++##
++## pyvnc2swf - edit.py
++##
++## $Id: edit.py,v 1.6 2008/11/16 02:39:40 euske Exp $
++##
++## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
++## All Rights Reserved.
++##
++## This 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 software 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 software; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++## USA.
++##
++
++import sys, re
++from pyvnc2swf.movie import SWFInfo, MovieContainer
++from pyvnc2swf.output import FLVVideoStream, MPEGVideoStream, SWFVideoStream, \
++ SWFShapeStream, ImageSequenceStream, MovieBuilder
++stderr = sys.stderr
++
++
++# range2list: converts strings like "1,5-8" to [1,5,6,7,8].
++class RangeError(ValueError): pass
++def range2list(s, n0, n1, step=1):
++ PAT_RANGE = re.compile(r'^([0-9]*)-([0-9]*)$')
++ r = []
++ for i in s.split(','):
++ i = i.strip()
++ if not i: continue
++ if i.isdigit():
++ n = int(i)
++ if n0 <= n and n <= n1:
++ r.append(n)
++ else:
++ raise RangeError('%d: must be in %d...%d' % (n,n0,n1))
++ else:
++ m = PAT_RANGE.match(i.strip())
++ if not m:
++ raise RangeError('%r: illegal number' % i)
++ b = n0
++ if m.group(1):
++ b = int(m.group(1))
++ e = n1
++ if m.group(2):
++ e = int(m.group(2))
++ if e < b:
++ (b,e) = (e,b)
++ if b < n0:
++ raise RangeError('%d: must be in %d...%d' % (b,n0,n1))
++ if n1 < e:
++ raise RangeError('%d: must be in %d...%d' % (e,n0,n1))
++ r.extend(xrange(b,e+1,step))
++ return r
++
++
++# reorganize
++def reorganize(info, stream, moviefiles, range_str='-',
++ loop=True, seekbar=True,
++ step=1, kfinterval=0,
++ mp3seek=True, mp3skip=0,
++ debug=0):
++ movie = MovieContainer(info)
++ for fname in moviefiles:
++ if fname.endswith('.swf'):
++ # vnc2swf file
++ movie.parse_vnc2swf(fname, True, debug=debug)
++ elif fname.endswith('.flv'):
++ # flv file
++ movie.parse_flv(fname, True, debug=debug)
++ elif fname.endswith('.vnc'):
++ # vncrec file
++ movie.parse_vncrec(fname, debug=debug)
++ else:
++ raise ValueError('unsupported format: %r' % fname)
++ r = range2list(range_str, 0, movie.nframes-1, step)
++ if movie.info.mp3:
++ if isinstance(mp3skip, float):
++ mp3skip = int(mp3skip * movie.info.mp3.sample_rate)
++ movie.info.mp3.set_initial_skip(mp3skip)
++ builder = MovieBuilder(movie, stream, mp3seek=mp3seek, kfinterval=kfinterval, debug=debug)
++ builder.build(r)
++ stream.close()
++ movie.info.write_html(seekbar=seekbar, loop=loop)
++ return 0
++
++
++# main
++def main(argv):
++ import getopt
++ def usage():
++ print >>stderr, '''usage: %s
++ [-d] [-c] [-t type] [-f|-F frames] [-a mp3file] [-r framerate]
++ [-S mp3sampleskip] [-C WxH+X+Y] [-B blocksize] [-K keyframe]
++ [-R framestep] [-s scaling]
++ -o outfile.swf file1 file2 ...
++
++ Specify one output filename from the following:
++ *.swf: generate a SWF movie.
++ *.flv: generate a FLV movie.
++ *.mpg: generate a MPEG movie.
++ *.png|*.bmp: save snapshots of given frames as "X-nnn.png"
++
++ -d: debug mode.
++ -c: compression.
++ -t {swf5,swf7,flv,mpeg,png,bmp}: specify the output movie type.
++ -f(-F) frames: frames to extract. e.g. 1-2,100-300,310,500-
++ -F disables seeking audio.
++ -R framestep: frame resampling step (default: 1)
++ -s scaling: scale factor (default: 1.0)
++ -a filename: attach MP3 file(s). (multiple files can be specified)
++ -r framerate: override framerate.
++ -B blocksize: (SWF7 and FLV mode only) blocksize of video packet (must be a multiple of 16)
++ -K keyframe: keyframe interval
++ -S N[s]: skip the first N samples (or N seconds) of the sound when the movie starts.
++ -C WxH+X+Y: crop a specific area of the movie.
++ -b: disable seekbar.
++ -l: disable loop.
++ -z: make the movie scalable.
++ ''' % argv[0]
++ return 100
++ try:
++ (opts, args) = getopt.getopt(argv[1:], 'dr:o:t:cHa:S:C:B:K:f:F:R:s:blz')
++ except getopt.GetoptError:
++ return usage()
++ #
++ debug = 0
++ info = SWFInfo()
++ range_str = '-'
++ step = 1
++ streamtype = None
++ kfinterval = 0
++ mp3skip = 0
++ mp3seek = True
++ loop = True
++ seekbar = True
++ for (k, v) in opts:
++ if k == '-d':
++ debug += 1
++ elif k == '-r':
++ info.set_framerate(float(v))
++ elif k == '-o':
++ info.filename = v
++ elif k == '-t':
++ v = v.lower()
++ if v not in ('swf5','swf7','mpeg','mpg','flv','png','bmp','gif'):
++ print >>stderr, 'Invalid output type:', v
++ return usage()
++ streamtype = v
++ elif k == '-a':
++ fp = file(v, 'rb')
++ print >>stderr, 'Reading mp3 file: %s...' % v
++ info.reg_mp3blocks(fp)
++ fp.close()
++ elif k == '-S':
++ if v.endswith('s'):
++ mp3skip = float(v[:-1])
++ else:
++ mp3skip = int(v)
++ elif k == '-C':
++ try:
++ info.set_clipping(v)
++ except ValueError:
++ print >>stderr, 'Invalid clipping specification:', v
++ return usage()
++ elif k == '-B':
++ blocksize = int(v)
++ assert 0 < blocksize and blocksize <= 256 and blocksize % 16 == 0, 'Invalid block size.'
++ info.blocksize = blocksize
++ elif k == '-K':
++ kfinterval = int(v)
++ elif k == '-c':
++ info.compression = True
++ elif k == '-f':
++ range_str = v
++ elif k == '-F':
++ range_str = v
++ mp3seek = False
++ elif k == '-R':
++ step = int(v)
++ mp3seek = False
++ elif k == '-s':
++ info.scaling = float(v)
++ assert 0 < info.scaling and info.scaling <= 1.0, 'Invalid scaling.'
++ elif k == '-b':
++ seekbar = False
++ elif k == '-l':
++ loop = False
++ elif k == '-z':
++ info.set_scalable(True)
++ if not args:
++ print >>stderr, 'Specify at least one input movie.'
++ return usage()
++ if not info.filename:
++ print >>stderr, 'Specify exactly one output file.'
++ return usage()
++ if not streamtype:
++ v = info.filename
++ if v.endswith('.swf'):
++ streamtype = 'swf5'
++ elif v.endswith('.png'):
++ streamtype = 'png'
++ elif v.endswith('.bmp'):
++ streamtype = 'bmp'
++ elif v.endswith('.gif'):
++ streamtype = 'gif'
++ elif v.endswith('.mpg') or v.endswith('.mpeg'):
++ streamtype = 'mpeg'
++ elif v.endswith('.flv'):
++ streamtype = 'flv'
++ else:
++ print >>stderr, 'Unknown stream type.'
++ return 100
++ if streamtype == 'mpeg' and not MPEGVideoStream:
++ print >>stderr, 'MPEGVideoStream is not supported.'
++ return 100
++ stream = None
++ if streamtype == 'swf5':
++ stream = SWFShapeStream(info, debug=debug)
++ elif streamtype == 'swf7':
++ stream = SWFVideoStream(info, debug=debug)
++ elif streamtype in ('mpg', 'mpeg'):
++ stream = MPEGVideoStream(info, debug=debug)
++ elif streamtype == 'flv':
++ stream = FLVVideoStream(info, debug=debug)
++ else:
++ stream = ImageSequenceStream(info, debug=debug)
++ try:
++ return reorganize(info, stream, args, range_str,
++ loop=loop, seekbar=seekbar,
++ step=step, kfinterval=kfinterval,
++ mp3seek=mp3seek, mp3skip=mp3skip,
++ debug=debug)
++ except RangeError, e:
++ print >>stderr, 'RangeError:', e
++ return 100
++
++if __name__ == "__main__": sys.exit(main(sys.argv))
+diff -Naur pyvnc2swf-0.9.5.old/bin/pyvnc2swf-play pyvnc2swf-0.9.5/bin/pyvnc2swf-play
+--- pyvnc2swf-0.9.5.old/bin/pyvnc2swf-play 1969-12-31 18:00:00.000000000 -0600
++++ pyvnc2swf-0.9.5/bin/pyvnc2swf-play 2008-12-18 06:08:06.000000000 -0600
+@@ -0,0 +1,275 @@
++#!/usr/bin/env python
++##
++## pyvnc2swf - play.py
++##
++## $Id: play.py,v 1.6 2008/11/16 02:39:40 euske Exp $
++##
++## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
++## All Rights Reserved.
++##
++## This 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 software 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 software; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++## USA.
++##
++
++import sys, os.path, subprocess
++import pygame
++from pyvnc2swf.image import create_image_from_string_argb
++from pyvnc2swf.movie import SWFInfo, MovieContainer
++from pyvnc2swf.output import SWFScreen, MovieOutputStream, MovieBuilder
++lowerbound = max
++upperbound = min
++stderr = sys.stderr
++
++
++## PygameMoviePlayer
++##
++class PygameMoviePlayer(MovieOutputStream):
++
++ """
++ A simple movie player using Pygame.
++ """
++
++ font_size = 24
++
++ def __init__(self, movie, debug=0):
++ MovieOutputStream.__init__(self, movie.info, debug)
++ self.builder = MovieBuilder(movie, self, debug)
++ self.movie = movie
++ return
++
++ # MovieOuputStream methods
++
++ def open(self):
++ MovieOutputStream.open(self)
++ # open window
++ (x,y,w,h) = self.info.clipping
++ self.imagesize = ( int(w*(self.info.scaling or 1)), int(h*(self.info.scaling or 1)) )
++ self.screen = SWFScreen(x, y, w, h)
++ (self.winwidth, self.winheight) = self.imagesize
++ self.font = pygame.font.SysFont(pygame.font.get_default_font(), self.font_size)
++ (fw1,fh1) = self.font.size('00000 ')
++ (fw2,fh2) = self.font.size('[>] ')
++ self.panel_x0 = 0
++ self.panel_x1 = fw1
++ self.panel_x2 = fw1+fw2
++ self.panel_y0 = self.winheight
++ self.panel_y1 = self.winheight + fh1/2
++ self.panel_h = fh1
++ self.panel_w = lowerbound(64, self.winwidth-fw1-fw2-4)
++ self.slide_h = fh1/2
++ self.slide_w = 8
++ self.actualwidth = self.panel_w+fw1+fw2+4
++ pygame.display.set_caption(self.info.filename, self.info.filename)
++ self.window = pygame.display.set_mode((self.actualwidth, self.winheight+self.panel_h))
++ self.cursor_image = None
++ self.cursor_pos = None
++ self.playing = True
++ self.mp3_out = self.mp3_dec = None
++ #import pymedia
++ #self.mp3_out = subprocess.Popen(['mpg123','-q','-'], stdin=subprocess.PIPE)
++ #self.mp3_dec = pymedia.audio.acodec.Decoder('mp3')
++ #self.mp3_out = pymedia.audio.sound.Output(44100,2,pymedia.audio.sound.AFMT_S16_LE)
++ return
++
++ def paint_frame(self, (images, othertags, cursor_info)):
++ for ((x0,y0), (w,h,data)) in images:
++ self.screen.paint_image(x0, y0, w, h, data)
++ if cursor_info:
++ (cursor_image, cursor_pos) = cursor_info
++ if cursor_image:
++ (w, h, dx, dy, data) = cursor_image
++ self.cursor_offset = (dx, dy)
++ self.cursor_image = create_image_from_string_argb(w, h, data)
++ if cursor_pos:
++ self.cursor_pos = cursor_pos
++ return
++
++ def preserve_frame(self):
++ img = pygame.Surface(self.screen.buf.get_size())
++ img.blit(self.screen.buf, (0,0))
++ return img
++
++ def recover_frame(self, img):
++ self.screen.buf.blit(img, (0,0))
++ return
++
++ # additional methods
++
++ def show_status(self):
++ f = self.current_frame
++ n = self.movie.nframes
++ s = '%05d' % f
++ self.window.fill((0,0,0), (0, self.panel_y0, self.actualwidth, self.panel_h))
++ self.window.blit(self.font.render(s, 0, (255,255,255)), (0, self.panel_y0))
++ if self.playing:
++ self.window.blit(self.font.render('[>]', 0, (0,255,0)), (self.panel_x1, self.panel_y0))
++ else:
++ self.window.blit(self.font.render('[||]', 0, (255,0,0)), (self.panel_x1, self.panel_y0))
++ self.window.fill((255,255,255), (self.panel_x2, self.panel_y1, self.panel_w, 1))
++ x = self.panel_x2 + self.panel_w*f/n - self.slide_w/2
++ y = self.panel_y1 - self.slide_h/2
++ self.window.fill((255,255,255), (x, y, self.slide_w, self.slide_h))
++ return
++
++ def update(self):
++ surface = self.screen.buf
++ if self.info.scaling:
++ # rotozoom is still very unstable... it sometime causes segfault :(
++ # in case it doesn't work, use scale instead.
++ # surface = pygame.transform.scale(surface, self.imagesize)
++ # surface.set_alpha()
++ surface = pygame.transform.rotozoom(surface, 0, self.info.scaling)
++ self.window.blit(surface, (0,0))
++ if self.cursor_image and self.cursor_pos:
++ (x, y) = self.cursor_pos
++ (dx, dy) = self.cursor_offset
++ self.window.blit(self.cursor_image, (x-dx, y-dy))
++ self.show_status()
++ pygame.display.update()
++ if self.mp3_out and self.info.mp3:
++ t = (self.current_frame+1) / self.info.framerate
++ (nsamples, seeksamples, mp3frames) = self.info.mp3.get_frames_until(t)
++ r = self.mp3_dec.decode(''.join(mp3frames))
++ self.mp3_out.play(r.data)
++ return
++
++ def toggle_playing(self):
++ self.playing = not self.playing
++ if self.playing and self.movie.nframes-1 <= self.current_frame:
++ self.current_frame = 0
++ return
++
++ def seek(self, goal):
++ self.current_frame = upperbound(lowerbound(goal, 0), self.movie.nframes-1)
++ self.builder.seek(self.current_frame)
++ self.playing = False
++ self.update()
++ return
++
++ def play(self):
++ drag = False
++ loop = True
++ ticks0 = 0
++ self.current_frame = 0
++ self.builder.start()
++ while loop:
++ if self.playing:
++ events = pygame.event.get()
++ else:
++ events = [pygame.event.wait()]
++ for e in events:
++ if e.type in (pygame.MOUSEBUTTONDOWN, pygame.MOUSEMOTION):
++ (x,y) = e.pos
++ if (e.type == pygame.MOUSEBUTTONDOWN and y < self.panel_y0):
++ # the screen clicked
++ self.toggle_playing()
++ elif (self.panel_y0 < y and (e.type == pygame.MOUSEBUTTONDOWN or drag)):
++ # slide bar dragging
++ drag = True
++ (x,y) = e.pos
++ self.seek((x-self.panel_x2)*self.movie.nframes/self.panel_w)
++ elif e.type == pygame.MOUSEBUTTONUP:
++ drag = False
++ elif e.type == pygame.KEYDOWN:
++ if e.key in (13, 32): # space or enter
++ self.toggle_playing()
++ elif e.key in (113, 27): # 'q'uit, esc
++ loop = False
++ elif e.key in (115, 83): # 's'napshot
++ (root, ext) = os.path.splitext(self.info.filename)
++ fname = '%s-%05d.bmp' % (root, self.current_frame)
++ pygame.image.save(self.screen.buf, fname)
++ print >>stderr, 'Save:', fname
++ elif e.key == 275: # right
++ self.current_frame += 1
++ self.seek(self.current_frame)
++ elif e.key == 276: # left
++ self.current_frame -= 1
++ self.seek(self.current_frame)
++ else:
++ print >>stderr, 'Unknown key:', e
++ elif e.type == pygame.QUIT:
++ # window close attmpt
++ loop = False
++ if self.playing:
++ self.builder.seek(self.current_frame)
++ if self.movie.nframes-1 <= self.current_frame:
++ # reach the end.
++ self.playing = False
++ else:
++ self.current_frame += 1
++ ticks1 = pygame.time.get_ticks()
++ d = lowerbound(int(1000.0/self.info.framerate), ticks0-ticks1)
++ ticks0 = ticks1
++ pygame.time.wait(d)
++ self.update()
++ # loop end
++ self.builder.finish()
++ self.close()
++ return
++
++
++# play
++def play(moviefiles, info, debug=0):
++ movie = MovieContainer(info)
++ for fname in moviefiles:
++ if fname.endswith('.swf'):
++ # vnc2swf file
++ movie.parse_vnc2swf(fname, True, debug=debug)
++ elif fname.endswith('.flv'):
++ # flv file
++ movie.parse_flv(fname, True, debug=debug)
++ elif fname.endswith('.vnc'):
++ # vncrec file
++ movie.parse_vncrec(fname, debug=debug)
++ else:
++ raise ValueError('unsupported format: %r' % fname)
++ info.filename = os.path.basename(fname)
++ PygameMoviePlayer(movie, debug=debug).play()
++ return
++
++# main
++def main(argv):
++ import getopt, re
++ def usage():
++ print 'usage: %s [-d] [-r framerate] [-C WxH+X+Y] [-s scaling] file1 file2 ...' % argv[0]
++ return 100
++ try:
++ (opts, args) = getopt.getopt(argv[1:], 'dr:C:s:')
++ except getopt.GetoptError:
++ return usage()
++ #
++ debug = 0
++ info = SWFInfo()
++ for (k, v) in opts:
++ if k == '-d':
++ debug += 1
++ elif k == '-r':
++ info.set_framerate(float(v))
++ elif k == '-C':
++ m = re.match(r'^(\d+)x(\d+)\+(\d+)\+(\d+)$', v)
++ if not m:
++ print >>stderr, 'Invalid clipping specification:', v
++ return usage()
++ x = map(int, m.groups())
++ info.clipping = (x[2],x[3], x[0],x[1])
++ elif k == '-s':
++ info.scaling = float(v)
++ if not args:
++ print >>stderr, 'Specify at least one input movie.'
++ return usage()
++ return play(args, info, debug=debug)
++
++if __name__ == "__main__": sys.exit(main(sys.argv))
+diff -Naur pyvnc2swf-0.9.5.old/bin/recordwin pyvnc2swf-0.9.5/bin/recordwin
+--- pyvnc2swf-0.9.5.old/bin/recordwin 1969-12-31 18:00:00.000000000 -0600
++++ pyvnc2swf-0.9.5/bin/recordwin 2008-11-15 20:39:40.000000000 -0600
+@@ -0,0 +1,60 @@
++#!/bin/sh
++##
++## recordwin.sh
++## $Id: recordwin.sh,v 1.3 2008/11/16 02:39:40 euske Exp $
++##
++## Quick recording script for UNIX.
++##
++## usage:
++## recordwin.sh [-display disp] [-name winname] [-id winid] output.swf
++##
++## Requires: x11vnc, xwininfo, awk
++##
++
++PYTHON=python
++VNC2SWF=pyvnc2swf/vnc2swf.py
++X11VNC=x11vnc
++XWININFO=xwininfo
++AWK=awk
++
++usage() {
++ echo "usage: $0 [-all] [-display display] [-name windowname] [-id windowid] [-type filetype] outfile"
++ exit 100
++}
++
++vncopts=
++xwopts=
++desktop=
++display="$DISPLAY"
++while [ $# -gt 1 ]; do
++ case "$1" in
++ -all|-a) desktop=1;;
++ -name) shift; xwopts="$xwopts -name $1";;
++ -id) shift; xwopts="$xwopts -id $1";;
++ -display|-d) shift; display="$1"; xwopts="$xwopts -display $1";;
++ -type|-t) shift; vncopts="$vncopts -t $1";;
++ -*) usage;;
++ esac
++ shift
++done
++
++if [ $# -lt 1 ]; then usage; fi
++
++outfile="$1"
++if [ "X$desktop" = "X" ]; then
++ info=`$XWININFO $xwopts 2>/dev/null`
++ if [ "X$info" = "X" ]; then
++ echo "Window $xwopts not found!"
++ exit 2
++ fi
++ geometry="-C `echo "$info" |
++ $AWK '/Absolute upper-left X:/{x=$4}
++ /Absolute upper-left Y:/{y=$4}
++ /Width:/{w=$2} /Height:/{h=$2}
++ END {printf "%dx%d+%d+%d",w,h,x,y}' `"
++ echo $geometry
++fi
++
++# launch x11vnc and vnc2swf
++$X11VNC -quiet -bg -nopw -display "$display" -viewonly -localhost -cursor -wait 10 -defer 10 &&
++ $PYTHON $VNC2SWF -n $vncopts -o "$outfile" $geometry
+diff -Naur pyvnc2swf-0.9.5.old/bin/recordwin.sh pyvnc2swf-0.9.5/bin/recordwin.sh
+--- pyvnc2swf-0.9.5.old/bin/recordwin.sh 2008-12-18 06:06:38.000000000 -0600
++++ pyvnc2swf-0.9.5/bin/recordwin.sh 1969-12-31 18:00:00.000000000 -0600
+@@ -1,60 +0,0 @@
+-#!/bin/sh
+-##
+-## recordwin.sh
+-## $Id: recordwin.sh,v 1.3 2008/11/16 02:39:40 euske Exp $
+-##
+-## Quick recording script for UNIX.
+-##
+-## usage:
+-## recordwin.sh [-display disp] [-name winname] [-id winid] output.swf
+-##
+-## Requires: x11vnc, xwininfo, awk
+-##
+-
+-PYTHON=python
+-VNC2SWF=pyvnc2swf/vnc2swf.py
+-X11VNC=x11vnc
+-XWININFO=xwininfo
+-AWK=awk
+-
+-usage() {
+- echo "usage: $0 [-all] [-display display] [-name windowname] [-id windowid] [-type filetype] outfile"
+- exit 100
+-}
+-
+-vncopts=
+-xwopts=
+-desktop=
+-display="$DISPLAY"
+-while [ $# -gt 1 ]; do
+- case "$1" in
+- -all|-a) desktop=1;;
+- -name) shift; xwopts="$xwopts -name $1";;
+- -id) shift; xwopts="$xwopts -id $1";;
+- -display|-d) shift; display="$1"; xwopts="$xwopts -display $1";;
+- -type|-t) shift; vncopts="$vncopts -t $1";;
+- -*) usage;;
+- esac
+- shift
+-done
+-
+-if [ $# -lt 1 ]; then usage; fi
+-
+-outfile="$1"
+-if [ "X$desktop" = "X" ]; then
+- info=`$XWININFO $xwopts 2>/dev/null`
+- if [ "X$info" = "X" ]; then
+- echo "Window $xwopts not found!"
+- exit 2
+- fi
+- geometry="-C `echo "$info" |
+- $AWK '/Absolute upper-left X:/{x=$4}
+- /Absolute upper-left Y:/{y=$4}
+- /Width:/{w=$2} /Height:/{h=$2}
+- END {printf "%dx%d+%d+%d",w,h,x,y}' `"
+- echo $geometry
+-fi
+-
+-# launch x11vnc and vnc2swf
+-$X11VNC -quiet -bg -nopw -display "$display" -viewonly -localhost -cursor -wait 10 -defer 10 &&
+- $PYTHON $VNC2SWF -n $vncopts -o "$outfile" $geometry