diff --git a/packaging/osx/lbry-osx-app/.gitignore b/packaging/osx/lbry-osx-app/.gitignore new file mode 100644 index 000000000..bc318a057 --- /dev/null +++ b/packaging/osx/lbry-osx-app/.gitignore @@ -0,0 +1,12 @@ + +*.pyc + +*.pyo + +*.so + +*.xml + +*.iml + +id.conf diff --git a/packaging/osx/lbry-osx-app/app.icns b/packaging/osx/lbry-osx-app/app.icns new file mode 100644 index 000000000..b4d00d2f2 Binary files /dev/null and b/packaging/osx/lbry-osx-app/app.icns differ diff --git a/packaging/osx/lbry-osx-app/build_app.sh b/packaging/osx/lbry-osx-app/build_app.sh new file mode 100755 index 000000000..59828f6b4 --- /dev/null +++ b/packaging/osx/lbry-osx-app/build_app.sh @@ -0,0 +1,63 @@ +dest=`pwd` +tmp="${dest}/build" +id=`cat id.conf` + +rm -rf build dist LBRY.app + +mkdir -p $tmp +cd $tmp + +echo "Updating lbryum" +git clone --depth 1 http://github.com/lbryio/lbryum.git +cd lbryum +python setup.py install &>/dev/null +cd .. +echo "Updating lbrynet" +git clone --depth 1 -b development http://github.com/lbryio/lbry.git +cd lbry +python setup.py install &>/dev/null + +cd $dest +echo "Building URI Handler" +python setup_uri_handler.py py2app &>/dev/null + +echo "Signing URI Handler" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "dist/LBRYURIHandler.app/Contents/Frameworks/Python.framework/Versions/2.7" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "dist/LBRYURIHandler.app/Contents/MacOS/python" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "dist/LBRYURIHandler.app/Contents/MacOS/LBRYURIHandler" +codesign -vvvv "dist/LBRYURIHandler.app" +mv "dist/LBRYURIHandler.app" "LBRYURIHandler.app" +rm -rf build dist + +echo "Building app" +python setup_app.py py2app &>/dev/null + +echo "Moving in correct libgmp" +rm "${dest}/dist/LBRY.app/Contents/Frameworks/libgmp.10.dylib" +cp "${dest}/libgmp.10.dylib" "${dest}/dist/LBRY.app/Contents/Frameworks" + +echo "Removing i386 libraries" + +remove_arch () { + lipo -output build/lipo.tmp -remove "$1" "$2" && mv build/lipo.tmp "$2" +} +for i in dist/LBRY.app/Contents/Resources/lib/python2.7/lib-dynload/* ; do + #remove_arch ppc ${i} + remove_arch i386 ${i} +done + +echo "Moving LBRYURIHandler.app into LBRY.app" +mv "${dest}/LBRYURIHandler.app" "${dest}/dist/LBRY.app/Contents/Resources" + +echo "Signing LBRY.app" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "${dest}/dist/LBRY.app/Contents/Frameworks/Python.framework/Versions/2.7" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "${dest}/dist/LBRY.app/Contents/Frameworks/libgmp.10.dylib" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "${dest}/dist/LBRY.app/Contents/MacOS/python" +codesign -s "Developer ID Application: LBRY Inc (${id})" -f "${dest}/dist/LBRY.app/Contents/MacOS/LBRY" +codesign -vvvv "${dest}/dist/LBRY.app" + +rm -rf $tmp +mv dist/LBRY.app LBRY.app +rm -rf dist + +chown -R ${SUDO_USER} LBRY.app \ No newline at end of file diff --git a/packaging/osx/lbry-osx-app/lbry_uri_handler/LBRYURIHandler.py b/packaging/osx/lbry-osx-app/lbry_uri_handler/LBRYURIHandler.py new file mode 100644 index 000000000..f6990cfea --- /dev/null +++ b/packaging/osx/lbry-osx-app/lbry_uri_handler/LBRYURIHandler.py @@ -0,0 +1,60 @@ +import os +import json +import webbrowser +import subprocess +import sys + +from time import sleep +from jsonrpc.proxy import JSONRPCProxy + +API_CONNECTION_STRING = "http://localhost:5279/lbryapi" +UI_ADDRESS = "http://localhost:5279" + + +class LBRYURIHandler(object): + def __init__(self): + self.started_daemon = False + self.daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) + + def handle_osx(self, lbry_name): + try: + status = self.daemon.is_running() + except: + os.system("open /Applications/LBRY.app") + sleep(3) + + if lbry_name == "lbry" or lbry_name == "": + webbrowser.open(UI_ADDRESS) + else: + webbrowser.open(UI_ADDRESS + "/?watch=" + lbry_name) + + def handle_linux(self, lbry_name): + try: + status = self.daemon.is_running() + except: + cmd = r'DIR = "$( cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )"' \ + r'if [-z "$(pgrep lbrynet-daemon)"]; then' \ + r'echo "running lbrynet-daemon..."' \ + r'$DIR / lbrynet - daemon &' \ + r'sleep 3 # let the daemon load before connecting' \ + r'fi' + subprocess.Popen(cmd, shell=True) + + if lbry_name == "lbry" or lbry_name == "": + webbrowser.open(UI_ADDRESS) + else: + webbrowser.open(UI_ADDRESS + "/?watch=" + lbry_name) + + +def main(args): + if len(args) != 1: + args = ['lbry://lbry'] + + name = args[0][7:] + if sys.platform == "darwin": + LBRYURIHandler().handle_osx(lbry_name=name) + else: + LBRYURIHandler().handle_linux(lbry_name=name) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py new file mode 100644 index 000000000..56f02846f --- /dev/null +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -0,0 +1,77 @@ +import AppKit +import webbrowser +import sys +import logging +import socket +import platform + +from PyObjCTools import AppHelper + +from twisted.internet import reactor +from twisted.web import server + +from lbrynet.lbrynet_daemon.LBRYDaemonServer import LBRYDaemonServer +from lbrynet.conf import API_PORT, API_INTERFACE, ICON_PATH, APP_NAME +from lbrynet.conf import UI_ADDRESS + +if platform.mac_ver()[0] >= "10.10": + from LBRYNotify import LBRYNotify + +log = logging.getLogger(__name__) + +REMOTE_SERVER = "www.google.com" + + +def test_internet_connection(): + try: + host = socket.gethostbyname(REMOTE_SERVER) + s = socket.create_connection((host, 80), 2) + return True + except: + return False + + +class LBRYDaemonApp(AppKit.NSApplication): + def finishLaunching(self): + self.connection = False + statusbar = AppKit.NSStatusBar.systemStatusBar() + self.statusitem = statusbar.statusItemWithLength_(AppKit.NSVariableStatusItemLength) + self.icon = AppKit.NSImage.alloc().initByReferencingFile_(ICON_PATH) + self.icon.setScalesWhenResized_(True) + self.icon.setSize_((20, 20)) + self.statusitem.setImage_(self.icon) + self.menubarMenu = AppKit.NSMenu.alloc().init() + self.open = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Open", "openui:", "") + self.menubarMenu.addItem_(self.open) + self.quit = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Quit", "replyToApplicationShouldTerminate:", "") + self.menubarMenu.addItem_(self.quit) + self.statusitem.setMenu_(self.menubarMenu) + self.statusitem.setToolTip_(APP_NAME) + + + if test_internet_connection(): + if platform.mac_ver()[0] >= "10.10": + LBRYNotify("Starting LBRY") + else: + if platform.mac_ver()[0] >= "10.10": + LBRYNotify("LBRY needs an internet connection to start, try again when one is available") + sys.exit(0) + + # if not subprocess.check_output("git ls-remote https://github.com/lbryio/lbry-web-ui.git | grep HEAD | cut -f 1", + # shell=True): + # LBRYNotify( + # "You should have been prompted to install xcode command line tools, please do so and then start LBRY") + # sys.exit(0) + + lbry = LBRYDaemonServer() + d = lbry.start() + d.addCallback(lambda _: webbrowser.open(UI_ADDRESS)) + reactor.listenTCP(API_PORT, server.Site(lbry.root), interface=API_INTERFACE) + + def openui_(self, sender): + webbrowser.open(UI_ADDRESS) + + def replyToApplicationShouldTerminate_(self, shouldTerminate): + if platform.mac_ver()[0] >= "10.10": + LBRYNotify("Goodbye!") + reactor.stop() diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYNotify.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYNotify.py new file mode 100644 index 000000000..d4a88e7ce --- /dev/null +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYNotify.py @@ -0,0 +1,27 @@ +import Foundation +import objc +import AppKit + +NSUserNotification = objc.lookUpClass('NSUserNotification') +NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter') + +def LBRYNotify(message): + notification = NSUserNotification.alloc().init() + notification.setTitle_("LBRY") + notification.setSubtitle_("") + notification.setInformativeText_(message) + notification.setUserInfo_({}) + notification.setSoundName_("NSUserNotificationDefaultSoundName") + notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(0, Foundation.NSDate.date())) + NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification) + +def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}): + notification = NSUserNotification.alloc().init() + notification.setTitle_(title) + notification.setSubtitle_(subtitle) + notification.setInformativeText_(info_text) + notification.setUserInfo_(userInfo) + if sound: + notification.setSoundName_("NSUserNotificationDefaultSoundName") + notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(delay, Foundation.NSDate.date())) + NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification) \ No newline at end of file diff --git a/packaging/osx/lbry-osx-app/lbrygui/__init__.py b/packaging/osx/lbry-osx-app/lbrygui/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packaging/osx/lbry-osx-app/lbrygui/app.icns b/packaging/osx/lbry-osx-app/lbrygui/app.icns new file mode 100644 index 000000000..b4d00d2f2 Binary files /dev/null and b/packaging/osx/lbry-osx-app/lbrygui/app.icns differ diff --git a/packaging/osx/lbry-osx-app/lbrygui/main.py b/packaging/osx/lbry-osx-app/lbrygui/main.py new file mode 100644 index 000000000..d7ca4dc00 --- /dev/null +++ b/packaging/osx/lbry-osx-app/lbrygui/main.py @@ -0,0 +1,35 @@ +from PyObjCTools import AppHelper +from twisted.internet.cfreactor import install +install(runner=AppHelper.runEventLoop) +from twisted.internet import reactor + +import logging +import sys +import os +from appdirs import user_data_dir + +from LBRYApp import LBRYDaemonApp + +if sys.platform != "darwin": + log_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") +else: + log_dir = user_data_dir("LBRY") + +if not os.path.isdir(log_dir): + os.mkdir(log_dir) + +LOG_FILENAME = os.path.join(log_dir, 'lbrynet-daemon.log') + +log = logging.getLogger(__name__) +handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=2097152, backupCount=5) +log.addHandler(handler) +logging.basicConfig(level=logging.INFO) + + +def main(): + app = LBRYDaemonApp.sharedApplication() + reactor.addSystemEventTrigger("after", "shutdown", AppHelper.stopEventLoop) + reactor.run() + +if __name__ == "__main__": + main() diff --git a/packaging/osx/lbry-osx-app/libgmp.10.dylib b/packaging/osx/lbry-osx-app/libgmp.10.dylib new file mode 100755 index 000000000..09f809987 Binary files /dev/null and b/packaging/osx/lbry-osx-app/libgmp.10.dylib differ diff --git a/packaging/osx/lbry-osx-app/setup_app.py b/packaging/osx/lbry-osx-app/setup_app.py new file mode 100644 index 000000000..f6d2a9145 --- /dev/null +++ b/packaging/osx/lbry-osx-app/setup_app.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +from lbrynet.conf import PROTOCOL_PREFIX, APP_NAME, ICON_PATH +import sys + +APP = [os.path.join('lbrygui', 'main.py')] +DATA_FILES = [] +DATA_FILES.append('app.icns') + +OPTIONS = { + # 'argv_emulation': True, + 'iconfile': ICON_PATH, + 'plist': { + 'CFBundleIdentifier': 'io.lbry.LBRY', + 'LSUIElement': True, + }, + 'packages': ['lbrynet', 'lbryum', 'requests', 'unqlite', 'certifi', + 'pkg_resources', 'json', 'jsonrpc', 'seccure',], +} + + +setup( + name=APP_NAME, + app=APP, + options={'py2app': OPTIONS}, + data_files=DATA_FILES, +) \ No newline at end of file diff --git a/packaging/osx/lbry-osx-app/setup_app.sh b/packaging/osx/lbry-osx-app/setup_app.sh new file mode 100755 index 000000000..d4141326a --- /dev/null +++ b/packaging/osx/lbry-osx-app/setup_app.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +set -o errexit +set -o xtrace + +dest=`pwd` +tmp="${dest}/build" + +rm -rf build dist LBRY.app + +mkdir -p $tmp +cd $tmp + +echo "Updating lbrynet" +if [ -z ${TRAVIS_BUILD_DIR+x} ]; then + # building locally + git clone --depth 1 http://github.com/lbryio/lbry.git + cd lbry + LBRY="${tmp}/lbry" +else + # building on travis + cd ${TRAVIS_BUILD_DIR} + LBRY=${TRAVIS_BUILD_DIR} +fi +python setup.py install +echo "Building URI Handler" +rm -rf build dist +python setup_uri_handler.py py2app + +echo "Signing URI Handler" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${LBRY}/dist/LBRYURIHandler.app/Contents/Frameworks/Python.framework/Versions/2.7" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${LBRY}/dist/LBRYURIHandler.app/Contents/MacOS/python" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${LBRY}/dist/LBRYURIHandler.app/Contents/MacOS/LBRYURIHandler" +codesign -vvvv "${LBRY}/dist/LBRYURIHandler.app" + +cd $dest +python setup.py py2app &>/dev/null + +echo "Moving in correct libgmp" +rm "${dest}/dist/LBRY.app/Contents/Frameworks/libgmp.10.dylib" +cp "${dest}/libgmp.10.dylib" "${dest}/dist/LBRY.app/Contents/Frameworks" + +echo "Removing i386 libraries" + +remove_arch () { + lipo -output build/lipo.tmp -remove "$1" "$2" && mv build/lipo.tmp "$2" +} +for i in dist/LBRY.app/Contents/Resources/lib/python2.7/lib-dynload/* ; do + remove_arch i386 ${i} +done + +echo "Moving LBRYURIHandler.app into LBRY.app" +mv "${LBRY}/dist/LBRYURIHandler.app" "${dest}/dist/LBRY.app/Contents/Resources" + +echo "Signing LBRY.app" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${dest}/dist/LBRY.app/Contents/Frameworks/Python.framework/Versions/2.7" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${dest}/dist/LBRY.app/Contents/Frameworks/libgmp.10.dylib" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${dest}/dist/LBRY.app/Contents/MacOS/python" +codesign -s "${LBRY_DEVELOPER_ID}" -f "${dest}/dist/LBRY.app/Contents/MacOS/LBRY" +codesign -vvvv "${dest}/dist/LBRY.app" + +rm -rf $tmp +mv dist/LBRY.app LBRY.app +rm -rf dist diff --git a/packaging/osx/lbry-osx-app/setup_uri_handler.py b/packaging/osx/lbry-osx-app/setup_uri_handler.py new file mode 100644 index 000000000..26097d8a4 --- /dev/null +++ b/packaging/osx/lbry-osx-app/setup_uri_handler.py @@ -0,0 +1,25 @@ +from setuptools import setup +import os + +APP = [os.path.join('lbry_uri_handler', 'LBRYURIHandler.py')] +DATA_FILES = [] +OPTIONS = {'argv_emulation': True, + 'packages': ['jsonrpc'], + 'plist': { + 'LSUIElement': True, + 'CFBundleIdentifier': 'io.lbry.LBRYURIHandler', + 'CFBundleURLTypes': [ + { + 'CFBundleURLTypes': 'LBRYURIHandler', + 'CFBundleURLSchemes': ['lbry'] + } + ] + } + } + +setup( + app=APP, + data_files=DATA_FILES, + options={'py2app': OPTIONS}, + setup_requires=['py2app'], +) \ No newline at end of file