diff --git a/CouchPotato.py b/CouchPotato.py index a07f235c..88ba3436 100644 --- a/CouchPotato.py +++ b/CouchPotato.py @@ -1,167 +1,127 @@ -from threading import Thread -from wx.lib.softwareupdate import SoftwareUpdate +#!/usr/bin/env python +from logging import handlers +from os.path import dirname +import logging import os +import signal +import subprocess import sys -import webbrowser -import wx - - -# Include proper dirs -if hasattr(sys, 'frozen'): - import libs - base_path = os.path.dirname(os.path.dirname(os.path.abspath(libs.__file__))) - print base_path -else: - base_path = os.path.dirname(os.path.abspath(__file__)) - -lib_dir = os.path.join(base_path, 'libs') - -sys.path.insert(0, base_path) -sys.path.insert(0, lib_dir) - -# Get options via arg -from couchpotato.runner import getOptions -from couchpotato.runner import runCouchPotato - - -class TaskBarIcon(wx.TaskBarIcon): - - TBMENU_OPEN = wx.NewId() - TBMENU_SETTINGS = wx.NewId() - TBMENU_ABOUT = wx.ID_ABOUT - TBMENU_EXIT = wx.ID_EXIT - - def __init__(self, frame): - wx.TaskBarIcon.__init__(self) - self.frame = frame - - icon = wx.Icon('icon.ico', wx.BITMAP_TYPE_ANY) - self.SetIcon(icon) - - self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.onTaskBarActivate) - - self.Bind(wx.EVT_MENU, self.onOpen, id = self.TBMENU_OPEN) - self.Bind(wx.EVT_MENU, self.onSettings, id = self.TBMENU_SETTINGS) - self.Bind(wx.EVT_MENU, self.onAbout, id = self.TBMENU_ABOUT) - self.Bind(wx.EVT_MENU, self.onTaskBarClose, id = self.TBMENU_EXIT) - - - def CreatePopupMenu(self): - menu = wx.Menu() - menu.Append(self.TBMENU_OPEN, "Open") - menu.Append(self.TBMENU_SETTINGS, "Settings") - menu.Append(self.TBMENU_ABOUT, "About") - menu.Append(self.TBMENU_EXIT, "Close") - return menu - - def onOpen(self, event): - url = self.frame.parent.getSetting('base_url') - webbrowser.open(url) - - def onSettings(self, event): - url = self.frame.parent.getSetting('base_url') + '/settings/' - webbrowser.open(url) - - def onAbout(self, event): - print 'onAbout' - - def onTaskBarActivate(self, evt): - if not self.frame.IsShown(): - self.frame.Show(True) - self.frame.Raise() - - def onTaskBarClose(self, evt): - wx.CallAfter(self.frame.Close) - - def makeIcon(self, img): - if "wxMSW" in wx.PlatformInfo: - img = img.Scale(16, 16) - elif "wxGTK" in wx.PlatformInfo: - img = img.Scale(22, 22) - - icon = wx.IconFromBitmap(img.CopyFromBitmap()) - return icon - - -class MainFrame(wx.Frame): - - def __init__(self, parent): - wx.Frame.__init__(self, None) - - self.parent = parent - self.tbicon = TaskBarIcon(self) - - -class WorkerThread(Thread): - - def __init__(self, desktop): - Thread.__init__(self) - self._desktop = desktop - - self.start() - - def run(self): - - args = ['--nogit', '--console_log']#, '--quiet'] - options = getOptions(base_path, args) - - try: - runCouchPotato(options, base_path, args, desktop = self._desktop) - except KeyboardInterrupt, e: - raise - except Exception, e: - raise - finally: - pass - - -class CouchPotatoApp(wx.App, SoftwareUpdate): - - settings = {} - events = {} - restart = False - - def OnInit(self): - - # Updater - base_url = 'http://couchpotatoapp.com/updates/' - self.InitUpdates(base_url, base_url + 'changelog.txt', - icon = wx.Icon('icon.ico')) - - self.frame = MainFrame(self) - self.frame.Bind(wx.EVT_CLOSE, self.onClose) - - # CouchPotato thread - self.worker = WorkerThread(self) - - return True - - def setSettings(self, settings = {}): - self.settings = settings - - def getSetting(self, name): - return self.settings.get(name) - - def addEvents(self, events = {}): - for name in events.iterkeys(): - self.events[name] = events[name] - - def onClose(self, event): - onClose = self.events.get('onClose') - if self.events.get('onClose'): - onClose(event) - else: - self.afterShutdown() - - def afterShutdown(self, restart = False): - self.frame.Destroy() - self.restart = restart - - +import traceback +  +  +# Root path +base_path = dirname(os.path.abspath(__file__)) +  +# Insert local directories into path +sys.path.insert(0, os.path.join(base_path, 'libs')) +  +from couchpotato.environment import Env +from couchpotato.core.helpers.variable import getDataDir +  +class Loader(object): +  +    do_restart = False +  +    def __init__(self): +  +        # Get options via arg +        from couchpotato.runner import getOptions +        self.options = getOptions(base_path, sys.argv[1:]) +  +        # Load settings +        settings = Env.get('settings') +        settings.setFile(self.options.config_file) +  +        # Create data dir if needed +        self.data_dir = os.path.expanduser(Env.setting('data_dir')) +        if self.data_dir == '': +            self.data_dir = getDataDir() +  +        if not os.path.isdir(self.data_dir): +            os.makedirs(self.data_dir) +  +        # Create logging dir +        self.log_dir = os.path.join(self.data_dir, 'logs'); +        if not os.path.isdir(self.log_dir): +            os.mkdir(self.log_dir) +  +        # Logging +        from couchpotato.core.logger import CPLog +        self.log = CPLog(__name__) +  +        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S') +        hdlr = handlers.RotatingFileHandler(os.path.join(self.log_dir, 'error.log'), 'a', 500000, 10) +        hdlr.setLevel(logging.CRITICAL) +        hdlr.setFormatter(formatter) +        self.log.logger.addHandler(hdlr) +  +    def addSignals(self): +  +        signal.signal(signal.SIGINT, self.onExit) +        signal.signal(signal.SIGTERM, lambda signum, stack_frame: sys.exit(1)) +  +        from couchpotato.core.event import addEvent +        addEvent('app.after_shutdown', self.afterShutdown) +  +    def afterShutdown(self, restart): +        self.do_restart = restart +  +    def onExit(self, signal, frame): +        from couchpotato.core.event import fireEvent +        fireEvent('app.crappy_shutdown', single = True) +  +    def run(self): +  +        self.addSignals() +  +        from couchpotato.runner import runCouchPotato +        runCouchPotato(self.options, base_path, sys.argv[1:], data_dir = self.data_dir, log_dir = self.log_dir, Env = Env) +  +        if self.do_restart: +            self.restart() +  +    def restart(self): +        try: +            # remove old pidfile first +            try: +                if self.runAsDaemon(): +                    self.daemon.delpid() +            except: +                self.log.critical(traceback.format_exc()) +  +            args = [sys.executable] + [os.path.join(base_path, __file__)] + sys.argv[1:] +            subprocess.Popen(args) +        except: +            self.log.critical(traceback.format_exc()) +  +    def daemonize(self): +  +        if self.runAsDaemon(): +            try: +                from daemon import Daemon +                self.daemon = Daemon(self.options.pid_file) +                self.daemon.daemonize() +            except SystemExit: +                raise +            except: +                self.log.critical(traceback.format_exc()) +  +    def runAsDaemon(self): +        return self.options.daemon and  self.options.pid_file +  +  if __name__ == '__main__': - app = CouchPotatoApp(redirect = False) - app.MainLoop() - - #path = os.path.join(sys.path[0].decode(sys.getfilesystemencoding()), sys.argv[0]) - #if app.restart: - # wx.Process.Open(sys.executable + ' ' + path) +    try: +        l = Loader() +        l.daemonize() +        l.run() +    except KeyboardInterrupt: +        pass +    except SystemExit: +        raise +    except Exception as (nr, msg): +        if nr != 4: +            try: +                l.log.critical(traceback.format_exc()) +            except: +                print traceback.format_exc() diff --git a/Desktop.py b/Desktop.py new file mode 100644 index 00000000..2d533e98 --- /dev/null +++ b/Desktop.py @@ -0,0 +1,188 @@ +from threading import Thread +from wx.lib.softwareupdate import SoftwareUpdate +import os +import sys +import webbrowser +import wx + + +# Include proper dirs +if hasattr(sys, 'frozen'): + import libs + base_path = os.path.dirname(os.path.dirname(os.path.abspath(libs.__file__))) + print base_path +else: + base_path = os.path.dirname(os.path.abspath(__file__)) + +lib_dir = os.path.join(base_path, 'libs') + +sys.path.insert(0, base_path) +sys.path.insert(0, lib_dir) + +from couchpotato.environment import Env + +class TaskBarIcon(wx.TaskBarIcon): + + TBMENU_OPEN = wx.NewId() + TBMENU_SETTINGS = wx.NewId() + TBMENU_ABOUT = wx.ID_ABOUT + TBMENU_EXIT = wx.ID_EXIT + + def __init__(self, frame): + wx.TaskBarIcon.__init__(self) + self.frame = frame + + icon = wx.Icon('icon.ico', wx.BITMAP_TYPE_ANY) + self.SetIcon(icon) + + self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.onTaskBarActivate) + + self.Bind(wx.EVT_MENU, self.onOpen, id = self.TBMENU_OPEN) + self.Bind(wx.EVT_MENU, self.onSettings, id = self.TBMENU_SETTINGS) + self.Bind(wx.EVT_MENU, self.onAbout, id = self.TBMENU_ABOUT) + self.Bind(wx.EVT_MENU, self.onTaskBarClose, id = self.TBMENU_EXIT) + + + def CreatePopupMenu(self): + menu = wx.Menu() + menu.Append(self.TBMENU_OPEN, "Open") + menu.Append(self.TBMENU_SETTINGS, "Settings") + menu.Append(self.TBMENU_ABOUT, "About") + menu.Append(self.TBMENU_EXIT, "Close") + return menu + + def onOpen(self, event): + url = self.frame.parent.getSetting('base_url') + webbrowser.open(url) + + def onSettings(self, event): + url = self.frame.parent.getSetting('base_url') + '/settings/' + webbrowser.open(url) + + def onAbout(self, event): + print 'onAbout' + + def onTaskBarActivate(self, evt): + if not self.frame.IsShown(): + self.frame.Show(True) + self.frame.Raise() + + def onTaskBarClose(self, evt): + wx.CallAfter(self.frame.Close) + + def makeIcon(self, img): + if "wxMSW" in wx.PlatformInfo: + img = img.Scale(16, 16) + elif "wxGTK" in wx.PlatformInfo: + img = img.Scale(22, 22) + + icon = wx.IconFromBitmap(img.CopyFromBitmap()) + return icon + + +class MainFrame(wx.Frame): + + def __init__(self, parent): + wx.Frame.__init__(self, None) + + self.parent = parent + self.tbicon = TaskBarIcon(self) + + +class WorkerThread(Thread): + + def __init__(self, desktop): + Thread.__init__(self) + self.daemon = True + self._desktop = desktop + + self.start() + + def run(self): + + # Get options via arg + from couchpotato.runner import getOptions + args = ['--nogit', '--console_log'] + self.options = getOptions(base_path, args) + + # Load settings + settings = Env.get('settings') + settings.setFile(self.options.config_file) + + # Create data dir if needed + self.data_dir = os.path.expanduser(Env.setting('data_dir')) + if self.data_dir == '': + from couchpotato.core.helpers.variable import getDataDir + self.data_dir = getDataDir() + + if not os.path.isdir(self.data_dir): + os.makedirs(self.data_dir) + + # Create logging dir + self.log_dir = os.path.join(self.data_dir, 'logs'); + if not os.path.isdir(self.log_dir): + os.mkdir(self.log_dir) + + try: + from couchpotato.runner import runCouchPotato + runCouchPotato(self.options, base_path, args, data_dir = self.data_dir, log_dir = self.log_dir, Env = Env, desktop = self._desktop) + except: + pass + + self._desktop.frame.Close() + + +class CouchPotatoApp(wx.App, SoftwareUpdate): + + settings = {} + events = {} + restart = False + + def OnInit(self): + + # Updater + base_url = 'http://localhost/updates/' + self.InitUpdates(base_url, base_url + 'changelog.txt', + icon = wx.Icon('icon.ico')) + + self.frame = MainFrame(self) + self.frame.Bind(wx.EVT_CLOSE, self.onClose) + + # CouchPotato thread + self.worker = WorkerThread(self) + + return True + + def setSettings(self, settings = {}): + self.settings = settings + + def getSetting(self, name): + return self.settings.get(name) + + def addEvents(self, events = {}): + for name in events.iterkeys(): + self.events[name] = events[name] + + def onClose(self, event): + + onClose = self.events.get('onClose') + if self.events.get('onClose'): + onClose(event) + else: + self.afterShutdown() + + def afterShutdown(self, restart = False): + self.frame.Destroy() + self.restart = restart + + self.ExitMainLoop() + + +if __name__ == '__main__': + app = CouchPotatoApp(redirect = False) + app.MainLoop() + + path = os.path.join(sys.path[0].decode(sys.getfilesystemencoding()), sys.argv[0]) + if app.restart: + pass + #wx.Process.Open(path) diff --git a/setup.py b/setup.py index c505c6b1..a4b0661c 100644 --- a/setup.py +++ b/setup.py @@ -65,7 +65,7 @@ elif sys.platform == "darwin": # Common NAME = "CouchPotato" -APP = [bdist_esky.Executable("CouchPotato.py", gui_only = True, icon = exeICON,)] +APP = [bdist_esky.Executable("Desktop.py", name = NAME, gui_only = True, icon = exeICON,)] DATA_FILES = ['icon.ico'] ESKY_OPTIONS = dict( freezer_module = FREEZER,