mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-21 19:07:44 +01:00
MacOS Notifications
replaced unreliable method
This commit is contained in:
@@ -1145,18 +1145,9 @@
|
||||
|
||||
<fieldset>
|
||||
<div class="row checkbox left">
|
||||
<input type="checkbox" class="bigcheck" name="osx_notify_enabled" id="osx_notify" value="1" ${config['osx_notify_enabled']} /><label for="osx_notify"><span class="option">OS X</span></label>
|
||||
<input type="checkbox" class="bigcheck" name="osx_notify_enabled" id="osx_notify" value="1" ${config['osx_notify_enabled']} /><label for="osx_notify"><span class="option">MacOS</span></label>
|
||||
</div>
|
||||
<div id="osx_notify_options">
|
||||
<div class="row">
|
||||
<input type="text" id="osx_notify_reg" name="osx_notify_app" value="${config['osx_notify_app']}" size="50"><label>Register Notify App</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<small>Enter the path/application name to be registered with the Notification Center, default is /Applications/Headphones</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="button" value="Register" id="osxnotifyregister"><label></label>
|
||||
</div>
|
||||
<div class="row checkbox">
|
||||
<input type="checkbox" name="osx_notify_onsnatch" value="1" ${config['osx_notify_onsnatch']} /><label>Notify on snatch?</label>
|
||||
</div>
|
||||
|
||||
@@ -197,7 +197,6 @@ _CONFIG_DEFINITIONS = {
|
||||
'OMGWTFNZBS_UID': (str, 'omgwtfnzbs', ''),
|
||||
'OPEN_MAGNET_LINKS': (int, 'General', 0), # 0: Ignore, 1: Open, 2: Convert, 3: Embed (rtorrent)
|
||||
'MAGNET_LINKS': (int, 'General', 0),
|
||||
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/Headphones'),
|
||||
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
||||
'OSX_NOTIFY_ONSNATCH': (int, 'OSX_Notify', 0),
|
||||
'PIRATEBAY': (int, 'Piratebay', 0),
|
||||
|
||||
+4
-68
@@ -840,78 +840,14 @@ class TwitterNotifier(object):
|
||||
|
||||
|
||||
class OSX_NOTIFY(object):
|
||||
def __init__(self):
|
||||
def notify(self, title, subtitle):
|
||||
try:
|
||||
self.objc = __import__("objc")
|
||||
self.AppKit = __import__("AppKit")
|
||||
except:
|
||||
logger.warn('OS X Notification: Cannot import objc or AppKit')
|
||||
pass
|
||||
|
||||
def swizzle(self, cls, SEL, func):
|
||||
old_IMP = getattr(cls, SEL, None)
|
||||
if old_IMP is None:
|
||||
old_IMP = cls.instanceMethodForSelector_(SEL)
|
||||
|
||||
def wrapper(self, *args, **kwargs):
|
||||
return func(self, old_IMP, *args, **kwargs)
|
||||
|
||||
new_IMP = self.objc.selector(
|
||||
wrapper,
|
||||
selector=old_IMP.selector,
|
||||
signature=old_IMP.signature
|
||||
)
|
||||
self.objc.classAddMethod(cls, SEL.encode(), new_IMP)
|
||||
|
||||
def notify(self, title, subtitle=None, text=None, sound=True, image=None):
|
||||
|
||||
try:
|
||||
self.swizzle(
|
||||
self.objc.lookUpClass('NSBundle'),
|
||||
'bundleIdentifier',
|
||||
self.swizzled_bundleIdentifier
|
||||
)
|
||||
|
||||
NSUserNotification = self.objc.lookUpClass('NSUserNotification')
|
||||
NSUserNotificationCenter = self.objc.lookUpClass(
|
||||
'NSUserNotificationCenter')
|
||||
NSAutoreleasePool = self.objc.lookUpClass('NSAutoreleasePool')
|
||||
|
||||
if not NSUserNotification or not NSUserNotificationCenter:
|
||||
return False
|
||||
|
||||
pool = NSAutoreleasePool.alloc().init()
|
||||
|
||||
notification = NSUserNotification.alloc().init()
|
||||
notification.setTitle_(title)
|
||||
if subtitle:
|
||||
notification.setSubtitle_(subtitle)
|
||||
if text:
|
||||
notification.setInformativeText_(text)
|
||||
if sound:
|
||||
notification.setSoundName_(
|
||||
"NSUserNotificationDefaultSoundName")
|
||||
if image:
|
||||
source_img = self.AppKit.NSImage.alloc().\
|
||||
initByReferencingFile_(image)
|
||||
notification.setContentImage_(source_img)
|
||||
# notification.set_identityImage_(source_img)
|
||||
notification.setHasActionButton_(False)
|
||||
|
||||
notification_center = NSUserNotificationCenter.\
|
||||
defaultUserNotificationCenter()
|
||||
notification_center.deliverNotification_(notification)
|
||||
|
||||
del pool
|
||||
return True
|
||||
|
||||
script = f'display notification "{subtitle}" with title "{title}"'
|
||||
subprocess.run(["osascript", "-e", script])
|
||||
except Exception as e:
|
||||
logger.warn('Error sending OS X Notification: %s' % e)
|
||||
logger.warn(f"Error sending MacOS Notification: {e}")
|
||||
return False
|
||||
|
||||
def swizzled_bundleIdentifier(self, original, swizzled):
|
||||
return 'ade.headphones.osxnotify'
|
||||
|
||||
|
||||
class BOXCAR(object):
|
||||
def __init__(self):
|
||||
|
||||
@@ -623,15 +623,9 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
|
||||
#twitter.notify_download(pushmessage)
|
||||
|
||||
if headphones.CONFIG.OSX_NOTIFY_ENABLED:
|
||||
from headphones import cache
|
||||
c = cache.Cache()
|
||||
album_art = c.get_artwork_from_cache(None, release['AlbumID'])
|
||||
logger.info("Sending OS X notification")
|
||||
osx_notify = notifiers.OSX_NOTIFY()
|
||||
osx_notify.notify(release['ArtistName'],
|
||||
release['AlbumTitle'],
|
||||
statusmessage,
|
||||
image=album_art)
|
||||
logger.info("Sending MacOS notification")
|
||||
osx = notifiers.OSX_NOTIFY()
|
||||
osx.notify(f"Headphones Processed", f"{pushmessage}\n{statusmessage}")
|
||||
|
||||
if headphones.CONFIG.BOXCAR_ENABLED:
|
||||
logger.info("Sending Boxcar2 notification")
|
||||
|
||||
@@ -1228,16 +1228,12 @@ def send_to_downloader(data, result, album):
|
||||
logger.info("Sending Pushalot notification")
|
||||
pushalot = notifiers.PUSHALOT()
|
||||
pushalot.notify(name, "Download started")
|
||||
|
||||
if headphones.CONFIG.OSX_NOTIFY_ENABLED and headphones.CONFIG.OSX_NOTIFY_ONSNATCH:
|
||||
from headphones import cache
|
||||
c = cache.Cache()
|
||||
album_art = c.get_artwork_from_cache(None, rgid)
|
||||
logger.info("Sending OS X notification")
|
||||
osx_notify = notifiers.OSX_NOTIFY()
|
||||
osx_notify.notify(artist,
|
||||
albumname,
|
||||
'Snatched: ' + provider + '. ' + name,
|
||||
image=album_art)
|
||||
logger.info("Sending MacOS notification")
|
||||
osx = notifiers.OSX_NOTIFY()
|
||||
osx.notify(f"Headphones Snatched", f"{artist} - {albumname}\nFrom {provider}, {name}")
|
||||
|
||||
if headphones.CONFIG.BOXCAR_ENABLED and headphones.CONFIG.BOXCAR_ONSNATCH:
|
||||
logger.info("Sending Boxcar2 notification")
|
||||
b2msg = 'From ' + provider + '<br></br>' + name
|
||||
|
||||
@@ -1369,7 +1369,6 @@ class WebInterface(object):
|
||||
"twitter_onsnatch": checked(headphones.CONFIG.TWITTER_ONSNATCH),
|
||||
"osx_notify_enabled": checked(headphones.CONFIG.OSX_NOTIFY_ENABLED),
|
||||
"osx_notify_onsnatch": checked(headphones.CONFIG.OSX_NOTIFY_ONSNATCH),
|
||||
"osx_notify_app": headphones.CONFIG.OSX_NOTIFY_APP,
|
||||
"boxcar_enabled": checked(headphones.CONFIG.BOXCAR_ENABLED),
|
||||
"boxcar_onsnatch": checked(headphones.CONFIG.BOXCAR_ONSNATCH),
|
||||
"boxcar_token": headphones.CONFIG.BOXCAR_TOKEN,
|
||||
@@ -1718,20 +1717,6 @@ class WebInterface(object):
|
||||
else:
|
||||
return "Error sending tweet"
|
||||
|
||||
@cherrypy.expose
|
||||
def osxnotifyregister(self, app):
|
||||
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
|
||||
from osxnotify import registerapp as osxnotify
|
||||
result, msg = osxnotify.registerapp(app)
|
||||
if result:
|
||||
osx_notify = notifiers.OSX_NOTIFY()
|
||||
osx_notify.notify('Registered', result, 'Success :-)')
|
||||
logger.info(
|
||||
'Registered %s, to re-register a different app, delete this app first' % result)
|
||||
else:
|
||||
logger.warn(msg)
|
||||
return msg
|
||||
|
||||
@cherrypy.expose
|
||||
def testPushover(self):
|
||||
logger.info("Sending Pushover notification")
|
||||
|
||||
Binary file not shown.
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import stat
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
def registerapp(app):
|
||||
|
||||
# don't do any of this unless >= 10.8
|
||||
if not [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 8]:
|
||||
return None, 'Registering requires OS X version >= 10.8'
|
||||
|
||||
app_path = None
|
||||
|
||||
# check app bundle doesn't already exist
|
||||
app_path = subprocess.check_output(['/usr/bin/mdfind', 'kMDItemCFBundleIdentifier == "ade.headphones.osxnotify"']).strip()
|
||||
if app_path:
|
||||
return app_path, 'App previously registered'
|
||||
|
||||
# check app doesn't already exist
|
||||
app = app.strip()
|
||||
if not app:
|
||||
return None, 'Path/Application not entered'
|
||||
if os.path.splitext(app)[1] == ".app":
|
||||
app_path = app
|
||||
else:
|
||||
app_path = app + '.app'
|
||||
if os.path.exists(app_path):
|
||||
return None, 'App %s already exists, choose a different name' % app_path
|
||||
|
||||
# generate app
|
||||
try:
|
||||
os.mkdir(app_path)
|
||||
os.mkdir(app_path + "/Contents")
|
||||
os.mkdir(app_path + "/Contents/MacOS")
|
||||
os.mkdir(app_path + "/Contents/Resources")
|
||||
shutil.copy(os.path.join(os.path.dirname(__file__), "appIcon.icns"), app_path + "/Contents/Resources/")
|
||||
|
||||
version = "1.0.0"
|
||||
bundleName = "OSXNotify"
|
||||
bundleIdentifier = "ade.headphones.osxnotify"
|
||||
|
||||
f = open(app_path + "/Contents/Info.plist", "w")
|
||||
f.write("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>main.py</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>appIcon.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>%s</string>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
""" % (bundleName + " " + version, bundleIdentifier, bundleName, bundleName + " " + version, version))
|
||||
f.close()
|
||||
|
||||
f = open(app_path + "/Contents/PkgInfo", "w")
|
||||
f.write("APPL????")
|
||||
f.close()
|
||||
|
||||
f = open(app_path + "/Contents/MacOS/main.py", "w")
|
||||
f.write("""#!/usr/bin/python
|
||||
|
||||
objc = None
|
||||
|
||||
def swizzle(cls, SEL, func):
|
||||
old_IMP = cls.instanceMethodForSelector_(SEL)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
return func(self, old_IMP, *args, **kwargs)
|
||||
new_IMP = objc.selector(wrapper, selector=old_IMP.selector,
|
||||
signature=old_IMP.signature)
|
||||
objc.classAddMethod(cls, SEL, new_IMP)
|
||||
|
||||
def notify(title, subtitle=None, text=None, sound=True):
|
||||
global objc
|
||||
objc = __import__("objc")
|
||||
swizzle(objc.lookUpClass('NSBundle'),
|
||||
b'bundleIdentifier',
|
||||
swizzled_bundleIdentifier)
|
||||
NSUserNotification = objc.lookUpClass('NSUserNotification')
|
||||
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
|
||||
NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool')
|
||||
pool = NSAutoreleasePool.alloc().init()
|
||||
notification = NSUserNotification.alloc().init()
|
||||
notification.setTitle_(title)
|
||||
notification.setSubtitle_(subtitle)
|
||||
notification.setInformativeText_(text)
|
||||
notification.setSoundName_("NSUserNotificationDefaultSoundName")
|
||||
notification_center = NSUserNotificationCenter.defaultUserNotificationCenter()
|
||||
notification_center.deliverNotification_(notification)
|
||||
del pool
|
||||
|
||||
def swizzled_bundleIdentifier(self, original):
|
||||
return 'ade.headphones.osxnotify'
|
||||
|
||||
if __name__ == '__main__':
|
||||
notify('Half Man Half Biscuit', 'Back in the DHSS', '99% Of Gargoyles Look Like Bob Todd')
|
||||
""")
|
||||
f.close()
|
||||
|
||||
oldmode = os.stat(app_path + "/Contents/MacOS/main.py").st_mode
|
||||
os.chmod(app_path + "/Contents/MacOS/main.py", oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
return app_path, 'App registered'
|
||||
|
||||
except Exception as e:
|
||||
return None, 'Error creating App %s. %s' % (app_path, e)
|
||||
Reference in New Issue
Block a user