11 changed files with 429 additions and 3 deletions
@ -0,0 +1,241 @@ |
|||
from esky.util import appdir_from_executable #@UnresolvedImport |
|||
from threading import Thread |
|||
from version import VERSION |
|||
from wx.lib.softwareupdate import SoftwareUpdate |
|||
import os |
|||
import sys |
|||
import time |
|||
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__))) |
|||
else: |
|||
base_path = os.path.dirname(os.path.abspath(__file__)) |
|||
|
|||
def icon(): |
|||
icon = 'icon_windows.png' |
|||
if os.path.isfile('icon_mac.png'): |
|||
icon = 'icon_mac.png' |
|||
|
|||
return wx.Icon(icon, wx.BITMAP_TYPE_PNG) |
|||
|
|||
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_EXIT = wx.ID_EXIT |
|||
|
|||
closed = False |
|||
menu = False |
|||
enabled = False |
|||
|
|||
def __init__(self, frame): |
|||
wx.TaskBarIcon.__init__(self) |
|||
self.frame = frame |
|||
|
|||
self.SetIcon(icon()) |
|||
|
|||
self.Bind(wx.EVT_TASKBAR_LEFT_UP, self.OnTaskBarClick) |
|||
self.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnTaskBarClick) |
|||
|
|||
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.onTaskBarClose, id = self.TBMENU_EXIT) |
|||
|
|||
def OnTaskBarClick(self, evt): |
|||
menu = self.CreatePopupMenu() |
|||
self.PopupMenu(menu) |
|||
menu.Destroy() |
|||
|
|||
def enable(self): |
|||
self.enabled = True |
|||
|
|||
if self.menu: |
|||
self.open_menu.Enable(True) |
|||
self.setting_menu.Enable(True) |
|||
|
|||
self.open_menu.SetText('Open') |
|||
|
|||
def CreatePopupMenu(self): |
|||
|
|||
if not self.menu: |
|||
self.menu = wx.Menu() |
|||
self.open_menu = self.menu.Append(self.TBMENU_OPEN, 'Open') |
|||
self.setting_menu = self.menu.Append(self.TBMENU_SETTINGS, 'About') |
|||
self.exit_menu = self.menu.Append(self.TBMENU_EXIT, 'Quit') |
|||
|
|||
if not self.enabled: |
|||
self.open_menu.Enable(False) |
|||
self.setting_menu.Enable(False) |
|||
|
|||
self.open_menu.SetText('Loading...') |
|||
|
|||
return self.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/about/' |
|||
webbrowser.open(url) |
|||
|
|||
def onTaskBarClose(self, evt): |
|||
if self.closed: |
|||
return |
|||
|
|||
self.closed = True |
|||
|
|||
self.RemoveIcon() |
|||
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, style = wx.FRAME_NO_TASKBAR) |
|||
|
|||
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 = ['--quiet'] |
|||
self.options = getOptions(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() |
|||
self._desktop.ExitMainLoop() |
|||
|
|||
|
|||
class CouchPotatoApp(wx.App, SoftwareUpdate): |
|||
|
|||
settings = {} |
|||
events = {} |
|||
restart = False |
|||
closing = False |
|||
triggered_onClose = False |
|||
|
|||
def OnInit(self): |
|||
|
|||
# Updater |
|||
base_url = 'https://api.couchpota.to/updates/%s' |
|||
self.InitUpdates(base_url % VERSION + '/', 'https://couchpota.to/updates/%s' % 'changelog.html', |
|||
icon = icon()) |
|||
|
|||
self.frame = MainFrame(self) |
|||
self.frame.Bind(wx.EVT_CLOSE, self.onClose) |
|||
|
|||
# CouchPotato thread |
|||
self.worker = WorkerThread(self) |
|||
|
|||
return True |
|||
|
|||
def onAppLoad(self): |
|||
self.frame.tbicon.enable() |
|||
|
|||
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): |
|||
|
|||
if not self.closing: |
|||
self.closing = True |
|||
self.frame.tbicon.onTaskBarClose(event) |
|||
|
|||
onClose = self.events.get('onClose') |
|||
if onClose and not self.triggered_onClose: |
|||
self.triggered_onClose = True |
|||
onClose(event) |
|||
|
|||
def afterShutdown(self, restart = False): |
|||
self.frame.Destroy() |
|||
self.restart = restart |
|||
self.ExitMainLoop() |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
|
|||
app = CouchPotatoApp(redirect = False) |
|||
app.MainLoop() |
|||
|
|||
time.sleep(1) |
|||
|
|||
if app.restart: |
|||
|
|||
def appexe_from_executable(exepath): |
|||
appdir = appdir_from_executable(exepath) |
|||
exename = os.path.basename(exepath) |
|||
|
|||
if sys.platform == "darwin": |
|||
if os.path.isdir(os.path.join(appdir, "Contents", "MacOS")): |
|||
return os.path.join(appdir, "Contents", "MacOS", exename) |
|||
|
|||
return os.path.join(appdir, exename) |
|||
|
|||
exe = appexe_from_executable(sys.executable) |
|||
os.chdir(os.path.dirname(exe)) |
|||
|
|||
os.execv(exe, [exe] + sys.argv[1:]) |
Binary file not shown.
After Width: | Height: | Size: 345 KiB |
After Width: | Height: | Size: 435 B |
After Width: | Height: | Size: 367 B |
@ -0,0 +1,52 @@ |
|||
#define MyAppName "CouchPotato" |
|||
#define MyAppVer "2.6.1" |
|||
#define MyAppBit "win32" |
|||
//#define MyAppBit "win-amd64" |
|||
|
|||
[Setup] |
|||
AppName={#MyAppName} |
|||
AppVersion=2 |
|||
AppVerName={#MyAppName} |
|||
DefaultDirName={userappdata}\{#MyAppName}\application |
|||
DisableProgramGroupPage=yes |
|||
DisableDirPage=yes |
|||
UninstallDisplayIcon=./icon.ico |
|||
SetupIconFile=./icon.ico |
|||
OutputDir=./dist |
|||
OutputBaseFilename={#MyAppName}-{#MyAppVer}.{#MyAppBit}.installer |
|||
AppPublisher=Your Mom |
|||
AppPublisherURL=http://couchpota.to |
|||
PrivilegesRequired=none |
|||
WizardSmallImageFile=installer_icon.bmp |
|||
WizardImageFile=installer_banner.bmp |
|||
UsePreviousAppDir=no |
|||
|
|||
[Messages] |
|||
WelcomeLabel1=Installing [name]! |
|||
WelcomeLabel2=This wizard will install [name] to your AppData folder. It does this so it can use the build in updater without needing admin rights. |
|||
|
|||
[CustomMessages] |
|||
LaunchProgram=Launch {#MyAppName} right now. |
|||
|
|||
[Files] |
|||
Source: "./dist/{#MyAppName}-{#MyAppVer}.{#MyAppBit}/*"; Flags: recursesubdirs; DestDir: "{app}" |
|||
|
|||
[Icons] |
|||
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppName}.exe" |
|||
Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppName}.exe"; Tasks: startup |
|||
|
|||
[Tasks] |
|||
Name: "startup"; Description: "Run {#MyAppName} at startup"; Flags: unchecked |
|||
|
|||
[Run] |
|||
Filename: {app}\{#MyAppName}.exe; Description: {cm:LaunchProgram,{#MyAppName}}; Flags: nowait postinstall skipifsilent |
|||
|
|||
|
|||
[UninstallDelete] |
|||
Type: filesandordirs; Name: "{app}\appdata" |
|||
Type: filesandordirs; Name: "{app}\Microsoft.VC90.CRT" |
|||
Type: filesandordirs; Name: "{app}\updates" |
|||
Type: filesandordirs; Name: "{app}\CouchPotato*" |
|||
Type: filesandordirs; Name: "{app}\python27.dll" |
|||
Type: filesandordirs; Name: "{app}\unins000.dat" |
|||
Type: filesandordirs; Name: "{app}\unins000.exe" |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 9.6 KiB |
@ -0,0 +1,133 @@ |
|||
from esky import bdist_esky |
|||
from setuptools import setup |
|||
import os |
|||
import sys |
|||
import version |
|||
|
|||
|
|||
# Include proper dirs |
|||
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) |
|||
|
|||
def getDataFiles(dirs): |
|||
data_files = [] |
|||
for directory in dirs: |
|||
for root, dirs, files in os.walk(directory): |
|||
if files: |
|||
for filename in files: |
|||
if filename[:-4] is not '.pyc': |
|||
data_files.append((root, [os.path.join(root, filename)])) |
|||
|
|||
return data_files |
|||
|
|||
includes = [ |
|||
'telnetlib', |
|||
'xml.etree.ElementTree', |
|||
'xml.etree.cElementTree', |
|||
'xml.dom', |
|||
'xml.dom.minidom', |
|||
'netrc', |
|||
'csv', |
|||
'HTMLParser', |
|||
'version', |
|||
'distutils', |
|||
'lxml', 'lxml.etree', 'lxml._elementpath', 'gzip', |
|||
] |
|||
|
|||
excludes = [ |
|||
'doctest', |
|||
'pdb', |
|||
'unittest', |
|||
'difflib', |
|||
'bsddb', |
|||
'pywin.debugger', 'pywin.debugger.dbgcon', 'pywin.dialogs', |
|||
'Tkconstants', 'Tkinter', |
|||
'curses', |
|||
'_gtkagg', '_tkagg', |
|||
] |
|||
|
|||
# Windows |
|||
if sys.platform == "win32": |
|||
import py2exe |
|||
|
|||
sys.path.append('C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.21022.8_none_bcb86ed6ac711f91') |
|||
|
|||
FREEZER = 'py2exe' |
|||
FREEZER_OPTIONS = dict( |
|||
compressed = 0, |
|||
bundle_files = 3, |
|||
dll_excludes = [ |
|||
'msvcp90.dll', |
|||
'msvcr90.dll', |
|||
'msvcr71.dll', |
|||
'mswsock.dll', |
|||
'powrprof.dll', |
|||
'USP10.dll', |
|||
'libgdk-win32-2.0-0.dll', |
|||
'libgobject-2.0-0.dll', |
|||
'tcl84.dll', |
|||
'tk84.dll' |
|||
], |
|||
packages = ['couchpotato', 'libs'], |
|||
includes = includes, |
|||
excludes = excludes, |
|||
skip_archive = 1, |
|||
) |
|||
exeICON = os.path.join(base_path, 'icon.ico') |
|||
DATA_FILES = getDataFiles([r'.\\couchpotato', r'.\\libs']) |
|||
DATA_FILES.append('icon_windows.png') |
|||
file_ext = 'win32.zip' |
|||
|
|||
|
|||
# OSX |
|||
elif sys.platform == "darwin": |
|||
import py2app |
|||
|
|||
FREEZER = 'py2app' |
|||
FREEZER_OPTIONS = dict( |
|||
arch = 'intel', |
|||
optimize = 2, |
|||
strip = True, |
|||
argv_emulation = False, |
|||
site_packages = False, |
|||
iconfile = 'icon.icns', |
|||
plist = dict( |
|||
LSUIElement = True, |
|||
), |
|||
packages = ['couchpotato', 'libs'], |
|||
includes = includes, |
|||
excludes = excludes, |
|||
) |
|||
exeICON = None |
|||
DATA_FILES = ['icon_mac.png'] |
|||
|
|||
file_ext = 'macosx-10_6-intel.zip' |
|||
|
|||
# Common |
|||
NAME = "CouchPotato" |
|||
APP = [bdist_esky.Executable("Desktop.py", name = NAME, icon = exeICON, gui_only = True,)] |
|||
ESKY_OPTIONS = dict( |
|||
freezer_module = FREEZER, |
|||
freezer_options = FREEZER_OPTIONS, |
|||
bundle_msvcrt = True, |
|||
) |
|||
|
|||
# Build the app and the esky bundle |
|||
setup( |
|||
name = NAME, |
|||
scripts = APP, |
|||
version = version.VERSION, |
|||
author = "Ruud", |
|||
author_email = "info@couchpota.to", |
|||
description = 'CouchPotato %s' % version.VERSION, |
|||
data_files = DATA_FILES, |
|||
options = dict(bdist_esky = ESKY_OPTIONS), |
|||
) |
|||
|
|||
#distpath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'dist') |
|||
#zipfilename = os.path.join(distpath, '%s-%s.%s' % (NAME, version.VERSION, file_ext)) |
|||
#zfile = zipfile.ZipFile(zipfilename, "r") |
|||
#zfile.extractall(distpath) |
@ -1,2 +1,2 @@ |
|||
VERSION = None |
|||
BRANCH = 'master' |
|||
VERSION = '2.6.1' |
|||
BRANCH = 'desktop' |
|||
|
Loading…
Reference in new issue