#!/usr/bin/env python # # Copyright (C) 2002 Brian Skahan # # 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 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 the program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA __author__ = "Brian Skahan " __date__ = "Dec 02 2002" __version__ = "0.1.2" import os import sys import ConfigParser import calendar import re from ftplib import FTP from Xlib import * class Screenshot: """Uses ImageMagick to create a screenshot if more than 1 X display screen is declared in ~/.circus/cscreenshot.cfg shots are taken of each screen and tacked together with montage. A thumbnail is created from the final shot. The files are named by date """ defaults = {'img_dir': os.path.expanduser('~/'), 'img_type': 'gif', 'img_width': '1024', 'num_screens': '2', 'thumb_size': '200', 'write_html': 'false', 'html_file': 'screens.html', 'html_reverse': 'true', 'remote_dir': 'www/screens', 'upload': 'false', 'proto': 'ftp', 'remote_site': 'None', 'remote_user': 'None', 'remote_pass': 'None'} config = ConfigParser.ConfigParser(defaults) config.read(os.path.expanduser('~/.cscreenshot.cfg')) date = None short_file_name = None file_name = None short_thumb_name = None thumb_name = None screenshot = None screens = [] disp = display.Display() #should move this to num_screens() html_file = None def __init__(self): # for multiheaded displays not using Xinerama, set the num_screens # option in ~/.cscreenshot.cfg, TODO getting the diplay name here is # the only thing that relies on xlib, whats a better way. i=0 dsp = self.disp.get_display_name()[:-1] while i < self.config.getint('main','num_screens'): self.screens.append(dsp + str(i)) i += 1 # format the date into YYYY-MM-DD full_date = calendar.localtime() self.date = "%d-%d-%d" %(full_date[0],full_date[1],full_date[2]) # make sure we're putting things in the right directories self.short_file_name = self.date \ + "." \ + self.config.get('main','img_type') self.file_name = self.config.get('main','img_dir') \ + "/" \ + self.short_file_name self.short_thumb_name = self.date \ + ".thumb." \ + self.config.get('main','img_type') self.thumb_name = self.config.get('main','img_dir') \ + "/" \ + self.short_thumb_name def snag_new(self): """this does most of the work uses import to get shots for each screen and use montage to join them if there's more than one display screen """ # theses are for the hardcode kludge temp0 = self.config.get('main','img_dir') \ + '/temp0.' \ + self.config.get('main','img_type') temp1 = self.config.get('main','img_dir') \ + '/temp1.' \ + self.config.get('main','img_type') temp2 = self.config.get('main','img_dir') \ + '/temp2.' \ + self.config.get('main','img_type') for screen in self.screens: pid = os.fork() if not pid: # important: the width of each initial screenshot is the # variable img_width divided by the user determined # num_screens os.execvp('import',['import', '-display', screen, '-window', 'root', '-geometry', str(self.config.getint('main', 'img_width') /self.config.getint('main', 'num_screens')), self.config.get('main','img_dir') \ + '/' \ + 'temp' \ + str(screen[-1:]) \ + "." \ + self.config.get('main','img_type')]) os.wait() # XXX this is dumb, hard coded for up to 3 screens fix me # see about using os.tmpname if len(self.screens) = 2: pid = os.fork() if not pid: os.execvp('montage',['montage', temp0, temp1, '-geometry', '+0+0', self.file_name]) os.wait() # do some cleanup os.remove(temp0) os.remove(temp1) # this next part is untested to my knowledge since I only have 2 # screens elif len(self.screens) = 3: pid = os.fork() if not pid: os.execvp('montage',['montage', temp0, temp1, temp2, '-geometry', '+0+0', self.file_name]) os.wait() # do some cleanup os.remove(temp0) os.remove(temp1) os.remove(temp2) elif len(self.screens) > 3: print "At the moment this program only handles up to 3 screens." print "If you would like to use it with more, send me an email," print "and I'll fix it, or fix it and send me a patch ;)" exit(-1) else: os.rename(temp0,self.file_name) # take self.file_name and make a thumb from it def make_thumb(self): """call convert to shrink the image""" pid = os.fork() if not pid: os.execvp('convert',['convert', '-geometry', self.config.get('main','thumb_size'), self.file_name, self.thumb_name]) os.wait() def write_html(self): """expands the html template and inserts it into html_file. The template is inserted right after finding a :::SCREENS::: in the file """ # you can change this template as you like, each %s is replace in # order with the variables in parenthesis template = '''
\"%s\"/
%s



''' % (self.short_file_name, self.short_thumb_name, self.short_file_name, self.date) html_file_name = self.config.get('main','img_dir') \ + '/' \ + self.config.get('main','html_file') regex = re.compile(':::SCREENS:::') top = [] bottom = [] found = None # open html_file in read mode html_file = file(html_file_name,'r+') # step through the file, saving each line to top, when the regex # matches add the line with the regex to top then put the rest of the # lines in bottom for line in html_file: score = regex.search(line) if not score: if not found: top.append(line) else: bottom.append(line) if score: found = 1 if self.config.get('main','html_reverse') == 'true': top.append(line) else: top.append(line) html_file.close() # only write html if it has :::SCREENS::: in it if found: # open html_file in write mode html_file = file(html_file_name,'w+') html_file.writelines(top) html_file.close() # open html_file in append mode html_file = file(html_file_name,'a+') html_file.write(template) html_file.writelines(bottom) html_file.close() else: print "You need to add a line with :::SCREENS::: to indicate where\ you want new screenshots to start in:\n", html_file_name sys.exit(-1) def ftp_transfer(self): """connect to ftp site, upload html_file, screenshot and thumb""" # get the configs for readability host = self.config.get('main','remote_site') user = self.config.get('main','remote_user') passwd = self.config.get('main','remote_pass') remote_dir = self.config.get('main','remote_dir') # open the files for ftp img = file(self.file_name) thumb = file(self.thumb_name) html_file = file(self.config.get('main','img_dir') \ + '/' \ + self.config.get('main','html_file'),'r+') # intitiate FTP and connect ftp = FTP(host,user,passwd) # change to the correct directory ftp.cwd(remote_dir) # upload if self.config.get('main','write_html') == 'true': ftp.storlines('STOR ' + self.config.get('main','html_file'),html_file) ftp.storbinary('STOR ' + self.short_file_name,img) ftp.storbinary('STOR ' + self.short_thumb_name,thumb) # close files img.close() thumb.close() html_file.close() def scp_transfer(self): """execs scp to transfer the files""" host = self.config.get('main','remote_site') user = self.config.get('main','remote_user') passwd = self.config.get('main','remote_pass') remote_dir = self.config.get('main','remote_dir') if self.config.get('main','write_html') == 'true': pid = os.fork() if not pid: os.execvp('scp',['scp', self.file_name, self.thumb_name, self.config.get('main','img_dir') \ + '/' \ + self.config.get('main','html_file'), user + '@' + host + ':' + remote_dir]) os.wait() else: pid = os.fork() if not pid: os.execvp('scp',['scp', self.file_name, self.thumb_name, user + '@' + host + ':' + remote_dir]) os.wait() def main(self): """how to call this as a standalone program""" self.snag_new() self.make_thumb() if self.config.get('main','write_html') == 'true': self.write_html() if self.config.get('main','upload') == 'true': if self.config.get('main','proto') == 'ftp': self.ftp_transfer() if self.config.get('main','proto') == 'scp': self.scp_transfer() if __name__ == '__main__': else: new = Screenshot() new.main()