#! /usr/bin/env python"""LibreOffice/OpenOffice Impress Viewer script For use in rendering unattended presentations, this should allow you to call: presentation-viewer /path/to/presentation and have the presentation load, switch to presentation mode, and autoadvance through the presentation until the end of the presentation,even if the presentation is not already set up for auto-advancing.Intended to optionally allow looping or not..."""import os, sys, subprocess, time, pprint, urllibimport unofrom com.sun.star.beans import PropertyValuefrom com.sun.star.presentation.FadeEffect import UNCOVER_TO_RIGHT, NONE as TRANSITION_NONECAPTIVE = Nonedef captive( port=2002 ): return subprocess.Popen( [ 'libreoffice', '--invisible', '--accept=socket,host=localhost,port=%(port)s;urp;'%locals(), '--norestore', '--nologo', '--nolockcheck', '--nodefault', ] )DESKTOP = Nonedef desktop( port=2002 ): global DESKTOP if DESKTOP is None: localContext = uno.getComponentContext() resolver = localContext.ServiceManager.createInstanceWithContext( 'com.sun.star.bridge.UnoUrlResolver', localContext ) context = resolver.resolve( 'uno:socket,host=localhost,port=%(port)s;urp;StarOffice.ComponentContext'%locals() ) DESKTOP = context.ServiceManager.createInstance('com.sun.star.frame.Desktop') return DESKTOPdef new( port = 2002 ): return load( "private:factory/simpress", port )def load_file( filename, port=2002 ): filename = os.path.abspath( filename ) file_url = 'file://'+ urllib.quote( filename ) # apparently unohelpers has this already return load( file_url, port )def load( url, port=2002 ): """Load the given Impress/PPT document""" return desktop().loadComponentFromURL(url, "_blank", 0, properties(Hidden=False))def properties( **named ): """Convert a dictionary of values to a set of property records for PyUNO""" result = [] for key,value in named.items(): p = PropertyValue() p.Name = key p.Value = value result.append( p ) return tuple(result)if __name__ == "__main__": CAPTIVE = captive() try: impress = None for i in range( 4 ): time.sleep( 1+(2**i)) try: impress = load_file(sys.argv[1]) except Exception, err: pass # Yes, yes, when the basics work... else: break if not impress: raise RuntimeError( "Unable to connect to libreoffice" ) pages = impress.getDrawPages() for i in range( pages.getCount()): page = pages.getByIndex( i ) page.setPropertyValue('Change', 1 ) page.setPropertyValue('Duration',5) # TODO: Only if there is no, or an invalid duration, set to the short period # This isn't necessary, AFAICS, at least, it doesn't seem to help... # page.setPropertyValue('Effect',TRANSITION_NONE) presentation = impress.getPresentation() pres_properties = properties( IsEndless = True, IsMouseVisible = False, IsAutomatic = True, # loop IsFullScreen = True,# IsAlwaysOnTop = True, # Fine, but annoying during testing... AllowAnimations = True, Pause = 0, # don't display black screen on finish # IsTransitionOnClick = False, # Crashes LibreOffice # IsShowLogo = False, # Crashes LibreOffice ) # Doesn't make a difference if they are set on the presentation, still # don't get transitions...# for item in pres_properties:# presentation.setPropertyValue( item.Name, item.Value ) presentation.startWithArguments( pres_properties ) controller = presentation.getController() while not controller: controller = presentation.getController() time.sleep( 0.01 ) # sigh last = None last_start = time.time() count = controller.getSlideCount() max_duration = 5 # There must be *some* way to convince LibreOffice to actually advance # the slides as the user intends... while controller.isRunning(): try: current = controller.getCurrentSlideIndex() if current != last: print '%s/%s'%( current, count ) last = current last_start = time.time() elif last_start + max_duration < time.time(): controller.gotoNextSlide() except Exception, err: print 'Unable to retrieve current slide' time.sleep( 1 ) # TODO: when we get transitions working, close and exit on last slide # This needs a parameter of some sort, oh java docs... # impress.close() finally: # TODO: properly send shut down signals, maybe save modified file to cache # to avoid startup penalty CAPTIVE.kill()