mirror of
https://github.com/rembo10/headphones.git
synced 2026-06-26 04:23:51 +01:00
Merge remote-tracking branch 'noam09/develop' into develop
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
@@ -2003,6 +2050,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 +2226,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 +2281,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() });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+11
-2
@@ -66,7 +66,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 +253,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),
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
# 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 not (link.startswith('http://') or link.startswith('https://')):
|
||||
#elif link.endswith('.torrent') or data:
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
+48
-2
@@ -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()
|
||||
|
||||
+17
-1
@@ -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,11 @@ 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