diff --git a/data/images/back_disabled.jpg b/data/images/back_disabled.jpg
index 1e73a546..11b1c688 100644
Binary files a/data/images/back_disabled.jpg and b/data/images/back_disabled.jpg differ
diff --git a/data/images/back_enabled.jpg b/data/images/back_enabled.jpg
index a6d764c7..91ef2fea 100644
Binary files a/data/images/back_enabled.jpg and b/data/images/back_enabled.jpg differ
diff --git a/data/images/forward_disabled.jpg b/data/images/forward_disabled.jpg
index 28a9dc53..d6cb703b 100644
Binary files a/data/images/forward_disabled.jpg and b/data/images/forward_disabled.jpg differ
diff --git a/data/images/forward_enabled.jpg b/data/images/forward_enabled.jpg
index 598c075f..adb1ee98 100644
Binary files a/data/images/forward_enabled.jpg and b/data/images/forward_enabled.jpg differ
diff --git a/data/images/headphoneslogo.png b/data/images/headphoneslogo.png
index 2b77ac93..f4b48b2c 100644
Binary files a/data/images/headphoneslogo.png and b/data/images/headphoneslogo.png differ
diff --git a/data/images/ui-bg_flat_0_aaaaaa_40x100.png b/data/images/ui-bg_flat_0_aaaaaa_40x100.png
index 3c07dd4e..be476d18 100755
Binary files a/data/images/ui-bg_flat_0_aaaaaa_40x100.png and b/data/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/data/images/ui-bg_flat_0_eeeeee_40x100.png b/data/images/ui-bg_flat_0_eeeeee_40x100.png
index 7d5e8992..ded77b96 100755
Binary files a/data/images/ui-bg_flat_0_eeeeee_40x100.png and b/data/images/ui-bg_flat_0_eeeeee_40x100.png differ
diff --git a/data/images/ui-bg_flat_55_c0402a_40x100.png b/data/images/ui-bg_flat_55_c0402a_40x100.png
index 6e53344d..973b7c2f 100755
Binary files a/data/images/ui-bg_flat_55_c0402a_40x100.png and b/data/images/ui-bg_flat_55_c0402a_40x100.png differ
diff --git a/data/images/ui-bg_flat_55_eeeeee_40x100.png b/data/images/ui-bg_flat_55_eeeeee_40x100.png
index bb8ee043..ded77b96 100755
Binary files a/data/images/ui-bg_flat_55_eeeeee_40x100.png and b/data/images/ui-bg_flat_55_eeeeee_40x100.png differ
diff --git a/data/images/ui-bg_glass_100_f8f8f8_1x400.png b/data/images/ui-bg_glass_100_f8f8f8_1x400.png
index 86f59cbf..3c07fdc3 100755
Binary files a/data/images/ui-bg_glass_100_f8f8f8_1x400.png and b/data/images/ui-bg_glass_100_f8f8f8_1x400.png differ
diff --git a/data/images/ui-bg_glass_35_dddddd_1x400.png b/data/images/ui-bg_glass_35_dddddd_1x400.png
index 8847220b..047f4dc7 100755
Binary files a/data/images/ui-bg_glass_35_dddddd_1x400.png and b/data/images/ui-bg_glass_35_dddddd_1x400.png differ
diff --git a/data/images/ui-bg_glass_60_eeeeee_1x400.png b/data/images/ui-bg_glass_60_eeeeee_1x400.png
index 57760b4d..331975b9 100755
Binary files a/data/images/ui-bg_glass_60_eeeeee_1x400.png and b/data/images/ui-bg_glass_60_eeeeee_1x400.png differ
diff --git a/data/images/ui-bg_inset-hard_75_999999_1x100.png b/data/images/ui-bg_inset-hard_75_999999_1x100.png
index b078d868..a4eeaa7c 100755
Binary files a/data/images/ui-bg_inset-hard_75_999999_1x100.png and b/data/images/ui-bg_inset-hard_75_999999_1x100.png differ
diff --git a/data/images/ui-bg_inset-soft_50_c9c9c9_1x100.png b/data/images/ui-bg_inset-soft_50_c9c9c9_1x100.png
index 09e002b1..41638da9 100755
Binary files a/data/images/ui-bg_inset-soft_50_c9c9c9_1x100.png and b/data/images/ui-bg_inset-soft_50_c9c9c9_1x100.png differ
diff --git a/data/images/ui-icons_3383bb_256x240.png b/data/images/ui-icons_3383bb_256x240.png
index c2eb45be..a305f6a8 100755
Binary files a/data/images/ui-icons_3383bb_256x240.png and b/data/images/ui-icons_3383bb_256x240.png differ
diff --git a/data/images/ui-icons_454545_256x240.png b/data/images/ui-icons_454545_256x240.png
index b6db1acd..5fc455f2 100755
Binary files a/data/images/ui-icons_454545_256x240.png and b/data/images/ui-icons_454545_256x240.png differ
diff --git a/data/images/ui-icons_70b2e1_256x240.png b/data/images/ui-icons_70b2e1_256x240.png
index 66f4f000..7986bdf6 100755
Binary files a/data/images/ui-icons_70b2e1_256x240.png and b/data/images/ui-icons_70b2e1_256x240.png differ
diff --git a/data/images/ui-icons_999999_256x240.png b/data/images/ui-icons_999999_256x240.png
index da7e727b..92a2262c 100755
Binary files a/data/images/ui-icons_999999_256x240.png and b/data/images/ui-icons_999999_256x240.png differ
diff --git a/data/images/ui-icons_fbc856_256x240.png b/data/images/ui-icons_fbc856_256x240.png
index 69480efc..d2643ba3 100755
Binary files a/data/images/ui-icons_fbc856_256x240.png and b/data/images/ui-icons_fbc856_256x240.png differ
diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html
index 02f40718..3859d4a7 100644
--- a/data/interfaces/default/config.html
+++ b/data/interfaces/default/config.html
@@ -1372,6 +1372,23 @@
+
+
@@ -2168,6 +2185,27 @@
}
});
+ if ($("#join").is(":checked"))
+ {
+ $("#joinoptions").show();
+ }
+ else
+ {
+ $("#joinoptions").hide();
+ }
+
+
+ $("#join").click(function(){
+ if ($("#join").is(":checked"))
+ {
+ $("#joinoptions").slideDown();
+ }
+ else
+ {
+ $("#joinoptions").slideUp();
+ }
+ });
+
if ($("#twitter").is(":checked"))
{
$("#twitteroptions").show();
diff --git a/data/interfaces/default/images/MusicBrainz_Album_Icon.png b/data/interfaces/default/images/MusicBrainz_Album_Icon.png
index 16abf29b..5237a429 100644
Binary files a/data/interfaces/default/images/MusicBrainz_Album_Icon.png and b/data/interfaces/default/images/MusicBrainz_Album_Icon.png differ
diff --git a/data/interfaces/default/images/MusicBrainz_Artist_Icon.png b/data/interfaces/default/images/MusicBrainz_Artist_Icon.png
index 82e3381d..019a7e94 100644
Binary files a/data/interfaces/default/images/MusicBrainz_Artist_Icon.png and b/data/interfaces/default/images/MusicBrainz_Artist_Icon.png differ
diff --git a/data/interfaces/default/images/NoAlbumArt.png b/data/interfaces/default/images/NoAlbumArt.png
index 146e1ccb..a52551c2 100644
Binary files a/data/interfaces/default/images/NoAlbumArt.png and b/data/interfaces/default/images/NoAlbumArt.png differ
diff --git a/data/interfaces/default/images/button.png b/data/interfaces/default/images/button.png
index a5fd7830..b5357ff7 100644
Binary files a/data/interfaces/default/images/button.png and b/data/interfaces/default/images/button.png differ
diff --git a/data/interfaces/default/images/icon_add.png b/data/interfaces/default/images/icon_add.png
index 9e5ccc47..5cf8d665 100644
Binary files a/data/interfaces/default/images/icon_add.png and b/data/interfaces/default/images/icon_add.png differ
diff --git a/data/interfaces/default/images/icon_delete.png b/data/interfaces/default/images/icon_delete.png
index e019d290..b879ff8c 100644
Binary files a/data/interfaces/default/images/icon_delete.png and b/data/interfaces/default/images/icon_delete.png differ
diff --git a/data/interfaces/default/images/icon_extra.gif b/data/interfaces/default/images/icon_extra.gif
index d447c632..f4278827 100644
Binary files a/data/interfaces/default/images/icon_extra.gif and b/data/interfaces/default/images/icon_extra.gif differ
diff --git a/data/interfaces/default/images/icon_gear.png b/data/interfaces/default/images/icon_gear.png
index 6513b30b..a63b9a13 100644
Binary files a/data/interfaces/default/images/icon_gear.png and b/data/interfaces/default/images/icon_gear.png differ
diff --git a/data/interfaces/default/images/icon_getextra.png b/data/interfaces/default/images/icon_getextra.png
index 19fe357b..923d02d6 100644
Binary files a/data/interfaces/default/images/icon_getextra.png and b/data/interfaces/default/images/icon_getextra.png differ
diff --git a/data/interfaces/default/images/icon_history.png b/data/interfaces/default/images/icon_history.png
index 363289c2..2590faf0 100644
Binary files a/data/interfaces/default/images/icon_history.png and b/data/interfaces/default/images/icon_history.png differ
diff --git a/data/interfaces/default/images/icon_like.png b/data/interfaces/default/images/icon_like.png
index e3f638d1..91a3a3bf 100644
Binary files a/data/interfaces/default/images/icon_like.png and b/data/interfaces/default/images/icon_like.png differ
diff --git a/data/interfaces/default/images/icon_logs.png b/data/interfaces/default/images/icon_logs.png
index 4943de1a..9fc1dfac 100644
Binary files a/data/interfaces/default/images/icon_logs.png and b/data/interfaces/default/images/icon_logs.png differ
diff --git a/data/interfaces/default/images/icon_manage.png b/data/interfaces/default/images/icon_manage.png
index 25c1a7e8..d677a241 100644
Binary files a/data/interfaces/default/images/icon_manage.png and b/data/interfaces/default/images/icon_manage.png differ
diff --git a/data/interfaces/default/images/icon_pause.png b/data/interfaces/default/images/icon_pause.png
index 0c99a2b6..de884766 100644
Binary files a/data/interfaces/default/images/icon_pause.png and b/data/interfaces/default/images/icon_pause.png differ
diff --git a/data/interfaces/default/images/icon_refresh.png b/data/interfaces/default/images/icon_refresh.png
index 13953728..24cf6009 100644
Binary files a/data/interfaces/default/images/icon_refresh.png and b/data/interfaces/default/images/icon_refresh.png differ
diff --git a/data/interfaces/default/images/icon_removeextra.png b/data/interfaces/default/images/icon_removeextra.png
index 65acd0db..1f9f0f97 100644
Binary files a/data/interfaces/default/images/icon_removeextra.png and b/data/interfaces/default/images/icon_removeextra.png differ
diff --git a/data/interfaces/default/images/icon_search.gif b/data/interfaces/default/images/icon_search.gif
index a64534cc..867a6d43 100644
Binary files a/data/interfaces/default/images/icon_search.gif and b/data/interfaces/default/images/icon_search.gif differ
diff --git a/data/interfaces/default/images/icon_search.png b/data/interfaces/default/images/icon_search.png
index 9845cc95..7a6cd079 100644
Binary files a/data/interfaces/default/images/icon_search.png and b/data/interfaces/default/images/icon_search.png differ
diff --git a/data/interfaces/default/images/icon_sprite_black.png b/data/interfaces/default/images/icon_sprite_black.png
index fe079a59..2723382a 100644
Binary files a/data/interfaces/default/images/icon_sprite_black.png and b/data/interfaces/default/images/icon_sprite_black.png differ
diff --git a/data/interfaces/default/images/icon_sprite_white.png b/data/interfaces/default/images/icon_sprite_white.png
index 42f8f992..701b147c 100644
Binary files a/data/interfaces/default/images/icon_sprite_white.png and b/data/interfaces/default/images/icon_sprite_white.png differ
diff --git a/data/interfaces/default/images/icon_upcoming.png b/data/interfaces/default/images/icon_upcoming.png
index 2a7acbe6..6e421eb5 100644
Binary files a/data/interfaces/default/images/icon_upcoming.png and b/data/interfaces/default/images/icon_upcoming.png differ
diff --git a/data/interfaces/default/images/icon_wanted.png b/data/interfaces/default/images/icon_wanted.png
index a06fd6e1..d1a08aae 100644
Binary files a/data/interfaces/default/images/icon_wanted.png and b/data/interfaces/default/images/icon_wanted.png differ
diff --git a/data/interfaces/default/images/loader_black.gif b/data/interfaces/default/images/loader_black.gif
index e2a116c7..17c51b14 100644
Binary files a/data/interfaces/default/images/loader_black.gif and b/data/interfaces/default/images/loader_black.gif differ
diff --git a/data/interfaces/default/images/loader_blue.gif b/data/interfaces/default/images/loader_blue.gif
index 956c1cd0..40d87f68 100644
Binary files a/data/interfaces/default/images/loader_blue.gif and b/data/interfaces/default/images/loader_blue.gif differ
diff --git a/data/interfaces/default/images/loader_refresh_black.gif b/data/interfaces/default/images/loader_refresh_black.gif
index 0ea146c0..551a6655 100644
Binary files a/data/interfaces/default/images/loader_refresh_black.gif and b/data/interfaces/default/images/loader_refresh_black.gif differ
diff --git a/data/interfaces/default/images/loader_refresh_blue.gif b/data/interfaces/default/images/loader_refresh_blue.gif
index 57a76afb..722066f6 100644
Binary files a/data/interfaces/default/images/loader_refresh_blue.gif and b/data/interfaces/default/images/loader_refresh_blue.gif differ
diff --git a/data/interfaces/default/images/no-cover-art.png b/data/interfaces/default/images/no-cover-art.png
index 40334da4..b654dc71 100644
Binary files a/data/interfaces/default/images/no-cover-art.png and b/data/interfaces/default/images/no-cover-art.png differ
diff --git a/data/interfaces/default/images/no-cover-artist.png b/data/interfaces/default/images/no-cover-artist.png
index 40fe7903..ae97e049 100644
Binary files a/data/interfaces/default/images/no-cover-artist.png and b/data/interfaces/default/images/no-cover-artist.png differ
diff --git a/data/interfaces/default/images/songkick.png b/data/interfaces/default/images/songkick.png
index c18e440d..c5261bd8 100644
Binary files a/data/interfaces/default/images/songkick.png and b/data/interfaces/default/images/songkick.png differ
diff --git a/data/interfaces/default/images/songkick_ribon.png b/data/interfaces/default/images/songkick_ribon.png
index 57ad4ccb..ff760f37 100644
Binary files a/data/interfaces/default/images/songkick_ribon.png and b/data/interfaces/default/images/songkick_ribon.png differ
diff --git a/data/interfaces/default/images/sort_asc.png b/data/interfaces/default/images/sort_asc.png
index e61cf34c..bb2bc57c 100644
Binary files a/data/interfaces/default/images/sort_asc.png and b/data/interfaces/default/images/sort_asc.png differ
diff --git a/data/interfaces/default/images/sort_both.png b/data/interfaces/default/images/sort_both.png
index 7261de19..2753be8f 100644
Binary files a/data/interfaces/default/images/sort_both.png and b/data/interfaces/default/images/sort_both.png differ
diff --git a/data/interfaces/default/images/sort_desc.png b/data/interfaces/default/images/sort_desc.png
index 980a7ecb..c48f18ac 100644
Binary files a/data/interfaces/default/images/sort_desc.png and b/data/interfaces/default/images/sort_desc.png differ
diff --git a/data/interfaces/default/images/toTop.gif b/data/interfaces/default/images/toTop.gif
index cde291a4..110534a2 100644
Binary files a/data/interfaces/default/images/toTop.gif and b/data/interfaces/default/images/toTop.gif differ
diff --git a/data/interfaces/default/images/trashcan.png b/data/interfaces/default/images/trashcan.png
index de10cbda..595328d8 100644
Binary files a/data/interfaces/default/images/trashcan.png and b/data/interfaces/default/images/trashcan.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_close.png b/data/interfaces/default/js/fancybox/fancy_close.png
index 07035307..ca41f1bd 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_close.png and b/data/interfaces/default/js/fancybox/fancy_close.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_loading.png b/data/interfaces/default/js/fancybox/fancy_loading.png
index 25030179..f208508e 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_loading.png and b/data/interfaces/default/js/fancybox/fancy_loading.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_nav_left.png b/data/interfaces/default/js/fancybox/fancy_nav_left.png
index ebaa6a4f..017d3b53 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_nav_left.png and b/data/interfaces/default/js/fancybox/fancy_nav_left.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_nav_right.png b/data/interfaces/default/js/fancybox/fancy_nav_right.png
index 873294e9..03f64f41 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_nav_right.png and b/data/interfaces/default/js/fancybox/fancy_nav_right.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_shadow_e.png b/data/interfaces/default/js/fancybox/fancy_shadow_e.png
index 2eda0893..fff72232 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_shadow_e.png and b/data/interfaces/default/js/fancybox/fancy_shadow_e.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_shadow_n.png b/data/interfaces/default/js/fancybox/fancy_shadow_n.png
index 69aa10e2..76ca9b7a 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_shadow_n.png and b/data/interfaces/default/js/fancybox/fancy_shadow_n.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_shadow_s.png b/data/interfaces/default/js/fancybox/fancy_shadow_s.png
index d8858bfb..d3b3c5b2 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_shadow_s.png and b/data/interfaces/default/js/fancybox/fancy_shadow_s.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_shadow_se.png b/data/interfaces/default/js/fancybox/fancy_shadow_se.png
index 541e3ffd..0cce09c1 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_shadow_se.png and b/data/interfaces/default/js/fancybox/fancy_shadow_se.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_shadow_w.png b/data/interfaces/default/js/fancybox/fancy_shadow_w.png
index 8a4e4a88..b9bde126 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_shadow_w.png and b/data/interfaces/default/js/fancybox/fancy_shadow_w.png differ
diff --git a/data/interfaces/default/js/fancybox/fancy_title_over.png b/data/interfaces/default/js/fancybox/fancy_title_over.png
index d9f458f4..74b9149e 100644
Binary files a/data/interfaces/default/js/fancybox/fancy_title_over.png and b/data/interfaces/default/js/fancybox/fancy_title_over.png differ
diff --git a/data/interfaces/default/js/fancybox/fancybox-x.png b/data/interfaces/default/js/fancybox/fancybox-x.png
index c2130f86..eb850fd3 100644
Binary files a/data/interfaces/default/js/fancybox/fancybox-x.png and b/data/interfaces/default/js/fancybox/fancybox-x.png differ
diff --git a/data/interfaces/default/js/fancybox/fancybox-y.png b/data/interfaces/default/js/fancybox/fancybox-y.png
index 7ef399b9..18458526 100644
Binary files a/data/interfaces/default/js/fancybox/fancybox-y.png and b/data/interfaces/default/js/fancybox/fancybox-y.png differ
diff --git a/data/interfaces/default/js/fancybox/fancybox.png b/data/interfaces/default/js/fancybox/fancybox.png
index 65e14f68..1a0dda99 100644
Binary files a/data/interfaces/default/js/fancybox/fancybox.png and b/data/interfaces/default/js/fancybox/fancybox.png differ
diff --git a/headphones/__init__.py b/headphones/__init__.py
index 8247e1c2..2bd3bf9c 100644
--- a/headphones/__init__.py
+++ b/headphones/__init__.py
@@ -621,8 +621,8 @@ def dbcheck():
c.execute('UPDATE snatched SET TorrentHash = FolderName WHERE Status LIKE "Seed_%"')
# One off script to set CleanName to lower case
- clean_name_mixed = c.execute('SELECT CleanName FROM have ORDER BY Date Desc').fetchone()[0]
- if clean_name_mixed != clean_name_mixed.lower():
+ clean_name_mixed = c.execute('SELECT CleanName FROM have ORDER BY Date Desc').fetchone()
+ if clean_name_mixed and clean_name_mixed[0] != clean_name_mixed[0].lower():
logger.info("Updating track clean name, this could take some time...")
c.execute('UPDATE tracks SET CleanName = LOWER(CleanName) WHERE LOWER(CleanName) != CleanName')
c.execute('UPDATE alltracks SET CleanName = LOWER(CleanName) WHERE LOWER(CleanName) != CleanName')
diff --git a/headphones/config.py b/headphones/config.py
index 98b23785..83c73415 100644
--- a/headphones/config.py
+++ b/headphones/config.py
@@ -145,6 +145,10 @@ _CONFIG_DEFINITIONS = {
'IGNORED_FILES': (list, 'Advanced', []), # path
'INCLUDE_EXTRAS': (int, 'General', 0),
'INTERFACE': (str, 'General', 'default'),
+ 'JOIN_APIKEY': (str, 'Join', ''),
+ 'JOIN_DEVICEID': (str, 'Join', ''),
+ 'JOIN_ENABLED': (int, 'Join', 0),
+ 'JOIN_ONSNATCH': (int, 'Join', 0),
'JOURNAL_MODE': (str, 'Advanced', 'wal'),
'KAT': (int, 'Kat', 0),
'KAT_PROXY_URL': (str, 'Kat', ''),
diff --git a/headphones/notifiers.py b/headphones/notifiers.py
index 54f4f4b5..26cdb234 100644
--- a/headphones/notifiers.py
+++ b/headphones/notifiers.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with Headphones. If not, see .
-from urllib import urlencode
+from urllib import urlencode, quote_plus
import urllib
import subprocess
import json
@@ -148,7 +148,9 @@ class PROWL(object):
http_handler.request("POST",
"/publicapi/add",
- headers={'Content-type': "application/x-www-form-urlencoded"},
+ headers={
+ 'Content-type':
+ "application/x-www-form-urlencoded"},
body=urlencode(data))
response = http_handler.getresponse()
request_status = response.status
@@ -203,28 +205,34 @@ class XBMC(object):
url = host + '/xbmcCmds/xbmcHttp/?' + url_command
if self.password:
- return request.request_content(url, auth=(self.username, self.password))
+ return request.request_content(url,
+ auth=(self.username, self.password))
else:
return request.request_content(url)
def _sendjson(self, host, method, params={}):
- data = [{'id': 0, 'jsonrpc': '2.0', 'method': method, 'params': params}]
+ data = [
+ {'id': 0, 'jsonrpc': '2.0', 'method': method, 'params': params}]
headers = {'Content-Type': 'application/json'}
url = host + '/jsonrpc'
if self.password:
- response = request.request_json(url, method="post", data=json.dumps(data),
- headers=headers, auth=(self.username, self.password))
+ response = request.request_json(
+ url, method="post",
+ data=json.dumps(data),
+ headers=headers, auth=(
+ self.username, self.password))
else:
- response = request.request_json(url, method="post", data=json.dumps(data),
+ response = request.request_json(url, method="post",
+ data=json.dumps(data),
headers=headers)
if response:
return response[0]['result']
def update(self):
- # From what I read you can't update the music library on a per directory or per path basis
- # so need to update the whole thing
+ # From what I read you can't update the music library on a per
+ # directory or per path basis so need to update the whole thing
hosts = [x.strip() for x in self.hosts.split(',')]
@@ -247,18 +255,23 @@ class XBMC(object):
logger.info('Sending notification command to XMBC @ ' + host)
try:
version = self._sendjson(host, 'Application.GetProperties',
- {'properties': ['version']})['version']['major']
+ {'properties': ['version']})[
+ 'version']['major']
if version < 12: # Eden
- notification = header + "," + message + "," + time + "," + albumartpath
+ notification = header + "," + message + "," + time + \
+ "," + albumartpath
notifycommand = {'command': 'ExecBuiltIn',
- 'parameter': 'Notification(' + notification + ')'}
+ 'parameter': 'Notification(' +
+ notification + ')'}
request = self._sendhttp(host, notifycommand)
else: # Frodo
- params = {'title': header, 'message': message, 'displaytime': int(time),
+ params = {'title': header, 'message': message,
+ 'displaytime': int(time),
'image': albumartpath}
- request = self._sendjson(host, 'GUI.ShowNotification', params)
+ request = self._sendjson(host, 'GUI.ShowNotification',
+ params)
if not request:
raise Exception
@@ -323,22 +336,28 @@ class Plex(object):
url = host + '/xbmcCmds/xbmcHttp/?' + command
if self.password:
- response = request.request_response(url, auth=(self.username, self.password))
+ response = request.request_response(url, auth=(
+ self.username, self.password))
else:
response = request.request_response(url)
return response
def _sendjson(self, host, method, params={}):
- data = [{'id': 0, 'jsonrpc': '2.0', 'method': method, 'params': params}]
+ data = [
+ {'id': 0, 'jsonrpc': '2.0', 'method': method, 'params': params}]
headers = {'Content-Type': 'application/json'}
url = host + '/jsonrpc'
if self.password:
- response = request.request_json(url, method="post", data=json.dumps(data),
- headers=headers, auth=(self.username, self.password))
+ response = request.request_json(
+ url, method="post",
+ data=json.dumps(data),
+ headers=headers, auth=(
+ self.username, self.password))
else:
- response = request.request_json(url, method="post", data=json.dumps(data),
+ response = request.request_json(url, method="post",
+ data=json.dumps(data),
headers=headers)
if response:
@@ -346,13 +365,14 @@ class Plex(object):
def update(self):
- # From what I read you can't update the music library on a per directory or per path basis
- # so need to update the whole thing
+ # From what I read you can't update the music library on a per
+ # directory or per path basis so need to update the whole thing
hosts = [x.strip() for x in self.server_hosts.split(',')]
for host in hosts:
- logger.info('Sending library update command to Plex Media Server@ ' + host)
+ logger.info(
+ 'Sending library update command to Plex Media Server@ ' + host)
url = "%s/library/sections" % host
if self.token:
params = {'X-Plex-Token': self.token}
@@ -369,7 +389,8 @@ class Plex(object):
for s in sections:
if s.getAttribute('type') == "artist":
- url = "%s/library/sections/%s/refresh" % (host, s.getAttribute('key'))
+ url = "%s/library/sections/%s/refresh" % (
+ host, s.getAttribute('key'))
request.request_response(url, params=params)
def notify(self, artist, album, albumartpath):
@@ -381,27 +402,35 @@ class Plex(object):
time = "3000" # in ms
for host in hosts:
- logger.info('Sending notification command to Plex client @ ' + host)
+ logger.info(
+ 'Sending notification command to Plex client @ ' + host)
try:
version = self._sendjson(host, 'Application.GetProperties',
- {'properties': ['version']})['version']['major']
+ {'properties': ['version']})[
+ 'version']['major']
if version < 12: # Eden
- notification = header + "," + message + "," + time + "," + albumartpath
+ notification = header + "," + message + "," + time + \
+ "," + albumartpath
notifycommand = {'command': 'ExecBuiltIn',
- 'parameter': 'Notification(' + notification + ')'}
+ 'parameter': 'Notification(' +
+ notification + ')'}
request = self._sendhttp(host, notifycommand)
else: # Frodo
- params = {'title': header, 'message': message, 'displaytime': int(time),
+ params = {'title': header, 'message': message,
+ 'displaytime': int(time),
'image': albumartpath}
- request = self._sendjson(host, 'GUI.ShowNotification', params)
+ request = self._sendjson(host, 'GUI.ShowNotification',
+ params)
if not request:
raise Exception
except Exception:
- logger.error('Error sending notification request to Plex client @ ' + host)
+ logger.error(
+ 'Error sending notification request to Plex client @ ' +
+ host)
class NMA(object):
@@ -419,7 +448,8 @@ class NMA(object):
message = "Headphones has snatched: " + snatched
else:
event = artist + ' - ' + album + ' complete!'
- message = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']'
+ message = "Headphones has downloaded and postprocessed: " + \
+ artist + ' [' + album + ']'
logger.debug(u"NMA event: " + event)
logger.debug(u"NMA message: " + message)
@@ -433,7 +463,8 @@ class NMA(object):
if len(keys) > 1:
batch = True
- response = p.push(title, event, message, priority=nma_priority, batch_mode=batch)
+ response = p.push(title, event, message, priority=nma_priority,
+ batch_mode=batch)
if not response[api][u'code'] == u'200':
logger.error(u'Could not send notification to NotifyMyAndroid')
@@ -461,9 +492,11 @@ class PUSHBULLET(object):
data['device_iden'] = self.deviceid
headers = {'Content-type': "application/json",
- 'Authorization': 'Bearer ' + headphones.CONFIG.PUSHBULLET_APIKEY}
+ 'Authorization': 'Bearer ' +
+ headphones.CONFIG.PUSHBULLET_APIKEY}
- response = request.request_json(url, method="post", headers=headers, data=json.dumps(data))
+ response = request.request_json(url, method="post", headers=headers,
+ data=json.dumps(data))
if response:
logger.info(u"PushBullet notifications sent.")
@@ -492,7 +525,9 @@ class PUSHALOT(object):
http_handler.request("POST",
"/api/sendmessage",
- headers={'Content-type': "application/x-www-form-urlencoded"},
+ headers={
+ 'Content-type':
+ "application/x-www-form-urlencoded"},
body=urlencode(data))
response = http_handler.getresponse()
request_status = response.status
@@ -512,6 +547,49 @@ class PUSHALOT(object):
return False
+class JOIN(object):
+ def __init__(self):
+
+ self.enabled = headphones.CONFIG.JOIN_ENABLED
+ self.apikey = headphones.CONFIG.JOIN_APIKEY
+ self.deviceid = headphones.CONFIG.JOIN_DEVICEID
+ self.url = 'https://joinjoaomgcd.appspot.com/_ah/' \
+ 'api/messaging/v1/sendPush?apikey={apikey}' \
+ '&title={title}&text={text}' \
+ '&icon={icon}'
+
+ def notify(self, message, event):
+ if not headphones.CONFIG.JOIN_ENABLED or \
+ not headphones.CONFIG.JOIN_APIKEY:
+ return
+
+ icon = "https://cdn.rawgit.com/Headphones/" \
+ "headphones/develop/data/images/headphoneslogo.png"
+
+ if not self.deviceid:
+ self.deviceid = "group.all"
+ l = [x.strip() for x in self.deviceid.split(',')]
+ if len(l) > 1:
+ self.url += '&deviceIds={deviceid}'
+ else:
+ self.url += '&deviceId={deviceid}'
+
+ response = urllib2.urlopen(self.url.format(apikey=self.apikey,
+ title=quote_plus(event),
+ text=quote_plus(
+ message.encode(
+ "utf-8")),
+ icon=icon,
+ deviceid=self.deviceid))
+
+ if response:
+ logger.info(u"Join notifications sent.")
+ return True
+ else:
+ logger.error(u"Join notification failed.")
+ return False
+
+
class Synoindex(object):
def __init__(self, util_loc='/usr/syno/bin/synoindex'):
self.util_loc = util_loc
@@ -524,7 +602,8 @@ class Synoindex(object):
if not self.util_exists():
logger.warn(
- "Error sending notification: synoindex utility not found at %s" % self.util_loc)
+ "Error sending notification: synoindex utility "
+ "not found at %s" % self.util_loc)
return
if os.path.isfile(path):
@@ -533,16 +612,19 @@ class Synoindex(object):
cmd_arg = '-A'
else:
logger.warn(
- "Error sending notification: Path passed to synoindex was not a file or folder.")
+ "Error sending notification: Path passed to synoindex "
+ "was not a file or folder.")
return
cmd = [self.util_loc, cmd_arg, path]
logger.info("Calling synoindex command: %s" % str(cmd))
try:
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
cwd=headphones.PROG_DIR)
out, error = p.communicate()
- # synoindex never returns any codes other than '0', highly irritating
+ # synoindex never returns any codes other than '0',
+ # highly irritating
except OSError, e:
logger.warn("Error sending notification: %s" % str(e))
@@ -580,7 +662,8 @@ class PUSHOVER(object):
headers = {'Content-type': "application/x-www-form-urlencoded"}
- response = request.request_response(url, method="POST", headers=headers, data=data)
+ response = request.request_response(url, method="POST",
+ headers=headers, data=data)
if response:
logger.info(u"Pushover notifications sent.")
@@ -614,20 +697,25 @@ class TwitterNotifier(object):
def notify_snatch(self, title):
if headphones.CONFIG.TWITTER_ONSNATCH:
self._notifyTwitter(
- common.notifyStrings[common.NOTIFY_SNATCH] + ': ' + title + ' at ' + helpers.now())
+ common.notifyStrings[
+ common.NOTIFY_SNATCH] + ': ' + title + ' at ' +
+ helpers.now())
def notify_download(self, title):
if headphones.CONFIG.TWITTER_ENABLED:
self._notifyTwitter(common.notifyStrings[
- common.NOTIFY_DOWNLOAD] + ': ' + title + ' at ' + helpers.now())
+ common.NOTIFY_DOWNLOAD] + ': ' +
+ title + ' at ' + helpers.now())
def test_notify(self):
return self._notifyTwitter(
- "This is a test notification from Headphones at " + helpers.now(), force=True)
+ "This is a test notification from Headphones at " + helpers.now(),
+ force=True)
def _get_authorization(self):
- oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
+ oauth_consumer = oauth.Consumer(key=self.consumer_key,
+ secret=self.consumer_secret)
oauth_client = oauth.Client(oauth_consumer)
logger.info('Requesting temp token from Twitter')
@@ -635,32 +723,42 @@ class TwitterNotifier(object):
resp, content = oauth_client.request(self.REQUEST_TOKEN_URL, 'GET')
if resp['status'] != '200':
- logger.info('Invalid respond from Twitter requesting temp token: %s' % resp['status'])
+ logger.info(
+ 'Invalid respond from Twitter requesting temp token: %s' %
+ resp['status'])
else:
request_token = dict(parse_qsl(content))
headphones.CONFIG.TWITTER_USERNAME = request_token['oauth_token']
- headphones.CONFIG.TWITTER_PASSWORD = request_token['oauth_token_secret']
+ headphones.CONFIG.TWITTER_PASSWORD = request_token[
+ 'oauth_token_secret']
- return self.AUTHORIZATION_URL + "?oauth_token=" + request_token['oauth_token']
+ return self.AUTHORIZATION_URL + "?oauth_token=" + request_token[
+ 'oauth_token']
def _get_credentials(self, key):
request_token = {}
request_token['oauth_token'] = headphones.CONFIG.TWITTER_USERNAME
- request_token['oauth_token_secret'] = headphones.CONFIG.TWITTER_PASSWORD
+ request_token[
+ 'oauth_token_secret'] = headphones.CONFIG.TWITTER_PASSWORD
request_token['oauth_callback_confirmed'] = 'true'
- token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
+ token = oauth.Token(request_token['oauth_token'],
+ request_token['oauth_token_secret'])
token.set_verifier(key)
- logger.info('Generating and signing request for an access token using key ' + key)
+ logger.info(
+ 'Generating and signing request for an access token using key ' +
+ key)
- oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
+ oauth_consumer = oauth.Consumer(key=self.consumer_key,
+ secret=self.consumer_secret)
logger.info('oauth_consumer: ' + str(oauth_consumer))
oauth_client = oauth.Client(oauth_consumer, token)
logger.info('oauth_client: ' + str(oauth_client))
- resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST',
+ resp, content = oauth_client.request(self.ACCESS_TOKEN_URL,
+ method='POST',
body='oauth_verifier=%s' % key)
logger.info('resp, content: ' + str(resp) + ',' + str(content))
@@ -669,14 +767,18 @@ class TwitterNotifier(object):
logger.info('resp[status] = ' + str(resp['status']))
if resp['status'] != '200':
- logger.info('The request for a token with did not succeed: ' + str(resp['status']),
+ logger.info('The request for a token with did not succeed: ' + str(
+ resp['status']),
logger.ERROR)
return False
else:
- logger.info('Your Twitter Access Token key: %s' % access_token['oauth_token'])
- logger.info('Access Token secret: %s' % access_token['oauth_token_secret'])
+ logger.info('Your Twitter Access Token key: %s' % access_token[
+ 'oauth_token'])
+ logger.info(
+ 'Access Token secret: %s' % access_token['oauth_token_secret'])
headphones.CONFIG.TWITTER_USERNAME = access_token['oauth_token']
- headphones.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret']
+ headphones.CONFIG.TWITTER_PASSWORD = access_token[
+ 'oauth_token_secret']
return True
def _send_tweet(self, message=None):
@@ -688,7 +790,8 @@ class TwitterNotifier(object):
logger.info(u"Sending tweet: " + message)
- api = twitter.Api(username, password, access_token_key, access_token_secret)
+ api = twitter.Api(username, password, access_token_key,
+ access_token_secret)
try:
api.PostUpdate(message)
@@ -741,7 +844,8 @@ class OSX_NOTIFY(object):
)
NSUserNotification = self.objc.lookUpClass('NSUserNotification')
- NSUserNotificationCenter = self.objc.lookUpClass('NSUserNotificationCenter')
+ NSUserNotificationCenter = self.objc.lookUpClass(
+ 'NSUserNotificationCenter')
NSAutoreleasePool = self.objc.lookUpClass('NSAutoreleasePool')
if not NSUserNotification or not NSUserNotificationCenter:
@@ -756,14 +860,17 @@ class OSX_NOTIFY(object):
if text:
notification.setInformativeText_(text)
if sound:
- notification.setSoundName_("NSUserNotificationDefaultSoundName")
+ notification.setSoundName_(
+ "NSUserNotificationDefaultSoundName")
if image:
- source_img = self.AppKit.NSImage.alloc().initByReferencingFile_(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 = NSUserNotificationCenter.\
+ defaultUserNotificationCenter()
notification_center.deliverNotification_(notification)
del pool
@@ -784,7 +891,8 @@ class BOXCAR(object):
def notify(self, title, message, rgid=None):
try:
if rgid:
- message += '
MusicBrainz' % rgid
+ message += '
MusicBrainz' % rgid
data = urllib.urlencode({
'user_credentials': headphones.CONFIG.BOXCAR_TOKEN,
@@ -820,8 +928,9 @@ class SubSonicNotifier(object):
self.host = self.host + "/"
# Invoke request
- request.request_response(self.host + "musicFolderSettings.view?scanNow",
- auth=(self.username, self.password))
+ request.request_response(
+ self.host + "musicFolderSettings.view?scanNow",
+ auth=(self.username, self.password))
class Email(object):
@@ -829,13 +938,15 @@ class Email(object):
message = MIMEText(message, 'plain', "utf-8")
message['Subject'] = subject
- message['From'] = email.utils.formataddr(('Headphones', headphones.CONFIG.EMAIL_FROM))
+ message['From'] = email.utils.formataddr(
+ ('Headphones', headphones.CONFIG.EMAIL_FROM))
message['To'] = headphones.CONFIG.EMAIL_TO
try:
if headphones.CONFIG.EMAIL_SSL:
- mailserver = smtplib.SMTP_SSL(headphones.CONFIG.EMAIL_SMTP_SERVER,
- headphones.CONFIG.EMAIL_SMTP_PORT)
+ mailserver = smtplib.SMTP_SSL(
+ headphones.CONFIG.EMAIL_SMTP_SERVER,
+ headphones.CONFIG.EMAIL_SMTP_PORT)
else:
mailserver = smtplib.SMTP(headphones.CONFIG.EMAIL_SMTP_SERVER,
headphones.CONFIG.EMAIL_SMTP_PORT)
@@ -849,7 +960,8 @@ class Email(object):
mailserver.login(headphones.CONFIG.EMAIL_SMTP_USER,
headphones.CONFIG.EMAIL_SMTP_PASSWORD)
- mailserver.sendmail(headphones.CONFIG.EMAIL_FROM, headphones.CONFIG.EMAIL_TO,
+ mailserver.sendmail(headphones.CONFIG.EMAIL_FROM,
+ headphones.CONFIG.EMAIL_TO,
message.as_string())
mailserver.quit()
return True
@@ -860,7 +972,6 @@ class Email(object):
class TELEGRAM(object):
-
def notify(self, message, status):
if not headphones.CONFIG.TELEGRAM_ENABLED:
return
@@ -878,14 +989,18 @@ class TELEGRAM(object):
# Send message to user using Telegram's Bot API
try:
- response = requests.post(TELEGRAM_API % (token, "sendMessage"), data=payload)
+ response = requests.post(TELEGRAM_API % (token, "sendMessage"),
+ data=payload)
except Exception, e:
logger.info(u'Telegram notify failed: ' + str(e))
# Error logging
sent_successfuly = True
if not response.status_code == 200:
- logger.info(u'Could not send notification to TelegramBot (token=%s). Response: [%s]', (token, response.text))
+ logger.info(
+ u'Could not send notification to TelegramBot '
+ u'(token=%s). Response: [%s]',
+ (token, response.text))
sent_successfuly = False
logger.info(u"Telegram notifications sent.")
@@ -893,7 +1008,6 @@ class TELEGRAM(object):
class SLACK(object):
-
def notify(self, message, status):
if not headphones.CONFIG.SLACK_ENABLED:
return
@@ -904,7 +1018,8 @@ class SLACK(object):
channel = headphones.CONFIG.SLACK_CHANNEL
emoji = headphones.CONFIG.SLACK_EMOJI
- payload = {'channel': channel, 'text': status + ': ' + message, 'icon_emoji': emoji}
+ payload = {'channel': channel, 'text': status + ': ' + message,
+ 'icon_emoji': emoji}
try:
response = requests.post(SLACK_URL, json=payload)
@@ -913,7 +1028,9 @@ class SLACK(object):
sent_successfuly = True
if not response.status_code == 200:
- logger.info(u'Could not send notification to Slack. Response: [%s]', (response.text))
+ logger.info(
+ u'Could not send notification to Slack. Response: [%s]',
+ (response.text))
sent_successfuly = False
logger.info(u"Slack notifications sent.")
diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py
index 38e4bba5..ed3c136b 100755
--- a/headphones/postprocessor.py
+++ b/headphones/postprocessor.py
@@ -574,6 +574,11 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
pushbullet = notifiers.PUSHBULLET()
pushbullet.notify(pushmessage, statusmessage)
+ if headphones.CONFIG.JOIN_ENABLED:
+ logger.info(u"Join request")
+ join = notifiers.JOIN()
+ join.notify(pushmessage, statusmessage)
+
if headphones.CONFIG.TELEGRAM_ENABLED:
logger.info(u"Telegram request")
telegram = notifiers.TELEGRAM()
diff --git a/headphones/searcher.py b/headphones/searcher.py
index b0652f7f..e3c3f591 100644
--- a/headphones/searcher.py
+++ b/headphones/searcher.py
@@ -32,6 +32,7 @@ import re
from pygazelle import api as gazelleapi
from pygazelle import encoding as gazelleencoding
from pygazelle import format as gazelleformat
+from pygazelle import release_type as gazellerelease_type
import headphones
from headphones.common import USER_AGENT
from headphones import logger, db, helpers, classes, sab, nzbget, request
@@ -1076,6 +1077,10 @@ def send_to_downloader(data, bestqual, album):
logger.info(u"Sending PushBullet notification")
pushbullet = notifiers.PUSHBULLET()
pushbullet.notify(name, "Download started")
+ if headphones.CONFIG.JOIN_ENABLED and headphones.CONFIG.JOIN_ONSNATCH:
+ logger.info(u"Sending Join notification")
+ join = notifiers.JOIN()
+ join.notify(name, "Download started")
if headphones.CONFIG.SLACK_ENABLED and headphones.CONFIG.SLACK_ONSNATCH:
logger.info(u"Sending Slack notification")
slack = notifiers.SLACK()
@@ -1564,16 +1569,45 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None,
if apolloobj and apolloobj.logged_in():
logger.info(u"Searching %s..." % provider)
all_torrents = []
+
+ # Specify release types to filter by
+ if album['Type'] == 'Album':
+ album_type = [gazellerelease_type.ALBUM]
+ if album['Type'] == 'Soundtrack':
+ album_type = [gazellerelease_type.SOUNDTRACK]
+ if album['Type'] == 'EP':
+ album_type = [gazellerelease_type.EP]
+ # No musicbrainz match for this type
+ #if album['Type'] == 'Anthology':
+ # album_type = [gazellerelease_type.ANTHOLOGY]
+ if album['Type'] == 'Compilation':
+ album_type = [gazellerelease_type.COMPILATION]
+ if album['Type'] == 'DJ-mix':
+ album_type = [gazellerelease_type.DJ_MIX]
+ if album['Type'] == 'Single':
+ album_type = [gazellerelease_type.SINGLE]
+ if album['Type'] == 'Live':
+ album_type = [gazellerelease_type.LIVE_ALBUM]
+ if album['Type'] == 'Remix':
+ album_type = [gazellerelease_type.REMIX]
+ if album['Type'] == 'Bootleg':
+ album_type = [gazellerelease_type.BOOTLEG]
+ if album['Type'] == 'Interview':
+ album_type = [gazellerelease_type.INTERVIEW]
+ if album['Type'] == 'Mixtape/Street':
+ album_type = [gazellerelease_type.MIXTAPE]
+
for search_format in search_formats:
if usersearchterm:
all_torrents.extend(
apolloobj.search_torrents(searchstr=usersearchterm, format=search_format,
- encoding=bitrate_string)['results'])
+ encoding=bitrate_string, releasetype=album_type)['results'])
else:
all_torrents.extend(apolloobj.search_torrents(artistname=semi_clean_artist_term,
groupname=semi_clean_album_term,
format=search_format,
- encoding=bitrate_string)['results'])
+ encoding=bitrate_string,
+ releasetype=album_type)['results'])
# filter on format, size, and num seeders
logger.info(u"Filtering torrents by format, maximum size, and minimum seeders...")
diff --git a/headphones/webserve.py b/headphones/webserve.py
index ee353fe2..6d95712a 100644
--- a/headphones/webserve.py
+++ b/headphones/webserve.py
@@ -537,7 +537,7 @@ class WebInterface(object):
myDB = db.DBConnection()
upcoming = myDB.select(
"SELECT * from albums WHERE ReleaseDate > date('now') order by ReleaseDate ASC")
- wanted = myDB.select("SELECT * from albums WHERE Status='Wanted'")
+ wanted = myDB.select("SELECT * from albums WHERE Status='Wanted' order by ReleaseDate ASC")
return serve_template(templatename="upcoming.html", title="Upcoming", upcoming=upcoming,
wanted=wanted)
@@ -1412,7 +1412,11 @@ class WebInterface(object):
"slack_url": headphones.CONFIG.SLACK_URL,
"slack_channel": headphones.CONFIG.SLACK_CHANNEL,
"slack_emoji": headphones.CONFIG.SLACK_EMOJI,
- "slack_onsnatch": checked(headphones.CONFIG.SLACK_ONSNATCH)
+ "slack_onsnatch": checked(headphones.CONFIG.SLACK_ONSNATCH),
+ "join_enabled": checked(headphones.CONFIG.JOIN_ENABLED),
+ "join_onsnatch": checked(headphones.CONFIG.JOIN_ONSNATCH),
+ "join_apikey": headphones.CONFIG.JOIN_APIKEY,
+ "join_deviceid": headphones.CONFIG.JOIN_DEVICEID
}
for k, v in config.iteritems():
@@ -1480,7 +1484,8 @@ class WebInterface(object):
"osx_notify_enabled", "osx_notify_onsnatch", "boxcar_enabled", "boxcar_onsnatch",
"songkick_enabled", "songkick_filter_enabled",
"mpc_enabled", "email_enabled", "email_ssl", "email_tls", "email_onsnatch",
- "customauth", "idtag", "deluge_paused"
+ "customauth", "idtag", "deluge_paused",
+ "join_enabled", "join_onsnatch"
]
for checked_config in checked_configs:
if checked_config not in kwargs:
@@ -1749,6 +1754,12 @@ class WebInterface(object):
telegram = notifiers.TELEGRAM()
telegram.notify("it works!", "lazers pew pew")
+ @cherrypy.expose
+ def testJoin(self):
+ logger.info("Testing Join notifications")
+ join = notifiers.JOIN()
+ join.notify("it works!", "Test message")
+
class Artwork(object):
@cherrypy.expose
diff --git a/lib/cherrypy/scaffold/static/made_with_cherrypy_small.png b/lib/cherrypy/scaffold/static/made_with_cherrypy_small.png
index c3aafeed..724f9d72 100644
Binary files a/lib/cherrypy/scaffold/static/made_with_cherrypy_small.png and b/lib/cherrypy/scaffold/static/made_with_cherrypy_small.png differ