Merged prowl notifications from Calimerorulez

This commit is contained in:
Remy Varma
2012-01-27 11:36:10 +00:00
10 changed files with 1460 additions and 9 deletions
+8
View File
@@ -321,6 +321,14 @@
<br><br> <br><br>
<h3>Log Directory:</h3><input type="text" name="log_dir" value="${config['log_dir']}" size="50"> <h3>Log Directory:</h3><input type="text" name="log_dir" value="${config['log_dir']}" size="50">
</td> </td>
<td>
<h2>Prowl Notification:</h2>
<br>
<h3><input type="checkbox" name="prowl_enabled" value="1" ${config['prowl_enabled']} />Enabled?</h3><br>
<h3>API key:</h3><input type="text" name="prowl_keys" value="${config['prowl_keys']}" size="50"><br><br>
<h3><input type="checkbox" name="prowl_onsnatch" value="1" ${config['prowl_onsnatch']} />Notify on snatch?</h3><br>
<h3>Priority (-2,-1,0,1 or 2):</h3><input type="text" name="prowl_priority" value="${config['prowl_priority']}" size="2">
</td>
</tr> </tr>
<tr> <tr>
<td> <td>
+17 -1
View File
@@ -130,6 +130,10 @@ ENCODEROUTPUTFORMAT = None
ENCODERQUALITY = None ENCODERQUALITY = None
ENCODERVBRCBR = None ENCODERVBRCBR = None
ENCODERLOSSLESS = False ENCODERLOSSLESS = False
PROWL_ENABLED = True
PROWL_PRIORITY = 1
PROWL_KEYS = None
PROWL_ONSNATCH = True
def CheckSection(sec): def CheckSection(sec):
""" Check if INI section exists, if not create it """ """ Check if INI section exists, if not create it """
@@ -191,7 +195,7 @@ def initialize():
NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \ NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \
NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \
ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, ENCODE, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \ ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, ENCODE, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \
ENCODERLOSSLESS ENCODERLOSSLESS, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH
if __INITIALIZED__: if __INITIALIZED__:
return False return False
@@ -203,6 +207,7 @@ def initialize():
CheckSection('Newznab') CheckSection('Newznab')
CheckSection('NZBsorg') CheckSection('NZBsorg')
CheckSection('Newzbin') CheckSection('Newzbin')
CheckSection('Prowl')
# Set global variables based on config file or use defaults # Set global variables based on config file or use defaults
try: try:
@@ -291,6 +296,11 @@ def initialize():
ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr') ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr')
ENCODERLOSSLESS = bool(check_setting_int(CFG, 'General', 'encoderlossless', 1)) ENCODERLOSSLESS = bool(check_setting_int(CFG, 'General', 'encoderlossless', 1))
PROWL_ENABLED = bool(check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0))
PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '')
PROWL_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0))
PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0)
if not LOG_DIR: if not LOG_DIR:
LOG_DIR = os.path.join(DATA_DIR, 'logs') LOG_DIR = os.path.join(DATA_DIR, 'logs')
@@ -471,6 +481,12 @@ def config_write():
new_config['Newzbin']['newzbin_uid'] = NEWZBIN_UID new_config['Newzbin']['newzbin_uid'] = NEWZBIN_UID
new_config['Newzbin']['newzbin_password'] = NEWZBIN_PASSWORD new_config['Newzbin']['newzbin_password'] = NEWZBIN_PASSWORD
new_config['Prowl'] = {}
new_config['Prowl']['prowl_enabled'] = int(PROWL_ENABLED)
new_config['Prowl']['prowl_keys'] = PROWL_KEYS
new_config['Prowl']['prowl_onsnatch'] = int(PROWL_ONSNATCH)
new_config['Prowl']['prowl_priority'] = int(PROWL_PRIORITY)
new_config['General']['lastfm_username'] = LASTFM_USERNAME new_config['General']['lastfm_username'] = LASTFM_USERNAME
new_config['General']['interface'] = INTERFACE new_config['General']['interface'] = INTERFACE
new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS
+9
View File
@@ -2,6 +2,8 @@ import os
import time import time
import encode import encode
import urllib, shutil, re import urllib, shutil, re
from headphones import prowl
from headphones.prowl import PROWL
import lib.beets as beets import lib.beets as beets
from lib.beets import autotag from lib.beets import autotag
from lib.beets.mediafile import MediaFile from lib.beets.mediafile import MediaFile
@@ -254,6 +256,13 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
updateHave(albumpath) updateHave(albumpath)
logger.info('Post-processing for %s - %s complete' % (release['ArtistName'], release['AlbumTitle'])) logger.info('Post-processing for %s - %s complete' % (release['ArtistName'], release['AlbumTitle']))
if headphones.PROWL_ONSNATCH:
pushmessage = release['ArtistName'] + ' - ' + release['AlbumTitle']
logger.info(u"Prowl request")
prowl = PROWL()
prowl.notify(pushmessage,"Download and Postprocessing completed")
def embedAlbumArt(artwork, downloaded_track_list): def embedAlbumArt(artwork, downloaded_track_list):
logger.info('Embedding album art') logger.info('Embedding album art')
+63
View File
@@ -0,0 +1,63 @@
from headphones import logger
import base64
import cherrypy
import urllib
import urllib2
import headphones
from httplib import HTTPSConnection
from urllib import urlencode
class PROWL:
keys = []
priority = []
def __init__(self):
self.enabled = headphones.PROWL_ENABLED
self.keys = headphones.PROWL_KEYS
self.priority = headphones.PROWL_PRIORITY
pass
def conf(self, options):
return cherrypy.config['config'].get('Prowl', options)
def notify(self, message, event):
if not headphones.PROWL_ENABLED:
return
http_handler = HTTPSConnection("api.prowlapp.com")
data = {'apikey': headphones.PROWL_KEYS,
'application': 'Headphones',
'event': event,
'description': message.encode("utf-8"),
'priority': headphones.PROWL_PRIORITY }
http_handler.request("POST",
"/publicapi/add",
headers = {'Content-type': "application/x-www-form-urlencoded"},
body = urlencode(data))
response = http_handler.getresponse()
request_status = response.status
if request_status == 200:
logger.info(u"Prowl notifications sent.")
return True
elif request_status == 401:
logger.info(u"Prowl auth failed: %s" % response.reason)
return False
else:
logger.info(u"Prowl notification failed.")
return False
def updateLibrary(self):
#For uniformity reasons not removed
return
def test(self, keys, priority):
self.enabled = True
self.keys = keys
self.priority = priority
self.notify('ZOMG Lazors Pewpewpew!', 'Test Message')
+7 -1
View File
@@ -25,7 +25,8 @@ import urllib2, cookielib
from headphones.common import USER_AGENT from headphones.common import USER_AGENT
from headphones import logger from headphones import logger
from headphones import prowl
from headphones.prowl import PROWL
def sendNZB(nzb): def sendNZB(nzb):
@@ -116,6 +117,11 @@ def sendNZB(nzb):
if sabText == "ok": if sabText == "ok":
logger.info(u"NZB sent to SAB successfully") logger.info(u"NZB sent to SAB successfully")
if headphones.PROWL_ONSNATCH:
logger.info(u"Prowl request")
prowl = PROWL()
prowl.notify(nzb.name,"Download started")
return True return True
elif sabText == "Missing authentication": elif sabText == "Missing authentication":
logger.info(u"Incorrect username/password sent to SAB, NZB not sent") logger.info(u"Incorrect username/password sent to SAB, NZB not sent")
+3 -3
View File
@@ -495,9 +495,9 @@ def verifyresult(title, artistterm, term):
if token == 'Various' or token == 'Artists' or token == 'VA': if token == 'Various' or token == 'Artists' or token == 'VA':
continue continue
if not re.search('(?:\W|^)+' + token + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE): if not re.search('(?:\W|^)+' + token + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
if not re.search('(?:\W|^)+' + token.replace("'","") + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE): if not re.search('(?:\W|^)+' + token.replace("'","") + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE):
logger.info("Removed from results: " + title + " (missing tokens: " + token + " and " + token.replace("'","") + ")") logger.info("Removed from results: " + title + " (missing tokens: " + token + " and " + token.replace("'","") + ")")
return False return False
return True return True
def getresultNZB(result): def getresultNZB(result):
+15
View File
@@ -355,6 +355,21 @@ configform = form = '''
<p><b>Log Directory</b>:<br><input type="text" name="log_dir" value="%s" size="60"> <p><b>Log Directory</b>:<br><input type="text" name="log_dir" value="%s" size="60">
</p> </p>
</td> </td>
<td>
<b>Prowl Notification:</b>
<p>
<input type="checkbox" name="prowl_enabled" value="1" %s />Enabled?
</p>
<p>
<i class="smalltext">API key:</i>
<input type="text" name="prowl_keys" value="%s" size="50">
</p>
<p>
<input type="checkbox" name="prowl_onsnatch" value="1" %s />Notify on snatch?</p>
<p><b>Priority (-2,-1,0,1 or 2):</b><input type="text" name="prowl_priority" value="%s" size="5">
</p>
</td>
</tr> </tr>
</table> </table>
+11 -2
View File
@@ -378,7 +378,11 @@ class WebInterface(object):
"samplingfrequency": headphones.SAMPLINGFREQUENCY, "samplingfrequency": headphones.SAMPLINGFREQUENCY,
"encodervbrcbr": headphones.ENCODERVBRCBR, "encodervbrcbr": headphones.ENCODERVBRCBR,
"encoderquality": headphones.ENCODERQUALITY, "encoderquality": headphones.ENCODERQUALITY,
"encoderlossless": checked(headphones.ENCODERLOSSLESS) "encoderlossless": checked(headphones.ENCODERLOSSLESS),
"prowl_enabled": checked(headphones.PROWL_ENABLED),
"prowl_onsnatch": checked(headphones.PROWL_ONSNATCH),
"prowl_keys": headphones.PROWL_KEYS,
"prowl_priority": headphones.PROWL_PRIORITY
} }
return serve_template(templatename="config.html", title="Settings", config=config) return serve_template(templatename="config.html", title="Settings", config=config)
config.exposed = True config.exposed = True
@@ -390,7 +394,8 @@ class WebInterface(object):
nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, newzbin=0, newzbin_uid=None, newzbin_password=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, newzbin=0, newzbin_uid=None, newzbin_password=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0,
torrentblackhole_dir=None, download_torrent_dir=None, numberofseeders=10, use_isohunt=0, use_kat=0, use_mininova=0, torrentblackhole_dir=None, download_torrent_dir=None, numberofseeders=10, use_isohunt=0, use_kat=0, use_mininova=0,
rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, interface=None, log_dir=None, rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, interface=None, log_dir=None,
encode=0, encoder=None, bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0): encode=0, encoder=None, bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0,
prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0):
headphones.HTTP_HOST = http_host headphones.HTTP_HOST = http_host
headphones.HTTP_PORT = http_port headphones.HTTP_PORT = http_port
@@ -450,6 +455,10 @@ class WebInterface(object):
headphones.ENCODERVBRCBR = encodervbrcbr headphones.ENCODERVBRCBR = encodervbrcbr
headphones.ENCODERQUALITY = int(encoderquality) headphones.ENCODERQUALITY = int(encoderquality)
headphones.ENCODERLOSSLESS = encoderlossless headphones.ENCODERLOSSLESS = encoderlossless
headphones.PROWL_ENABLED = prowl_enabled
headphones.PROWL_ONSNATCH = prowl_onsnatch
headphones.PROWL_KEYS = prowl_keys
headphones.PROWL_PRIORITY = prowl_priority
headphones.config_write() headphones.config_write()
+1215
View File
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
"""
iri2uri
Converts an IRI to a URI.
"""
__author__ = "Joe Gregorio (joe@bitworking.org)"
__copyright__ = "Copyright 2006, Joe Gregorio"
__contributors__ = []
__version__ = "1.0.0"
__license__ = "MIT"
__history__ = """
"""
import urlparse
# Convert an IRI to a URI following the rules in RFC 3987
#
# The characters we need to enocde and escape are defined in the spec:
#
# iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD
# ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
# / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
# / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
# / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
# / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
# / %xD0000-DFFFD / %xE1000-EFFFD
escape_range = [
(0xA0, 0xD7FF ),
(0xE000, 0xF8FF ),
(0xF900, 0xFDCF ),
(0xFDF0, 0xFFEF),
(0x10000, 0x1FFFD ),
(0x20000, 0x2FFFD ),
(0x30000, 0x3FFFD),
(0x40000, 0x4FFFD ),
(0x50000, 0x5FFFD ),
(0x60000, 0x6FFFD),
(0x70000, 0x7FFFD ),
(0x80000, 0x8FFFD ),
(0x90000, 0x9FFFD),
(0xA0000, 0xAFFFD ),
(0xB0000, 0xBFFFD ),
(0xC0000, 0xCFFFD),
(0xD0000, 0xDFFFD ),
(0xE1000, 0xEFFFD),
(0xF0000, 0xFFFFD ),
(0x100000, 0x10FFFD)
]
def encode(c):
retval = c
i = ord(c)
for low, high in escape_range:
if i < low:
break
if i >= low and i <= high:
retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')])
break
return retval
def iri2uri(uri):
"""Convert an IRI to a URI. Note that IRIs must be
passed in a unicode strings. That is, do not utf-8 encode
the IRI before passing it into the function."""
if isinstance(uri ,unicode):
(scheme, authority, path, query, fragment) = urlparse.urlsplit(uri)
authority = authority.encode('idna')
# For each character in 'ucschar' or 'iprivate'
# 1. encode as utf-8
# 2. then %-encode each octet of that utf-8
uri = urlparse.urlunsplit((scheme, authority, path, query, fragment))
uri = "".join([encode(c) for c in uri])
return uri
if __name__ == "__main__":
import unittest
class Test(unittest.TestCase):
def test_uris(self):
"""Test that URIs are invariant under the transformation."""
invariant = [
u"ftp://ftp.is.co.za/rfc/rfc1808.txt",
u"http://www.ietf.org/rfc/rfc2396.txt",
u"ldap://[2001:db8::7]/c=GB?objectClass?one",
u"mailto:John.Doe@example.com",
u"news:comp.infosystems.www.servers.unix",
u"tel:+1-816-555-1212",
u"telnet://192.0.2.16:80/",
u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ]
for uri in invariant:
self.assertEqual(uri, iri2uri(uri))
def test_iri(self):
""" Test that the right type of escaping is done for each part of the URI."""
self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}"))
self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}"))
self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}"))
self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}"))
self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))
self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")))
self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8')))
unittest.main()