mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-19 18:15:31 +01:00
v0.5.12
This commit is contained in:
6
.pep8
6
.pep8
@@ -1,5 +1,4 @@
|
||||
[pep8]
|
||||
# E111 indentation is not a multiple of four
|
||||
# E121 continuation line under-indented for hanging indent
|
||||
# E122 continuation line missing indentation or outdented
|
||||
# E124 closing bracket does not match visual indentation
|
||||
@@ -10,8 +9,7 @@
|
||||
# E261 at least two spaces before inline comment
|
||||
# E262 inline comment should start with '# '
|
||||
# E265 block comment should start with '# '
|
||||
# E302 expected 2 blank lines, found 1
|
||||
# E501 line too long (312 > 160 characters)
|
||||
# E502 the backslash is redundant between brackets
|
||||
ignore = E111,E121,E122,E123,E124,E125,E126,E127,E128,E261,E262,E265,E302,E501,E502
|
||||
max-line-length = 160
|
||||
ignore = E121,E122,E124,E125,E126,E127,E128,E261,E262,E265,E501,E502
|
||||
max-line-length = 160
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## v0.5.12
|
||||
Released 25 February 2016
|
||||
|
||||
This is mostly a hotfix update
|
||||
|
||||
Highlights:
|
||||
* Added: Experimental Deluge Support
|
||||
* Fixed: Some pep8 stuff
|
||||
* Improved: Use curly braces for pathrender optional variables
|
||||
|
||||
The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/v0.5.11...v0.5.12).
|
||||
|
||||
## v0.5.11
|
||||
Released 20 February 2016
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
**Master Branch:** [](https://travis-ci.org/rembo10/headphones)
|
||||
**Develop Branch:** [](https://travis-ci.org/rembo10/headphones)
|
||||
|
||||
Headphones is an automated music downloader for NZB and Torrent, written in Python. It supports SABnzbd, NZBget, Transmission, µTorrent and Blackhole.
|
||||
Headphones is an automated music downloader for NZB and Torrent, written in Python. It supports SABnzbd, NZBget, Transmission, µTorrent, Deluge and Blackhole.
|
||||
|
||||
## Support & Discuss
|
||||
You are free to join the Headphones support community on IRC where you can ask questions, hang around and discuss anything related to HP.
|
||||
|
||||
@@ -311,6 +311,7 @@
|
||||
<input type="radio" name="torrent_downloader" id="torrent_downloader_blackhole" value="0" ${config['torrent_downloader_blackhole']}> Black Hole
|
||||
<input type="radio" name="torrent_downloader" id="torrent_downloader_transmission" value="1" ${config['torrent_downloader_transmission']}> Transmission
|
||||
<input type="radio" name="torrent_downloader" id="torrent_downloader_utorrent" value="2" ${config['torrent_downloader_utorrent']}> uTorrent (Beta)
|
||||
<input type="radio" name="torrent_downloader" id="torrent_downloader_deluge" value="3" ${config['torrent_downloader_deluge']}> Deluge (Beta)
|
||||
</fieldset>
|
||||
<fieldset id="torrent_blackhole_options">
|
||||
<div class="row">
|
||||
@@ -385,6 +386,35 @@
|
||||
<input type="text" name="utorrent_label" value="${config['utorrent_label']}" size="30">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset id="deluge_options">
|
||||
<div class="row">
|
||||
<label>Deluge WebUI Host and Port</label>
|
||||
<input type="text" name="deluge_host" value="${config['deluge_host']}" size="30">
|
||||
<small>Usually http://localhost:8112 (requires WebUI plugin)</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Deluge Password</label>
|
||||
<input type="password" name="deluge_password" value="${config['deluge_password']}" size="30">
|
||||
</div>
|
||||
<div class="row">
|
||||
<small>Note: With Deluge, you can specify a different download directory for downloads sent from Headphones.
|
||||
Set it in the Music Download Directory below</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Deluge Label</label>
|
||||
<input type="text" name="deluge_label" value="${config['deluge_label']}" size="30">
|
||||
<small>Labels shouldn't contain spaces (requires Label plugin)</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Move When Completed</label>
|
||||
<input type="text" name="deluge_done_directory" value="${config['deluge_done_directory']}" size="30">
|
||||
<small>Directory where Deluge should move completed downloads</small>
|
||||
</div>
|
||||
<div class="row checkbox">
|
||||
<label>Add Torrent Paused</label>
|
||||
<input type="checkbox" name="deluge_paused" value="1" ${config['deluge_paused']}>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset id="general_torrent_options">
|
||||
<div class="row">
|
||||
<label>Minimum seeders</label>
|
||||
@@ -858,7 +888,7 @@
|
||||
<div class="row">
|
||||
as <input type="text" class="override-float" name="album_art_format" value="${config['album_art_format']}" size="10">.jpg
|
||||
</div>
|
||||
<small>Use $Artist/$artist, $Album/$album, $Year/$year</small>
|
||||
<small>Use $Artist/$artist, $Album/$album, $Year/$year, put optional variables in square brackets, use single-quote marks to escape square brackets literally ('[', ']').</small>
|
||||
</div>
|
||||
<div class="row checkbox left clearfix nopad">
|
||||
<label>
|
||||
@@ -1222,6 +1252,23 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<div class="row checkbox left">
|
||||
<input type="checkbox" class="bigcheck" name="telegram_enabled" id="telegram" value="1" ${config['telegram_enabled']} /><label for="telegram"><span class="option">Telegram</span></label>
|
||||
</div>
|
||||
<div id="telegramoptions">
|
||||
<div class="row">
|
||||
<label>Bot Token</label><input type="text" name="telegram_token" value="${config['telegram_token']}" size="50"><small>Contact <a href="http://telegram.me/BotFather">@BotFather</a> to create a bot and get its token</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>User ID</label><input type="text" name="telegram_userid" value="${config['telegram_userid']}" size="50"><small>Contact <a href="http://telegram.me/myidbot">@myidbot</a> to get your user ID</small>
|
||||
</div>
|
||||
<div class="row checkbox">
|
||||
<input type="checkbox" name="telegram_onsnatch" value="1" ${config['telegram_onsnatch']} /><label>Notify on snatch?</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -1236,14 +1283,13 @@
|
||||
<div class="row">
|
||||
<label>Folder Format</label>
|
||||
<input type="text" name="folder_format" value="${config['folder_format']}" size="43">
|
||||
<small>Use: $Artist/$artist, $SortArtist/$sortartist, $Album/$album, $Year/$year, $Type/$type (release type) and $First/$first (first letter in artist name), $OriginalFolder/$originalfolder (downloaded directory name)
|
||||
E.g.: $Type/$First/$artist/$album [$year] = Album/G/girl talk/all day [2010]</small>
|
||||
<small>Use: $Artist/$artist, $SortArtist/$sortartist, $Album/$album, $Year/$year, $Type/$type (release type) and $First/$first (first letter in artist name), $OriginalFolder/$originalfolder (downloaded directory name). Put optional variables in square brackets, use single-quote marks to escape square brackets literally ('[', ']').<br>E.g.: $Type/$First/$artist/$album '['$year']' = Album/G/girl talk/all day [2010]</small>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>File Format</label>
|
||||
<input type="text" name="file_format" value="${config['file_format']}" size="43">
|
||||
<small>Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year</small>
|
||||
<small>Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year. Put optional variables in square brackets, use single-quote marks to escape square brackets literally ('[', ']').</small>
|
||||
</div>
|
||||
<div class="checkbox row clearfix">
|
||||
<input type="checkbox" name="file_underscores" id="file_underscores" value="1" ${config['file_underscores']}/><label>Use underscores instead of spaces</label>
|
||||
@@ -2003,6 +2049,26 @@
|
||||
}
|
||||
});
|
||||
|
||||
if ($("#telegram").is(":checked"))
|
||||
{
|
||||
$("#telegramoptions").show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#telegramoptions").hide();
|
||||
}
|
||||
|
||||
$("#telegram").click(function(){
|
||||
if ($("#telegram").is(":checked"))
|
||||
{
|
||||
$("#telegramoptions").slideDown();
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#telegramoptions").slideUp();
|
||||
}
|
||||
});
|
||||
|
||||
if ($("#osx_notify").is(":checked"))
|
||||
{
|
||||
$("#osx_notify_options").show();
|
||||
@@ -2159,19 +2225,25 @@
|
||||
|
||||
if ($("#torrent_downloader_blackhole").is(":checked"))
|
||||
{
|
||||
$("#transmission_options,#utorrent_options").hide();
|
||||
$("#transmission_options,#utorrent_options,#deluge_options").hide();
|
||||
$("#torrent_blackhole_options").show();
|
||||
}
|
||||
if ($("#torrent_downloader_transmission").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#utorrent_options").hide();
|
||||
$("#torrent_blackhole_options,#utorrent_options,#deluge_options").hide();
|
||||
$("#transmission_options").show();
|
||||
}
|
||||
if ($("#torrent_downloader_utorrent").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#transmission_options").hide();
|
||||
$("#torrent_blackhole_options,#transmission_options,#deluge_options").hide();
|
||||
$("#utorrent_options").show();
|
||||
}
|
||||
if ($("#torrent_downloader_deluge").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#transmission_options,#utorrent_options").hide();
|
||||
$("#deluge_options").show();
|
||||
}
|
||||
|
||||
|
||||
$('input[type=radio]').change(function(){
|
||||
if ($("#preferred_bitrate").is(":checked"))
|
||||
@@ -2208,15 +2280,19 @@
|
||||
}
|
||||
if ($("#torrent_downloader_blackhole").is(":checked"))
|
||||
{
|
||||
$("#transmission_options,#utorrent_options").fadeOut("fast", function() { $("#torrent_blackhole_options").fadeIn() });
|
||||
$("#transmission_options,#utorrent_options,#deluge_options").fadeOut("fast", function() { $("#torrent_blackhole_options").fadeIn() });
|
||||
}
|
||||
if ($("#torrent_downloader_transmission").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#utorrent_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() });
|
||||
$("#torrent_blackhole_options,#utorrent_options,#deluge_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() });
|
||||
}
|
||||
if ($("#torrent_downloader_utorrent").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#transmission_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() });
|
||||
$("#torrent_blackhole_options,#transmission_options,#deluge_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() });
|
||||
}
|
||||
if ($("#torrent_downloader_deluge").is(":checked"))
|
||||
{
|
||||
$("#torrent_blackhole_options,#utorrent_options,#transmission_options").fadeOut("fast", function() { $("#deluge_options").fadeIn() });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ MIRRORLIST = ["musicbrainz.org", "headphones", "custom"]
|
||||
|
||||
UMASK = None
|
||||
|
||||
|
||||
def initialize(config_file):
|
||||
with INIT_LOCK:
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from headphones.unittestcompat import TestCase
|
||||
|
||||
import headphones.albumart
|
||||
|
||||
|
||||
# no tests...
|
||||
class AlbumArtTest(TestCase):
|
||||
def test_nothing(self):
|
||||
|
||||
@@ -15,6 +15,7 @@ def bool_int(value):
|
||||
value = 0
|
||||
return int(bool(value))
|
||||
|
||||
|
||||
class path(str):
|
||||
"""Internal 'marker' type for paths in config."""
|
||||
|
||||
@@ -66,7 +67,12 @@ _CONFIG_DEFINITIONS = {
|
||||
'CUSTOMSLEEP': (int, 'General', 1),
|
||||
'CUSTOMUSER': (str, 'General', ''),
|
||||
'DELETE_LOSSLESS_FILES': (int, 'General', 1),
|
||||
'DESTINATION_DIR': (path, 'General', ''),
|
||||
'DELUGE_HOST': (str, 'Deluge', ''),
|
||||
'DELUGE_PASSWORD': (str, 'Deluge', ''),
|
||||
'DELUGE_LABEL': (str, 'Deluge', ''),
|
||||
'DELUGE_DONE_DIRECTORY': (str, 'Deluge', ''),
|
||||
'DELUGE_PAUSED': (int, 'Deluge', 0),
|
||||
'DESTINATION_DIR': (str, 'General', ''),
|
||||
'DETECT_BITRATE': (int, 'General', 0),
|
||||
'DO_NOT_PROCESS_UNMATCHED': (int, 'General', 0),
|
||||
'DOWNLOAD_DIR': (path, 'General', ''),
|
||||
@@ -248,7 +254,11 @@ _CONFIG_DEFINITIONS = {
|
||||
'SUBSONIC_PASSWORD': (str, 'Subsonic', ''),
|
||||
'SUBSONIC_USERNAME': (str, 'Subsonic', ''),
|
||||
'SYNOINDEX_ENABLED': (int, 'Synoindex', 0),
|
||||
'TORRENTBLACKHOLE_DIR': (path, 'General', ''),
|
||||
'TELEGRAM_TOKEN': (str, 'Telegram', ''),
|
||||
'TELEGRAM_USERID': (str, 'Telegram', ''),
|
||||
'TELEGRAM_ENABLED': (int, 'Telegram', 0),
|
||||
'TELEGRAM_ONSNATCH': (int, 'Telegram', 0),
|
||||
'TORRENTBLACKHOLE_DIR': (str, 'General', ''),
|
||||
'TORRENT_DOWNLOADER': (int, 'General', 0),
|
||||
'TORRENT_REMOVAL_INTERVAL': (int, 'General', 720),
|
||||
'TORZNAB': (int, 'Torznab', 0),
|
||||
|
||||
@@ -5,6 +5,7 @@ import re
|
||||
import unittestcompat
|
||||
from unittestcompat import TestCase, TestArgs
|
||||
|
||||
|
||||
class ConfigApiTest(TestCase):
|
||||
""" Common tests for headphones.Config
|
||||
|
||||
|
||||
460
headphones/deluge.py
Normal file
460
headphones/deluge.py
Normal file
@@ -0,0 +1,460 @@
|
||||
# This file is part of Headphones.
|
||||
#
|
||||
# Headphones is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Headphones is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Parts of this file are a part of SickRage.
|
||||
# Author: Mr_Orange <mr_orange@hotmail.it>
|
||||
# URL: http://code.google.com/p/sickbeard/
|
||||
# Adapted for Headphones by <noamgit@gmail.com>
|
||||
# URL: https://github.com/noam09
|
||||
#
|
||||
# SickRage is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# SickRage is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from headphones import logger
|
||||
#from headphones import request
|
||||
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
import headphones
|
||||
import requests
|
||||
from base64 import b64encode
|
||||
import traceback
|
||||
|
||||
delugeweb_auth = {}
|
||||
delugeweb_url = ''
|
||||
|
||||
|
||||
def addTorrent(link, data=None):
|
||||
try:
|
||||
result = {}
|
||||
retid = False
|
||||
|
||||
if link.startswith('magnet:'):
|
||||
logger.debug('Deluge: Got a magnet link: %s' % link)
|
||||
result = {'type': 'magnet',
|
||||
'url': link}
|
||||
retid = _add_torrent_magnet(result)
|
||||
|
||||
elif link.startswith('http://') or link.startswith('https://'):
|
||||
logger.debug('Deluge: Got a URL: %s' % link)
|
||||
user_agent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2243.2 Safari/537.36'
|
||||
headers = {'User-Agent': user_agent}
|
||||
torrentfile = ''
|
||||
logger.debug('Deluge: Trying to download (GET)')
|
||||
try:
|
||||
r = requests.get(link, headers=headers)
|
||||
if r.status_code == 200:
|
||||
logger.debug('Deluge: 200 OK')
|
||||
torrentfile = r.text
|
||||
#for chunk in r.iter_content(chunk_size=1024):
|
||||
# if chunk: # filter out keep-alive new chunks
|
||||
# torrentfile = torrentfile + chunk
|
||||
else:
|
||||
logger.debug('Deluge: Trying to GET %s returned status %d' % (link, r.status_code))
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.debug('Deluge: Download failed: %s' % str(e))
|
||||
if 'announce' not in torrentfile[:40]:
|
||||
logger.debug('Deluge: Contents of %s doesn\'t look like a torrent file' % link)
|
||||
return False
|
||||
# Extract torrent name from .torrent
|
||||
try:
|
||||
logger.debug('Deluge: Getting torrent name length')
|
||||
name_length = int(re.findall('name([0-9]*)\:.*?\:', torrentfile)[0])
|
||||
logger.debug('Deluge: Getting torrent name')
|
||||
name = re.findall('name[0-9]*\:(.*?)\:', torrentfile)[0][:name_length]
|
||||
except Exception as e:
|
||||
logger.debug('Deluge: Could not get torrent name, getting file name')
|
||||
# get last part of link/path (name only)
|
||||
name = link.split('\\')[-1].split('/')[-1]
|
||||
# remove '.torrent' suffix
|
||||
if name[-len('.torrent'):] == '.torrent':
|
||||
name = name[:-len('.torrent')]
|
||||
logger.debug('Deluge: Sending Deluge torrent with name %s and content [%s...]' % (name, torrentfile[:40]))
|
||||
result = {'type': 'torrent',
|
||||
'name': name,
|
||||
'content': torrentfile}
|
||||
retid = _add_torrent_file(result)
|
||||
|
||||
# elif link.endswith('.torrent') or data:
|
||||
elif not (link.startswith('http://') or link.startswith('https://')):
|
||||
if data:
|
||||
logger.debug('Deluge: Getting .torrent data')
|
||||
torrentfile = data
|
||||
else:
|
||||
logger.debug('Deluge: Getting .torrent file')
|
||||
with open(link, 'rb') as f:
|
||||
torrentfile = f.read()
|
||||
# Extract torrent name from .torrent
|
||||
try:
|
||||
logger.debug('Deluge: Getting torrent name length')
|
||||
name_length = int(re.findall('name([0-9]*)\:.*?\:', torrentfile)[0])
|
||||
logger.debug('Deluge: Getting torrent name')
|
||||
name = re.findall('name[0-9]*\:(.*?)\:', torrentfile)[0][:name_length]
|
||||
except Exception as e:
|
||||
logger.debug('Deluge: Could not get torrent name, getting file name')
|
||||
# get last part of link/path (name only)
|
||||
name = link.split('\\')[-1].split('/')[-1]
|
||||
# remove '.torrent' suffix
|
||||
if name[-len('.torrent'):] == '.torrent':
|
||||
name = name[:-len('.torrent')]
|
||||
logger.debug('Deluge: Sending Deluge torrent with name %s and content [%s...]' % (name, torrentfile[:40]))
|
||||
result = {'type': 'torrent',
|
||||
'name': name,
|
||||
'content': torrentfile}
|
||||
retid = _add_torrent_file(result)
|
||||
|
||||
else:
|
||||
logger.error('Deluge: Unknown file type: %s' % link)
|
||||
|
||||
if retid:
|
||||
logger.info('Deluge: Torrent sent to Deluge successfully (%s)' % retid)
|
||||
return retid
|
||||
else:
|
||||
logger.info('Deluge returned status %s' % retid)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
formatted_lines = traceback.format_exc().splitlines()
|
||||
logger.error('; '.join(formatted_lines))
|
||||
|
||||
|
||||
def getTorrentFolder(result):
|
||||
logger.debug('Deluge: Get torrent folder name')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
try:
|
||||
post_data = json.dumps({"method": "web.get_torrent_status",
|
||||
"params": [
|
||||
result['hash'],
|
||||
["total_done"]
|
||||
],
|
||||
"id": 22})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result['total_done'] = json.loads(response.text)['result']['total_done']
|
||||
|
||||
tries = 0
|
||||
while result['total_done'] == 0 and tries < 10:
|
||||
tries += 1
|
||||
time.sleep(5)
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result['total_done'] = json.loads(response.text)['result']['total_done']
|
||||
|
||||
post_data = json.dumps({"method": "web.get_torrent_status",
|
||||
"params": [
|
||||
result['hash'],
|
||||
[
|
||||
"name",
|
||||
"save_path",
|
||||
"total_size",
|
||||
"num_files",
|
||||
"message",
|
||||
"tracker",
|
||||
"comment"
|
||||
]
|
||||
],
|
||||
"id": 23})
|
||||
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
|
||||
result['save_path'] = json.loads(response.text)['result']['save_path']
|
||||
result['name'] = json.loads(response.text)['result']['name']
|
||||
|
||||
return json.loads(response.text)['result']['name']
|
||||
except Exception as e:
|
||||
logger.debug('Deluge: Could not get torrent folder name: %s' % str(e))
|
||||
|
||||
|
||||
def removeTorrent(torrentid, remove_data=False):
|
||||
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
result = False
|
||||
post_data = json.dumps({"method": "core.remove_torrent",
|
||||
"params": [
|
||||
torrentid,
|
||||
remove_data
|
||||
],
|
||||
"id": 25})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result = json.loads(response.text)['result']
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _get_auth():
|
||||
logger.debug('Deluge: Authenticating...')
|
||||
global delugeweb_auth, delugeweb_url
|
||||
delugeweb_auth = {}
|
||||
|
||||
delugeweb_host = headphones.CONFIG.DELUGE_HOST
|
||||
delugeweb_password = headphones.CONFIG.DELUGE_PASSWORD
|
||||
|
||||
if not delugeweb_host.startswith('http'):
|
||||
delugeweb_host = 'http://%s' % delugeweb_host
|
||||
|
||||
if delugeweb_host.endswith('/'):
|
||||
delugeweb_host = delugeweb_host[:-1]
|
||||
|
||||
delugeweb_url = delugeweb_host + '/json'
|
||||
|
||||
post_data = json.dumps({"method": "auth.login",
|
||||
"params": [delugeweb_password],
|
||||
"id": 1})
|
||||
try:
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
# , verify=TORRENT_VERIFY_CERT)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
auth = json.loads(response.text)["result"]
|
||||
delugeweb_auth = response.cookies
|
||||
|
||||
post_data = json.dumps({"method": "web.connected",
|
||||
"params": [],
|
||||
"id": 10})
|
||||
try:
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
# , verify=TORRENT_VERIFY_CERT)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
connected = json.loads(response.text)['result']
|
||||
|
||||
if not connected:
|
||||
post_data = json.dumps({"method": "web.get_hosts",
|
||||
"params": [],
|
||||
"id": 11})
|
||||
try:
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
# , verify=TORRENT_VERIFY_CERT)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
delugeweb_hosts = json.loads(response.text)['result']
|
||||
if len(delugeweb_hosts) == 0:
|
||||
logger.error('Deluge: WebUI does not contain daemons')
|
||||
return None
|
||||
|
||||
post_data = json.dumps({"method": "web.connect",
|
||||
"params": [delugeweb_hosts[0][0]],
|
||||
"id": 11})
|
||||
|
||||
try:
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
# , verify=TORRENT_VERIFY_CERT)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
post_data = json.dumps({"method": "web.connected",
|
||||
"params": [],
|
||||
"id": 10})
|
||||
|
||||
try:
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
# , verify=TORRENT_VERIFY_CERT)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
connected = json.loads(response.text)['result']
|
||||
|
||||
if not connected:
|
||||
logger.error('Deluge: WebUI could not connect to daemon')
|
||||
return None
|
||||
|
||||
return auth
|
||||
|
||||
|
||||
def _add_torrent_magnet(result):
|
||||
logger.debug('Deluge: Adding magnet')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
try:
|
||||
post_data = json.dumps({"method": "core.add_torrent_magnet",
|
||||
"params": [result['url'], {}],
|
||||
"id": 2})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result['hash'] = json.loads(response.text)['result']
|
||||
logger.debug('Deluge: Response was %s' % str(json.loads(response.text)['result']))
|
||||
return json.loads(response.text)['result']
|
||||
except Exception as e:
|
||||
logger.error('Deluge: Adding torrent magnet failed: %s' % str(e))
|
||||
|
||||
'''
|
||||
def _add_torrent_url(result):
|
||||
logger.debug('Deluge: Adding URL')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
try:
|
||||
post_data = json.dumps({"method": "web.download_torrent_from_url",
|
||||
"params": [result['url'], {}],
|
||||
"id": 2})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result['hash'] = json.loads(response.text)['result']
|
||||
logger.debug('Deluge: Response was %s' % str(json.loads(response.text)['result']))
|
||||
return json.loads(response.text)['result']
|
||||
except Exception as e:
|
||||
logger.error('Deluge: Adding torrent URL failed: %s' % str(e))
|
||||
'''
|
||||
|
||||
|
||||
def _add_torrent_file(result):
|
||||
logger.debug('Deluge: Adding file')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
try:
|
||||
# content is torrent file contents that needs to be encoded to base64
|
||||
post_data = json.dumps({"method": "core.add_torrent_file",
|
||||
"params": [result['name'] + '.torrent', b64encode(result['content'].encode('utf8')), {}],
|
||||
"id": 2})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
result['hash'] = json.loads(response.text)['result']
|
||||
logger.debug('Deluge: Response was %s' % str(json.loads(response.text)['result']))
|
||||
return json.loads(response.text)['result']
|
||||
except Exception as e:
|
||||
logger.error('Deluge: Adding torrent file failed: %s' % str(e))
|
||||
formatted_lines = traceback.format_exc().splitlines()
|
||||
logger.error('; '.join(formatted_lines))
|
||||
|
||||
|
||||
def setTorrentLabel(result):
|
||||
logger.debug('Deluge: Setting label')
|
||||
label = headphones.CONFIG.DELUGE_LABEL
|
||||
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
if ' ' in label:
|
||||
logger.error('Deluge: Invalid label. Label can\'t contain spaces - replacing with underscores')
|
||||
label = label.replace(' ', '_')
|
||||
if label:
|
||||
# check if label already exists and create it if not
|
||||
post_data = json.dumps({"method": 'label.get_labels',
|
||||
"params": [],
|
||||
"id": 3})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
labels = json.loads(response.text)['result']
|
||||
|
||||
if labels is not None:
|
||||
if label not in labels:
|
||||
try:
|
||||
logger.debug('Deluge: %s label doesn\'t exist in Deluge, let\'s add it' % label)
|
||||
post_data = json.dumps({"method": 'label.add',
|
||||
"params": [label],
|
||||
"id": 4})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
logger.debug('Deluge: %s label added to Deluge' % label)
|
||||
except Exception as e:
|
||||
logger.error('Deluge: Setting label failed: %s' % str(e))
|
||||
formatted_lines = traceback.format_exc().splitlines()
|
||||
logger.error('; '.join(formatted_lines))
|
||||
|
||||
# add label to torrent
|
||||
post_data = json.dumps({"method": 'label.set_torrent',
|
||||
"params": [result['hash'], label],
|
||||
"id": 5})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
logger.debug('Deluge: %s label added to torrent' % label)
|
||||
else:
|
||||
logger.debug('Deluge: Label plugin not detected')
|
||||
return False
|
||||
|
||||
return not json.loads(response.text)['error']
|
||||
|
||||
|
||||
def setSeedRatio(result):
|
||||
logger.debug('Deluge: Setting seed ratio')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
ratio = None
|
||||
if result['ratio']:
|
||||
ratio = result['ratio']
|
||||
|
||||
if ratio:
|
||||
post_data = json.dumps({"method": "core.set_torrent_stop_at_ratio",
|
||||
"params": [result['hash'], True],
|
||||
"id": 5})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
post_data = json.dumps({"method": "core.set_torrent_stop_ratio",
|
||||
"params": [result['hash'], float(ratio)],
|
||||
"id": 6})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
|
||||
return not json.loads(response.text)['error']
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def setTorrentPath(result):
|
||||
logger.debug('Deluge: Setting download path')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
if headphones.CONFIG.DELUGE_DONE_DIRECTORY or headphones.CONFIG.DOWNLOAD_TORRENT_DIR:
|
||||
post_data = json.dumps({"method": "core.set_torrent_move_completed",
|
||||
"params": [result['hash'], True],
|
||||
"id": 7})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
|
||||
if headphones.CONFIG.DELUGE_DONE_DIRECTORY:
|
||||
move_to = headphones.CONFIG.DELUGE_DONE_DIRECTORY
|
||||
else:
|
||||
move_to = headphones.CONFIG.DOWNLOAD_TORRENT_DIR
|
||||
|
||||
if not os.path.exists(move_to):
|
||||
logger.debug('Deluge: %s directory doesn\'t exist, let\'s create it' % move_to)
|
||||
os.makedirs(move_to)
|
||||
post_data = json.dumps({"method": "core.set_torrent_move_completed_path",
|
||||
"params": [result['hash'], move_to],
|
||||
"id": 8})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
|
||||
return not json.loads(response.text)['error']
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def setTorrentPause(result):
|
||||
logger.debug('Deluge: Pausing torrent')
|
||||
if not any(delugeweb_auth):
|
||||
_get_auth()
|
||||
|
||||
if headphones.CONFIG.DELUGE_PAUSED:
|
||||
post_data = json.dumps({"method": "core.pause_torrent",
|
||||
"params": [[result['hash']]],
|
||||
"id": 9})
|
||||
response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth)
|
||||
|
||||
return not json.loads(response.text)['error']
|
||||
|
||||
return True
|
||||
@@ -25,6 +25,7 @@ class NewzbinAPIThrottled(HeadphonesException):
|
||||
Newzbin has throttled us, deal with it
|
||||
"""
|
||||
|
||||
|
||||
class SoftChrootError(HeadphonesException):
|
||||
"""
|
||||
Fatal errors in SoftChroot module
|
||||
|
||||
@@ -856,3 +856,36 @@ class Email(object):
|
||||
except Exception, e:
|
||||
logger.warn('Error sending Email: %s' % e)
|
||||
return False
|
||||
|
||||
|
||||
class TELEGRAM(object):
|
||||
|
||||
def notify(self, message, status):
|
||||
if not headphones.CONFIG.TELEGRAM_ENABLED:
|
||||
return
|
||||
|
||||
import requests
|
||||
|
||||
TELEGRAM_API = "https://api.telegram.org/bot%s/%s"
|
||||
|
||||
# Get configuration data
|
||||
token = headphones.CONFIG.TELEGRAM_TOKEN
|
||||
userid = headphones.CONFIG.TELEGRAM_USERID
|
||||
|
||||
# Construct message
|
||||
payload = {'chat_id': userid, 'text': status + ': ' + message}
|
||||
|
||||
# Send message to user using Telegram's Bot API
|
||||
try:
|
||||
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))
|
||||
sent_successfuly = False
|
||||
|
||||
logger.info(u"Telegram notifications sent.")
|
||||
return sent_successfuly
|
||||
|
||||
@@ -25,15 +25,16 @@
|
||||
* substitution variables, which start with dollar sign ($) and
|
||||
extend until next non-alphanumeric+underscore character
|
||||
(like $This and $5_that).
|
||||
* optional elements enclosed in square brackets, which render
|
||||
* optional elements enclosed in curly braces, which render
|
||||
nonempty value only if any variable or optional inside returned
|
||||
nonempty value, ignoring literals (like [\'[\'$That\']\' ]).
|
||||
nonempty value, ignoring literals (like {\'[\'$That\']\'}).
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from enum import Enum
|
||||
|
||||
__author__ = "Andrzej Ciarkowski <andrzej.ciarkowski@gmail.com>"
|
||||
|
||||
|
||||
class _PatternElement(object):
|
||||
'''ABC for hierarchy of path name renderer pattern elements.'''
|
||||
def render(self, replacement):
|
||||
@@ -41,11 +42,13 @@ class _PatternElement(object):
|
||||
'''Format this _PatternElement into string using provided substitution dictionary.'''
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class _Generator(_PatternElement):
|
||||
# pylint: disable=abstract-method
|
||||
'''Tagging interface for "content-generating" elements like replacement or optional block.'''
|
||||
pass
|
||||
|
||||
|
||||
class _Replacement(_Generator):
|
||||
'''Replacement variable, eg. $title.'''
|
||||
def __init__(self, pattern):
|
||||
@@ -90,20 +93,23 @@ class _OptionalBlock(_Generator):
|
||||
return u""
|
||||
|
||||
|
||||
_OPTIONAL_START = u'['
|
||||
_OPTIONAL_END = u']'
|
||||
_OPTIONAL_START = u'{'
|
||||
_OPTIONAL_END = u'}'
|
||||
_ESCAPE_CHAR = u'\''
|
||||
_REPLACEMENT_START = u'$'
|
||||
|
||||
|
||||
def _is_replacement_valid(c):
|
||||
# type: (str) -> bool
|
||||
return c.isalnum() or c == u'_'
|
||||
|
||||
|
||||
class _State(Enum):
|
||||
LITERAL = 0
|
||||
ESCAPE = 1
|
||||
REPLACEMENT = 2
|
||||
|
||||
|
||||
def _append_literal(scope, text):
|
||||
# type: ([_PatternElement], str) -> None
|
||||
'''Append literal text to the scope BUT ONLY if it's not an empty string.'''
|
||||
@@ -111,11 +117,13 @@ def _append_literal(scope, text):
|
||||
return
|
||||
scope.append(_LiteralText(text))
|
||||
|
||||
|
||||
class Warnings(Enum):
|
||||
'''Pattern parsing warnings, as stored withing warnings property of Pattern object after parsing.'''
|
||||
UNCLOSED_ESCAPE = 'Warnings.UNCLOSED_ESCAPE'
|
||||
UNCLOSED_OPTIONAL = 'Warnings.UNCLOSED_OPTIONAL'
|
||||
|
||||
|
||||
def _parse_pattern(pattern, warnings):
|
||||
# type: (str,MutableSet[Warnings]) -> [_PatternElement]
|
||||
'''Parse path pattern text into list of _PatternElements, put warnings into the provided set.'''
|
||||
@@ -188,6 +196,7 @@ def _parse_pattern(pattern, warnings):
|
||||
_append_literal(root_scope, pattern[start:])
|
||||
return root_scope
|
||||
|
||||
|
||||
class Pattern(object):
|
||||
'''Stores preparsed rename pattern for repeated use.
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ from beets import autotag
|
||||
from beets import config as beetsconfig
|
||||
from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError
|
||||
from beetsplug import lyrics as beetslyrics
|
||||
from headphones import notifiers, utorrent, transmission
|
||||
from headphones import notifiers, utorrent, transmission, deluge
|
||||
from headphones import db, albumart, librarysync
|
||||
from headphones import logger, helpers, request, mb, music_encoder
|
||||
|
||||
@@ -46,7 +46,10 @@ def checkFolder():
|
||||
if album['Kind'] == 'nzb':
|
||||
download_dir = headphones.CONFIG.DOWNLOAD_DIR
|
||||
else:
|
||||
download_dir = headphones.CONFIG.DOWNLOAD_TORRENT_DIR
|
||||
if headphones.CONFIG.DELUGE_DONE_DIRECTORY:
|
||||
download_dir = headphones.CONFIG.DELUGE_DONE_DIRECTORY
|
||||
else:
|
||||
download_dir = headphones.CONFIG.DOWNLOAD_TORRENT_DIR
|
||||
|
||||
album_path = os.path.join(download_dir, album['FolderName']).encode(
|
||||
headphones.SYS_ENCODING, 'replace')
|
||||
@@ -454,6 +457,8 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
|
||||
release['ArtistName'], release['AlbumTitle']))
|
||||
if headphones.CONFIG.TORRENT_DOWNLOADER == 1:
|
||||
torrent_removed = transmission.removeTorrent(hash, True)
|
||||
elif headphones.CONFIG.TORRENT_DOWNLOADER == 3: # Deluge
|
||||
torrent_removed = deluge.removeTorrent(hash, True)
|
||||
else:
|
||||
torrent_removed = utorrent.removeTorrent(hash, True)
|
||||
|
||||
@@ -533,6 +538,11 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
|
||||
pushbullet = notifiers.PUSHBULLET()
|
||||
pushbullet.notify(pushmessage, statusmessage)
|
||||
|
||||
if headphones.CONFIG.TELEGRAM_ENABLED:
|
||||
logger.info(u"Telegram request")
|
||||
telegram = notifiers.TELEGRAM()
|
||||
telegram.notify(pushmessage, statusmessage)
|
||||
|
||||
if headphones.CONFIG.TWITTER_ENABLED:
|
||||
logger.info(u"Sending Twitter notification")
|
||||
twitter = notifiers.TwitterNotifier()
|
||||
@@ -666,9 +676,9 @@ def renameNFO(albumpath):
|
||||
def moveFiles(albumpath, release, tracks):
|
||||
logger.info("Moving files: %s" % albumpath)
|
||||
try:
|
||||
date = release['ReleaseDate']
|
||||
date = release['ReleaseDate']
|
||||
except TypeError:
|
||||
date = u''
|
||||
date = u''
|
||||
year = date[:4]
|
||||
artist = release['ArtistName'].replace('/', '_')
|
||||
album = release['AlbumTitle'].replace('/', '_')
|
||||
|
||||
@@ -33,7 +33,7 @@ from pygazelle import format as gazelleformat
|
||||
import headphones
|
||||
from headphones.common import USER_AGENT
|
||||
from headphones import logger, db, helpers, classes, sab, nzbget, request
|
||||
from headphones import utorrent, transmission, notifiers, rutracker
|
||||
from headphones import utorrent, transmission, notifiers, rutracker, deluge
|
||||
from bencode import bencode, bdecode
|
||||
|
||||
|
||||
@@ -851,7 +851,7 @@ def send_to_downloader(data, bestqual, album):
|
||||
else:
|
||||
logger.error("Cannot save magnet link in blackhole. " \
|
||||
"Please switch your torrent downloader to " \
|
||||
"Transmission or uTorrent, or allow Headphones " \
|
||||
"Transmission, uTorrent or Deluge, or allow Headphones " \
|
||||
"to open or convert magnet links")
|
||||
return
|
||||
else:
|
||||
@@ -889,6 +889,48 @@ def send_to_downloader(data, bestqual, album):
|
||||
if seed_ratio is not None:
|
||||
transmission.setSeedRatio(torrentid, seed_ratio)
|
||||
|
||||
elif headphones.CONFIG.TORRENT_DOWNLOADER == 3: # Deluge
|
||||
logger.info("Sending torrent to Deluge")
|
||||
|
||||
try:
|
||||
# Add torrent
|
||||
if bestqual[3] == 'rutracker.org':
|
||||
torrentid = deluge.addTorrent('', data)
|
||||
else:
|
||||
torrentid = deluge.addTorrent(bestqual[2])
|
||||
|
||||
if not torrentid:
|
||||
logger.error("Error sending torrent to Deluge. Are you sure it's running? Maybe the torrent already exists?")
|
||||
return
|
||||
|
||||
# This pauses the torrent right after it is added
|
||||
if headphones.CONFIG.DELUGE_PAUSED:
|
||||
deluge.setTorrentPause({'hash': torrentid})
|
||||
|
||||
# Set Label
|
||||
if headphones.CONFIG.DELUGE_LABEL:
|
||||
deluge.setTorrentLabel({'hash': torrentid})
|
||||
|
||||
# Set Seed Ratio
|
||||
seed_ratio = get_seed_ratio(bestqual[3])
|
||||
if seed_ratio is not None:
|
||||
deluge.setSeedRatio({'hash': torrentid, 'ratio': seed_ratio})
|
||||
|
||||
# Set move-to directory
|
||||
if headphones.CONFIG.DELUGE_DONE_DIRECTORY:
|
||||
deluge.setTorrentPath({'hash': torrentid})
|
||||
|
||||
# I only just realized this function is useless...
|
||||
folder_name = deluge.getTorrentFolder({'hash': torrentid})
|
||||
if folder_name:
|
||||
logger.info('Torrent folder name: %s' % folder_name)
|
||||
else:
|
||||
logger.error('Torrent folder name could not be determined')
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
logger.error('Error sending torrent to Deluge: %s' % str(e))
|
||||
|
||||
else: # if headphones.CONFIG.TORRENT_DOWNLOADER == 2:
|
||||
logger.info("Sending torrent to uTorrent")
|
||||
|
||||
@@ -960,6 +1002,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.TELEGRAM_ENABLED and headphones.CONFIG.TELEGRAM_ONSNATCH:
|
||||
logger.info(u"Sending Telegram notification")
|
||||
telegram = notifiers.TELEGRAM()
|
||||
telegram.notify(name, "Download started")
|
||||
if headphones.CONFIG.TWITTER_ENABLED and headphones.CONFIG.TWITTER_ONSNATCH:
|
||||
logger.info(u"Sending Twitter notification")
|
||||
twitter = notifiers.TwitterNotifier()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
from headphones.exceptions import SoftChrootError
|
||||
|
||||
|
||||
class SoftChroot(object):
|
||||
""" SoftChroot provides SOFT chrooting for UI
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from headphones.unittestcompat import TestCase, TestArgs
|
||||
from headphones.softchroot import SoftChroot
|
||||
from headphones.exceptions import SoftChrootError
|
||||
|
||||
|
||||
class SoftChrootTest(TestCase):
|
||||
def test_create(self):
|
||||
""" create headphones.SoftChroot """
|
||||
|
||||
@@ -29,6 +29,7 @@ import headphones
|
||||
|
||||
_session_id = None
|
||||
|
||||
|
||||
def addTorrent(link, data=None):
|
||||
method = 'torrent-add'
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ _dummy = False
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] <= 6:
|
||||
_dummy = True
|
||||
|
||||
|
||||
def _d(f):
|
||||
def decorate(self, *args, **kw):
|
||||
if not _dummy:
|
||||
@@ -92,6 +93,7 @@ class TestCase(TC):
|
||||
# True indicates, that exception is handled
|
||||
return True
|
||||
|
||||
|
||||
def TestArgs(*parameters):
|
||||
def tuplify(x):
|
||||
if not isinstance(x, tuple):
|
||||
|
||||
@@ -1156,6 +1156,11 @@ class WebInterface(object):
|
||||
"transmission_host": headphones.CONFIG.TRANSMISSION_HOST,
|
||||
"transmission_username": headphones.CONFIG.TRANSMISSION_USERNAME,
|
||||
"transmission_password": headphones.CONFIG.TRANSMISSION_PASSWORD,
|
||||
"deluge_host": headphones.CONFIG.DELUGE_HOST,
|
||||
"deluge_password": headphones.CONFIG.DELUGE_PASSWORD,
|
||||
"deluge_label": headphones.CONFIG.DELUGE_LABEL,
|
||||
"deluge_done_directory": headphones.CONFIG.DELUGE_DONE_DIRECTORY,
|
||||
"deluge_paused": checked(headphones.CONFIG.DELUGE_PAUSED),
|
||||
"utorrent_host": headphones.CONFIG.UTORRENT_HOST,
|
||||
"utorrent_username": headphones.CONFIG.UTORRENT_USERNAME,
|
||||
"utorrent_password": headphones.CONFIG.UTORRENT_PASSWORD,
|
||||
@@ -1166,6 +1171,7 @@ class WebInterface(object):
|
||||
"torrent_downloader_blackhole": radio(headphones.CONFIG.TORRENT_DOWNLOADER, 0),
|
||||
"torrent_downloader_transmission": radio(headphones.CONFIG.TORRENT_DOWNLOADER, 1),
|
||||
"torrent_downloader_utorrent": radio(headphones.CONFIG.TORRENT_DOWNLOADER, 2),
|
||||
"torrent_downloader_deluge": radio(headphones.CONFIG.TORRENT_DOWNLOADER, 3),
|
||||
"download_dir": headphones.CONFIG.DOWNLOAD_DIR,
|
||||
"use_blackhole": checked(headphones.CONFIG.BLACKHOLE),
|
||||
"blackhole_dir": headphones.CONFIG.BLACKHOLE_DIR,
|
||||
@@ -1324,6 +1330,10 @@ class WebInterface(object):
|
||||
"pushbullet_onsnatch": checked(headphones.CONFIG.PUSHBULLET_ONSNATCH),
|
||||
"pushbullet_apikey": headphones.CONFIG.PUSHBULLET_APIKEY,
|
||||
"pushbullet_deviceid": headphones.CONFIG.PUSHBULLET_DEVICEID,
|
||||
"telegram_enabled": checked(headphones.CONFIG.TELEGRAM_ENABLED),
|
||||
"telegram_onsnatch": checked(headphones.CONFIG.TELEGRAM_ONSNATCH),
|
||||
"telegram_token": headphones.CONFIG.TELEGRAM_TOKEN,
|
||||
"telegram_userid": headphones.CONFIG.TELEGRAM_USERID,
|
||||
"subsonic_enabled": checked(headphones.CONFIG.SUBSONIC_ENABLED),
|
||||
"subsonic_host": headphones.CONFIG.SUBSONIC_HOST,
|
||||
"subsonic_username": headphones.CONFIG.SUBSONIC_USERNAME,
|
||||
@@ -1428,10 +1438,11 @@ class WebInterface(object):
|
||||
"synoindex_enabled", "pushover_enabled",
|
||||
"pushover_onsnatch", "pushbullet_enabled", "pushbullet_onsnatch", "subsonic_enabled",
|
||||
"twitter_enabled", "twitter_onsnatch",
|
||||
"telegram_enabled", "telegram_onsnatch",
|
||||
"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"
|
||||
"customauth", "idtag", "deluge_paused"
|
||||
]
|
||||
for checked_config in checked_configs:
|
||||
if checked_config not in kwargs:
|
||||
@@ -1692,6 +1703,12 @@ class WebInterface(object):
|
||||
pushbullet = notifiers.PUSHBULLET()
|
||||
pushbullet.notify("it works!", "Test message")
|
||||
|
||||
@cherrypy.expose
|
||||
def testTelegram(self):
|
||||
logger.info("Testing Telegram notifications")
|
||||
telegram = notifiers.TELEGRAM()
|
||||
telegram.notify("it works!", "lazers pew pew")
|
||||
|
||||
|
||||
class Artwork(object):
|
||||
@cherrypy.expose
|
||||
|
||||
Reference in New Issue
Block a user