From 7e127c3969ded9ace8f056c5f3e47d070ff17179 Mon Sep 17 00:00:00 2001 From: James Bunton Date: Wed, 2 Jul 2008 01:45:29 +1000 Subject: [PATCH] RandomBG: More major cleanups. * Moved FileLists into randombg.py * Made WallChanger into just a library for setting the wallpaper, no cycling, etc * Cache saving is broken for the moment. --- bin/randombg.py | 209 ++++++++++++++++++++++++++++++++++++++++----- lib/FileLists.py | 195 ------------------------------------------ lib/WallChanger.py | 38 +++------ 3 files changed, 200 insertions(+), 242 deletions(-) delete mode 100644 lib/FileLists.py diff --git a/bin/randombg.py b/bin/randombg.py index ce67906..f31cbb6 100755 --- a/bin/randombg.py +++ b/bin/randombg.py @@ -4,31 +4,197 @@ VERSION = "2.0" import asyncore, asynchat, socket -import os, os.path, sys, time +import os, os.path, random, sys, time from optparse import OptionParser import logging from logging import debug, info, warning, error, critical logging.basicConfig(format="%(levelname)s: %(message)s") +try: + import cPickle as pickle +except ImportError: + import pickle try: # Required libraries import asyncsched - from FileLists import * import WallChanger except ImportError, e: critical("Missing libraries! Exiting...") sys.exit(1) + + +def filter_images(filenames): + extensions = ('.jpg', '.jpe', '.jpeg', '.png', '.gif', '.bmp') + for filename in filenames: + _, ext = os.path.splitext(filename) + if ext.lower() in extensions: + yield filename + +class BaseFileList(object): + """Base file list implementation""" + def scan_paths(self): + raise NotImplementedError() + + def add_path(self, path): + raise NotImplementedError() + + def store_cache(self, path): + pass + + def load_cache(self, filename, rescanPaths = False): + pass + + def get_next_image(self): + raise NotImplementedError() + + def get_prev_image(self): + raise NotImplementedError() + + def get_current_image(self): + raise NotImplementedError() + + def is_empty(self): + return False + + +class RandomFileList(BaseFileList): + def __init__(self): + self.list = [] + self.paths = [] + self.last_image = None + + def scan_paths(self): + for path in self.paths: + for dirpath, dirsnames, filenames in os.walk(path): + for filename in filter_images(filenames): + self.list.append(os.path.join(dirpath, filename)) + + def add_path(self, path): + self.paths.append(path) + debug('Added path "%s" to the list' % path) + + def get_next_image(self): + n = random.randint(0, len(self.list)-1) + self.last_image = self.list[n] + debug("Picked file '%s' from list" % self.last_image) + return self.last_image + + def is_empty(self): + return len(self.list) > 0 + + +class AllRandomFileList(BaseFileList): + def __init__(self): + self.list = None + self.paths = [] + self.imagePointer = 0 + + # Scan the input directory, and then randomize the file list + def scan_paths(self): + debug("Scanning paths") + + self.list = [] + for path in self.paths: + debug('Scanning "%s"' % path) + for dirpath, dirsnames, filenames in os.walk(path): + for filename in filter_images(filenames): + debug('Adding file "%s"' % filename) + self.list.append(os.path.join(dirpath, filename)) + + random.shuffle(self.list) + + def add_path(self, path): + self.paths.append(path) + debug('Added path "%s" to the list' % path) + + def store_cache(self, filename): + try: + fd = open(filename, 'wb') + pickle.dump(obj = self, file = fd, protocol = 2) + debug("Cache successfully stored") + except Exception, e: + warning("Exception while storing cache: '%s'" % e) + + def load_cache(self, filename, rescanPaths = False): + debug('Attempting to load cache from "%s"' % filename) + self.paths.sort() + try: + fd = open(filename, 'rb') + tmp = pickle.load(fd) + if self.paths == tmp.paths: + debug("Path lists match, copying properties") + # Overwrite this object with the other + for attr in ('list', 'imagePointer'): + setattr(self, attr, getattr(tmp, attr)) + else: + debug("Ignoring cache, path lists do not match") + except Exception, e: + warning("Exception while loading cache: '%s'" % e) + + def get_current_image(self): + return self.list[self.imagePointer] + + def __inc_in_range(self, n, amount = 1, rangeMax = None, rangeMin = 0): + if rangeMax == None: rangeMax = len(self.list) + assert rangeMax > 0 + return (n + amount) % rangeMax + + def get_next_image(self): + self.imagePointer = self.__inc_in_range(self.imagePointer) + imageName = self.list[self.imagePointer] + debug("Picked file '%s' (pointer=%d) from list" % (imageName, self.imagePointer)) + return imageName + + def get_prev_image(self): + self.imagePointer = self.__inc_in_range(self.imagePointer, amount=-1) + imageName = self.list[self.imagePointer] + debug("Picked file '%s' (pointer=%d) from list" % (imageName, self.imagePointer)) + return imageName + + def is_empty(self): + return self.list + +class FolderRandomFileList(BaseFileList): + """A file list that will pick a file randomly within a directory. Each + directory has the same chance of being chosen.""" + def __init__(self): + self.directories = {} + + def add_path(self, path): + debug('Added path "%s" to the list' % path) + for dirpath, dirs, filenames in os.walk(path): + debug('Scanning "%s" for images' % dirpath) + if self.directories.has_key(dirpath): + continue + filenames = filter_images(filenames) + if len(filenames): + self.directories[dirpath] = filenames + debug('Adding "%s" to "%s"' % (filenames, dirpath)) + else: + debug("No images found in '%s'" % dirpath) + + def get_next_image(self): + directory = random.choice(self.directories.keys()) + debug('directory: "%s"' % directory) + filename = random.choice(self.directories[directory]) + debug('filename: "%s"' % filename) + return os.path.join(directory, filename) + + def is_empty(self): + return len(self.directories.values()) + + class Cycler(object): def __init__(self, options, paths): - filelist = self.find_files(options, paths) - if not filelist.hasImages(): + self.filelist = self.find_files(options, paths) + if not self.filelist.is_empty(): error("No images were found. Exiting...") sys.exit(1) - debug("Initilizing RandomBG") - self.randombg = WallChanger.RandomBG(filelist, options.background_colour, options.permanent) + debug("Initialising RandomBG") + self.randombg = WallChanger.RandomBG(options.background_colour, options.permanent) self.cycle_time = options.cycle_time self.task = None @@ -43,18 +209,19 @@ class Cycler(object): filelist = RandomFileList() for path in paths: - filelist.doAddPath(path) + filelist.add_path(path) - if filelist.attemptCacheLoad(options.history_filename): + if filelist.load_cache(options.history_filename): debug("Loaded cache successfully") else: debug("Could not load cache") - filelist.doScanPaths() + filelist.scan_paths() return filelist def cmd_reset(self): def next(): - self.randombg.cycleNext() + image = self.filelist.get_next_image() + self.randombg.setImage(image) self.task = None self.cmd_reset() @@ -64,19 +231,22 @@ class Cycler(object): debug("Reset timer for %s seconds" % self.cycle_time) def cmd_reload(self): - self.randombg.cycleReload() + image = self.filelist.get_current_image() + self.randombg.setImage(image) self.cmd_reset() def cmd_next(self): - self.randombg.cycleNext() + image = self.filelist.get_next_image() + self.randombg.setImage(image) self.cmd_reset() def cmd_prev(self): - self.randombg.cyclePrev() + image = self.filelist.get_prev_image() + self.randombg.setImage(image) self.cmd_reset() def cmd_rescan(self): - self.randombg.filelist.doScanPaths() + self.filelist.scan_paths() self.cmd_next() def cmd_pause(self): @@ -124,11 +294,12 @@ class Listener(asyncore.dispatcher): def do_server(options, paths): try: - cycler = Cycler(options, paths) - listener = Listener(options.socket_filename, cycler) - asyncsched.loop() - except KeyboardInterrupt: - print + try: + cycler = Cycler(options, paths) + listener = Listener(options.socket_filename, cycler) + asyncsched.loop() + except KeyboardInterrupt: + print finally: # Make sure that the socket is cleaned up try: diff --git a/lib/FileLists.py b/lib/FileLists.py deleted file mode 100644 index 6c769f6..0000000 --- a/lib/FileLists.py +++ /dev/null @@ -1,195 +0,0 @@ -#! python - -import sys, os, os.path, random -import cPickle - -try: - import GregDebug - from GregDebug import debug, DEBUG_LEVEL_DEBUG, DEBUG_LEVEL_LOW, DEBUG_LEVEL_MEDIUM, DEBUG_LEVEL_HIGH - if __name__ == "__main__": - GregDebug.DEBUG_LEVEL = -10 -except ImportError: - print >>sys.stderr, "WARNING: debugging disabled as GregDebug could not be found" - DEBUG_LEVEL_DEBUG = DEBUG_LEVEL_LOW = DEBUG_LEVEL_MEDIUM = DEBUG_LEVEL_HIGH = None - def debug(message, level=None, indent_level = None): - pass - -class FileListNotImplemented(Exception): - pass - -def filterImageFiles(imageList): - IMAGE_EXT_LIST = ('.jpg', '.jpe', '.jpeg', '.png', '.gif', '.bmp') - def isImageFile(fname): - filebase, fileext = os.path.splitext(fname) - fileext = fileext.lower() - return fileext in IMAGE_EXT_LIST - return [fname for fname in imageList if isImageFile(fname)] - - -class BaseFileList(object): - """Base file list implementation""" - def doScanPaths(self): - raise FileListNotImplemented() - def doAddPaths(self, paths): - for path in paths: - self.doAddPath(path) - def doAddPath(self, path): - raise FileListNotImplemented() - def doStoreCache(self, path): - return False - def getNextRandomImage(self): - raise FileListNotImplemented() - def getPrevRandomImage(self): - raise FileListNotImplemented() - def getCurrentImage(self): - raise FileListNotImplemented() - def attemptCacheLoad(self, filename, rescanPaths = False): - return False - def hasImages(self): - return False - -class RandomFileList(BaseFileList): - def __init__(self): - self.list = [] - self.paths = [] - self.lastImage = None - - def doScanPaths(self): - for path in self.paths: - for dirpath, dirsnames, filenames in os.walk(path): - for filename in filterImageFiles(filenames): - self.list.append(os.path.join(dirpath, filename)) - - def doAddPath(self, path): - self.paths.append(path) - debug('Added path "%s" to the list' % path, DEBUG_LEVEL_DEBUG) - - def doStoreCache(self, filename): - pass - - def getLastImage(self): - return self.lastImage - - def getNextRandomImage(self): - n = random.randint(0, len(self.list)-1) - self.lastImage = self.list[n] - debug("Picked file '%s' from list" % self.lastImage) - return self.lastImage - - def attemptCacheLoad(self, filename, rescanPaths = False): - return False - - def hasImages(self): - return len(self.list) > 0 - - -class AllRandomFileList(BaseFileList): - def __init__(self): - self.list = None - self.paths = [] - self.imagePointer = 0 - - # Scan the input directory, and then randomize the file list - def doScanPaths(self): - debug("Scanning paths", DEBUG_LEVEL_DEBUG) - - self.list = [] - for path in self.paths: - debug('Scanning "%s"' % path, DEBUG_LEVEL_DEBUG) - print os.path.exists(path) - for dirpath, dirsnames, filenames in os.walk(path): - for filename in filterImageFiles(filenames): - debug('Adding file "%s"' % filename, DEBUG_LEVEL_DEBUG - 2*GregDebug.DEBUG_INCREMENT) - self.list.append(os.path.join(dirpath, filename)) - - random.shuffle(self.list) - - def doAddPath(self, path): - self.paths.append(path) - debug('Added path "%s" to the list' % path, DEBUG_LEVEL_DEBUG) - - def doStoreCache(self, filename): - fd = open(filename, 'wb') - cPickle.dump(obj = self, file = fd, protocol = 2) - debug("Cache successfully stored", DEBUG_LEVEL_LOW) - return True - - def getCurrentImage(self): - return self.list[self.imagePointer] - - def __incrementInRange(self, n, amount = 1, rangeMax = None, rangeMin = 0): - if rangeMax == None: rangeMax = len(self.list) - assert rangeMax > 0 - return (n + amount) % rangeMax - - def getNextRandomImage(self): - self.imagePointer = self.__incrementInRange(self.imagePointer) - imageName = self.list[self.imagePointer] - debug("Picked file '%s' (pointer=%d) from list" % (imageName, self.imagePointer)) - return imageName - - def getPrevRandomImage(self): - self.imagePointer = self.__incrementInRange(self.imagePointer, amount=-1) - imageName = self.list[self.imagePointer] - debug("Picked file '%s' (pointer=%d) from list" % (imageName, self.imagePointer)) - return imageName - - def attemptCacheLoad(self, filename, rescanPaths = False): - debug('Attempting to load cache from "%s"' % filename, DEBUG_LEVEL_DEBUG) - self.paths.sort() - try: - return self._attemptCacheLoad(filename) - except Exception, e: - debug("Exception while loading cache: '%s'" % e) - - def _attemptCacheLoad(self, filename): - try: - fd = open(filename, 'rb') - tmp = cPickle.load(fd) - if self.paths == tmp.paths: - debug("Path lists match, copying properties", DEBUG_LEVEL_DEBUG) - # Overwrite this object with the other - for attr in ('list', 'imagePointer'): - setattr(self, attr, getattr(tmp, attr)) - return True - else: - debug("Ignoring cache, path lists do not match", DEBUG_LEVEL_LOW) - return False - except IOError, e: - debug("Exception raised while trying to load cache: '%s'" % e) - return False - - def hasImages(self): - return self.list - -class FolderRandomFileList(BaseFileList): - """A file list that will pick a file randomly within a directory. Each directory - has the same chance of being chosen.""" - def __init__(self): - self.directories = {} - - def doScanPaths(self): - return True # Since it is already done - - def doAddPath(self, path): - debug('Added path "%s" to the list' % path, DEBUG_LEVEL_DEBUG) - for dirpath, dirs, filenames in os.walk(path): - debug('Scanning "%s" for images' % dirpath) - if self.directories.has_key(dirpath): - continue - filenames = filterImageFiles(filenames) - if len(filenames): - self.directories[dirpath] = filenames - debug('Adding "%s" to "%s"' % (filenames, dirpath)) - else: - debug("No images found in '%s'" % dirpath) - - def getNextRandomImage(self): - directory = random.choice(self.directories.keys()) - debug('directory: "%s"' % directory) - filename = random.choice(self.directories[directory]) - debug('filename: "%s"' % filename) - return os.path.join(directory, filename) - - def hasImages(self): - return len(self.directories.values()) diff --git a/lib/WallChanger.py b/lib/WallChanger.py index b7a81ab..efebd50 100644 --- a/lib/WallChanger.py +++ b/lib/WallChanger.py @@ -2,7 +2,6 @@ import commands, sys, os, os.path, subprocess, time from GregDebug import debug, setDebugLevel, DEBUG_LEVEL_DEBUG, DEBUG_LEVEL_LOW, DEBUG_LEVEL_MEDIUM, DEBUG_LEVEL_HIGH, DEBUG_INCREMENT -import FileLists import python24_adapter # NB: Must be imported before collections import collections @@ -58,35 +57,17 @@ def RandomBG(*args, **kwargs): return ret class __BaseChanger(object): - def __init__(self, filelist, backgroundColour='black', permanent=False): + def __init__(self, backgroundColour='black', permanent=False): debug('Determined the window manager is "%s"' % self.__class__.__name__, DEBUG_LEVEL_MEDIUM) self.backgroundColour = backgroundColour self.permanent = permanent - self.filelist = filelist # Used to 'chain' background changers self.nextChanger = None - - def callChained(self, filename): - if self.nextChanger is None: - return True - else: - return self.nextChanger.changeTo(filename) - - def cycleNext(self): - file = self.filelist.getNextRandomImage() - return self.changeTo(file) and self.callChained(file) - - def cyclePrev(self): - file = self.filelist.getPrevRandomImage() - return self.changeTo(file) and self.callChained(file) - def cycleReload(self): - try: - file = self.filelist.getCurrentImage() - return self.changeTo(file) and self.callChained(file) - except FileLists.FileListNotImplemented: - return self.cycleNext() - + def setImage(self, filename): + self._setImage(filename) + if self.nextChanger is not None: + self.nextChange.changeTo(filename) class __WMakerChanger(__BaseChanger): _ConvertedWallpaperLocation = '/tmp/wallpapers_wmaker/' @@ -107,7 +88,8 @@ class __WMakerChanger(__BaseChanger): cmd = ["convert", '-resize', '1280', '-gravity', 'Center', '-crop', '1280x800+0+0', file, output_name] debug("""Convert command: '"%s"'""" % '" "'.join(cmd), DEBUG_LEVEL_DEBUG) return output_name, subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() - def changeTo(self, file): + + def _setImage(self, file): file, convert_status = self._convertImageFormat(file) if convert_status: debug('Convert failed') @@ -170,7 +152,7 @@ class __OSXChanger(__BaseChanger): except ImportError: debug('Could not import the Foundation module, you may have problems with dual screens', DEBUG_LEVEL_MEDIUM) - def changeTo(self, file): + def _setImage(self, file): output_name, ret = self._convertImageFormat(file) if not ret: debug("Convert failed") @@ -181,13 +163,13 @@ class __OSXChanger(__BaseChanger): return not commands.getstatusoutput(cmd)[0] class __GnomeChanger(__BaseChanger): - def changeTo(self, file): + def _setImage(self, file): cmd = ['gconftool-2', '--type', 'string', '--set', '/desktop/gnome/background/picture_filename', file] debug(cmd, DEBUG_LEVEL_DEBUG) return subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() class __KDEChanger(__BaseChanger): - def changeTo(self, file): + def _setImage(self, file): cmds = [] for group in ('Desktop0', 'Desktop0Screen0'): base = ['kwriteconfig', '--file', 'kdesktoprc', '--group', group, '--key'] -- 2.39.2