X-Git-Url: https://code.delx.au/bg-scripts/blobdiff_plain/f71c2fbef0d1f0f7b4957ebc68f5639a533fec1a..7e127c3969ded9ace8f056c5f3e47d070ff17179:/bin/randombg.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: