mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-21 16:34:01 +01:00
Cleanup search code. Add support for magnet links conversion. Fixes #1926.
This commit is contained in:
@@ -317,10 +317,27 @@
|
|||||||
<input type="text" name="torrentblackhole_dir" value="${config['torrentblackhole_dir']}" size="50">
|
<input type="text" name="torrentblackhole_dir" value="${config['torrentblackhole_dir']}" size="50">
|
||||||
<small>Folder your Download program watches for Torrents</small>
|
<small>Folder your Download program watches for Torrents</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="row checkbox">
|
|
||||||
<label>Open Magnet Links</label>
|
<div class="row">
|
||||||
<input type="checkbox" name="open_magnet_links" value="1" ${config['open_magnet_links']}>
|
<label>Magnet links</label>
|
||||||
<small>Allow Headphones to open magnet links</small>
|
|
||||||
|
<label class="inline" title="Invoke shell command to open magnet URL.">
|
||||||
|
<input type="radio" name="magnet_links" id="magnet_links_0" value="0" ${config['magnet_links_0']}>
|
||||||
|
Ignore
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="inline" title="Use external service to convert magnet links into torrents.">
|
||||||
|
<input type="radio" name="magnet_links" id="magnet_links_1" value="1" ${config['magnet_links_1']}>
|
||||||
|
Open
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="inline">
|
||||||
|
<input type="radio" name="magnet_links" id="magnet_links_2" value="2" ${config['magnet_links_2']}>
|
||||||
|
Convert
|
||||||
|
</label>
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
|
||||||
|
<small>Note: opening magnet URL's is not suitable for headless/console/terminal servers.</small>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset id="transmission_options">
|
<fieldset id="transmission_options">
|
||||||
@@ -382,7 +399,7 @@
|
|||||||
<input type="radio" name="prefer_torrents" id="prefer_torrents_0" value="0" ${config['prefer_torrents_0']}>NZBs
|
<input type="radio" name="prefer_torrents" id="prefer_torrents_0" value="0" ${config['prefer_torrents_0']}>NZBs
|
||||||
<input type="radio" name="prefer_torrents" id="prefer_torrents_1" value="1" ${config['prefer_torrents_1']}>Torrents
|
<input type="radio" name="prefer_torrents" id="prefer_torrents_1" value="1" ${config['prefer_torrents_1']}>Torrents
|
||||||
<input type="radio" name="prefer_torrents" id="prefer_torrents_2" value="2" ${config['prefer_torrents_2']}>No Preference
|
<input type="radio" name="prefer_torrents" id="prefer_torrents_2" value="2" ${config['prefer_torrents_2']}>No Preference
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -336,6 +336,10 @@ form .row label {
|
|||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
width: 175px;
|
width: 175px;
|
||||||
}
|
}
|
||||||
|
form .row label.inline {
|
||||||
|
margin-right: 5px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
form .row input {
|
form .row input {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ form {
|
|||||||
line-height: normal;
|
line-height: normal;
|
||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
width: 175px;
|
width: 175px;
|
||||||
|
|
||||||
|
&.inline {
|
||||||
|
margin-right: 5px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
input { margin-right: 5px; }
|
input { margin-right: 5px; }
|
||||||
input[type=text], input[type=password] {
|
input[type=text], input[type=password] {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ AUTOWANT_ALL = False
|
|||||||
AUTOWANT_MANUALLY_ADDED = True
|
AUTOWANT_MANUALLY_ADDED = True
|
||||||
KEEP_TORRENT_FILES = False
|
KEEP_TORRENT_FILES = False
|
||||||
PREFER_TORRENTS = None # 0: nzbs, 1: torrents, 2: no preference
|
PREFER_TORRENTS = None # 0: nzbs, 1: torrents, 2: no preference
|
||||||
OPEN_MAGNET_LINKS = False
|
MAGNET_LINKS = None # 0: Ignore, 1: Open, 2: Convert
|
||||||
|
|
||||||
SEARCH_INTERVAL = 360
|
SEARCH_INTERVAL = 360
|
||||||
LIBRARYSCAN = False
|
LIBRARYSCAN = False
|
||||||
@@ -361,7 +361,7 @@ def initialize():
|
|||||||
HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, GIT_USER, GIT_BRANCH, DO_NOT_OVERRIDE_GIT_BRANCH, \
|
HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, GIT_USER, GIT_BRANCH, DO_NOT_OVERRIDE_GIT_BRANCH, \
|
||||||
CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \
|
CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \
|
||||||
LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, FREEZE_DB, MOVE_FILES, \
|
LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, FREEZE_DB, MOVE_FILES, \
|
||||||
RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, FILE_UNDERSCORES, CLEANUP_FILES, KEEP_NFO, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, AUTOWANT_MANUALLY_ADDED, KEEP_TORRENT_FILES, PREFER_TORRENTS, OPEN_MAGNET_LINKS, \
|
RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, FILE_UNDERSCORES, CLEANUP_FILES, KEEP_NFO, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, AUTOWANT_MANUALLY_ADDED, KEEP_TORRENT_FILES, PREFER_TORRENTS, MAGNET_LINKS, \
|
||||||
ADD_ALBUM_ART, ALBUM_ART_FORMAT, EMBED_ALBUM_ART, EMBED_LYRICS, REPLACE_EXISTING_FOLDERS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \
|
ADD_ALBUM_ART, ALBUM_ART_FORMAT, EMBED_ALBUM_ART, EMBED_LYRICS, REPLACE_EXISTING_FOLDERS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \
|
||||||
TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, KAT, KAT_PROXY_URL, KAT_RATIO, PIRATEBAY, PIRATEBAY_PROXY_URL, PIRATEBAY_RATIO, MININOVA, MININOVA_RATIO, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, WAFFLES_RATIO, \
|
TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, KAT, KAT_PROXY_URL, KAT_RATIO, PIRATEBAY, PIRATEBAY_PROXY_URL, PIRATEBAY_RATIO, MININOVA, MININOVA_RATIO, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, WAFFLES_RATIO, \
|
||||||
RUTRACKER, RUTRACKER_USER, RUTRACKER_PASSWORD, RUTRACKER_RATIO, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, WHATCD_RATIO, DOWNLOAD_TORRENT_DIR, \
|
RUTRACKER, RUTRACKER_USER, RUTRACKER_PASSWORD, RUTRACKER_RATIO, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, WHATCD_RATIO, DOWNLOAD_TORRENT_DIR, \
|
||||||
@@ -467,7 +467,7 @@ def initialize():
|
|||||||
AUTOWANT_MANUALLY_ADDED = bool(check_setting_int(CFG, 'General', 'autowant_manually_added', 1))
|
AUTOWANT_MANUALLY_ADDED = bool(check_setting_int(CFG, 'General', 'autowant_manually_added', 1))
|
||||||
KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0))
|
KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0))
|
||||||
PREFER_TORRENTS = check_setting_int(CFG, 'General', 'prefer_torrents', 0)
|
PREFER_TORRENTS = check_setting_int(CFG, 'General', 'prefer_torrents', 0)
|
||||||
OPEN_MAGNET_LINKS = bool(check_setting_int(CFG, 'General', 'open_magnet_links', 0))
|
MAGNET_LINKS = int(check_setting_int(CFG, 'General', 'magnet_links', 0))
|
||||||
|
|
||||||
SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440)
|
SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440)
|
||||||
LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1))
|
LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1))
|
||||||
@@ -913,7 +913,7 @@ def config_write():
|
|||||||
new_config['General']['autowant_manually_added'] = int(AUTOWANT_MANUALLY_ADDED)
|
new_config['General']['autowant_manually_added'] = int(AUTOWANT_MANUALLY_ADDED)
|
||||||
new_config['General']['keep_torrent_files'] = int(KEEP_TORRENT_FILES)
|
new_config['General']['keep_torrent_files'] = int(KEEP_TORRENT_FILES)
|
||||||
new_config['General']['prefer_torrents'] = PREFER_TORRENTS
|
new_config['General']['prefer_torrents'] = PREFER_TORRENTS
|
||||||
new_config['General']['open_magnet_links'] = OPEN_MAGNET_LINKS
|
new_config['General']['magnet_links'] = int(MAGNET_LINKS)
|
||||||
|
|
||||||
new_config['General']['numberofseeders'] = NUMBEROFSEEDERS
|
new_config['General']['numberofseeders'] = NUMBEROFSEEDERS
|
||||||
new_config['General']['torrentblackhole_dir'] = TORRENTBLACKHOLE_DIR
|
new_config['General']['torrentblackhole_dir'] = TORRENTBLACKHOLE_DIR
|
||||||
|
|||||||
+181
-90
@@ -20,18 +20,19 @@ from pygazelle import api as gazelleapi
|
|||||||
from pygazelle import encoding as gazelleencoding
|
from pygazelle import encoding as gazelleencoding
|
||||||
from pygazelle import format as gazelleformat
|
from pygazelle import format as gazelleformat
|
||||||
from pygazelle import media as gazellemedia
|
from pygazelle import media as gazellemedia
|
||||||
from xml.dom import minidom
|
|
||||||
from base64 import b16encode, b32decode
|
from base64 import b16encode, b32decode
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
|
|
||||||
import os, re, time
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
import string
|
import string
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import random
|
||||||
|
import headphones
|
||||||
import subprocess
|
import subprocess
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
import headphones
|
|
||||||
from headphones.common import USER_AGENT
|
from headphones.common import USER_AGENT
|
||||||
from headphones import logger, db, helpers, classes, sab, nzbget, request
|
from headphones import logger, db, helpers, classes, sab, nzbget, request
|
||||||
from headphones import utorrent, transmission, notifiers
|
from headphones import utorrent, transmission, notifiers
|
||||||
@@ -39,19 +40,136 @@ from headphones import utorrent, transmission, notifiers
|
|||||||
from bencode import bencode, bdecode
|
from bencode import bencode, bdecode
|
||||||
|
|
||||||
import headphones.searcher_rutracker as rutrackersearch
|
import headphones.searcher_rutracker as rutrackersearch
|
||||||
rutracker = rutrackersearch.Rutracker()
|
|
||||||
|
# Magnet to torrent services, for Black hole. Stolen from CouchPotato.
|
||||||
|
TORRENT_TO_MAGNET_SERVICES = [
|
||||||
|
'https://zoink.it/torrent/%s.torrent',
|
||||||
|
'http://torrage.com/torrent/%s.torrent',
|
||||||
|
'https://torcache.net/torrent/%s.torrent',
|
||||||
|
]
|
||||||
|
|
||||||
# Persistent What.cd API object
|
# Persistent What.cd API object
|
||||||
gazelle = None
|
gazelle = None
|
||||||
|
|
||||||
def url_fix(s, charset='utf-8'):
|
# RUtracker search object
|
||||||
|
rutracker = rutrackersearch.Rutracker()
|
||||||
|
|
||||||
|
def fix_url(s, charset="utf-8"):
|
||||||
|
"""
|
||||||
|
Fix the URL so it is proper formatted and encoded.
|
||||||
|
"""
|
||||||
|
|
||||||
if isinstance(s, unicode):
|
if isinstance(s, unicode):
|
||||||
s = s.encode(charset, 'ignore')
|
s = s.encode(charset, 'ignore')
|
||||||
|
|
||||||
scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
|
scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
|
||||||
path = urllib.quote(path, '/%')
|
path = urllib.quote(path, '/%')
|
||||||
qs = urllib.quote_plus(qs, ':&=')
|
qs = urllib.quote_plus(qs, ':&=')
|
||||||
|
|
||||||
return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
|
return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
|
||||||
|
|
||||||
|
def torrent_to_file(target_file, data):
|
||||||
|
"""
|
||||||
|
Write torrent data to file, and change permissions accordingly. Will return
|
||||||
|
None in case of a write error. If changing permissions fails, it will
|
||||||
|
continue anyway.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Write data to file
|
||||||
|
try:
|
||||||
|
with open(target_file, "wb") as fp:
|
||||||
|
fp.write(data)
|
||||||
|
except IOError as e:
|
||||||
|
logger.error("Could not write torrent file '%s': %s. Skipping.",
|
||||||
|
target_file, e.message)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Try to change permissions
|
||||||
|
try:
|
||||||
|
os.chmod(target_file, int(headphones.FILE_PERMISSIONS, 8))
|
||||||
|
except OSError as e:
|
||||||
|
logger.warn("Could not change permissions for file '%s': %s. " \
|
||||||
|
"Continuing.", target_file, e.message)
|
||||||
|
|
||||||
|
# Done
|
||||||
|
return True
|
||||||
|
|
||||||
|
def read_torrent_name(torrent_file, default_name=None):
|
||||||
|
"""
|
||||||
|
Read the torrent file and return the torrent name. If the torrent name
|
||||||
|
cannot be determined, it will return the `default_name`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Open file
|
||||||
|
try:
|
||||||
|
with open(torrent_file, "rb") as fp:
|
||||||
|
torrent_info = bdecode(fp.read())
|
||||||
|
except IOError as e:
|
||||||
|
logger.error("Unable to open torrent file: %s", torrent_file)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Read dictionary
|
||||||
|
if torrent_info:
|
||||||
|
try:
|
||||||
|
return torrent_info["info"]["name"]
|
||||||
|
except KeyError:
|
||||||
|
if default_name:
|
||||||
|
logger.warning("Couldn't get name from torrent file: %s. " \
|
||||||
|
"Defaulting to '%s'", e, default_name)
|
||||||
|
else:
|
||||||
|
logger.warning("Couldn't get name from torrent file: %s. No " \
|
||||||
|
"default given", e)
|
||||||
|
|
||||||
|
# Return default
|
||||||
|
return default_name
|
||||||
|
|
||||||
|
def calculate_torrent_hash(link, data=None):
|
||||||
|
"""
|
||||||
|
Calculate the torrent hash from a magnet link or data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if link.startswith("magnet:"):
|
||||||
|
torrent_hash = re.findall("urn:btih:([\w]{32,40})", link)[0]
|
||||||
|
if len(torrent_hash) == 32:
|
||||||
|
torrent_hash = b16encode(b32decode(torrent_hash)).lower()
|
||||||
|
elif data:
|
||||||
|
info = bdecode(data)["info"]
|
||||||
|
torrent_hash = sha1(bencode(info)).hexdigest()
|
||||||
|
else:
|
||||||
|
raise ValueError("Cannot calculate torrent hash without magnet link " \
|
||||||
|
"or data")
|
||||||
|
|
||||||
|
return torrent_hash
|
||||||
|
|
||||||
|
def get_seed_ratio(provider):
|
||||||
|
"""
|
||||||
|
Return the seed ratio for the specified provider, if applicable. Defaults to
|
||||||
|
None in case of an error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if provider == 'rutracker.org':
|
||||||
|
seed_ratio = headphones.RUTRACKER_RATIO
|
||||||
|
elif provider == 'Kick Ass Torrents':
|
||||||
|
seed_ratio = headphones.KAT_RATIO
|
||||||
|
elif provider == 'What.cd':
|
||||||
|
seed_ratio = headphones.WHATCD_RATIO
|
||||||
|
elif provider == 'The Pirate Bay':
|
||||||
|
seed_ratio = headphones.PIRATEBAY_RATIO
|
||||||
|
elif provider == 'Waffles.fm':
|
||||||
|
seed_ratio = headphones.WAFFLES_RATIO
|
||||||
|
elif provider == 'Mininova':
|
||||||
|
seed_ratio = headphones.MININOVA_RATIO
|
||||||
|
else:
|
||||||
|
seed_ratio = None
|
||||||
|
|
||||||
|
if seed_ratio is not None:
|
||||||
|
try:
|
||||||
|
seed_ratio = float(seed_ratio)
|
||||||
|
except ValueError:
|
||||||
|
logger.warn("Could not get seed ratio for %s" % provider)
|
||||||
|
|
||||||
|
return seed_ratio
|
||||||
|
|
||||||
def searchforalbum(albumid=None, new=False, losslessOnly=False, choose_specific_download=False):
|
def searchforalbum(albumid=None, new=False, losslessOnly=False, choose_specific_download=False):
|
||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
|
|
||||||
@@ -80,7 +198,6 @@ def searchforalbum(albumid=None, new=False, losslessOnly=False, choose_specific_
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
album = myDB.action('SELECT * from albums WHERE AlbumID=?', [albumid]).fetchone()
|
album = myDB.action('SELECT * from albums WHERE AlbumID=?', [albumid]).fetchone()
|
||||||
logger.info('Searching for "%s - %s" since it was marked as wanted' % (album['ArtistName'], album['AlbumTitle']))
|
logger.info('Searching for "%s - %s" since it was marked as wanted' % (album['ArtistName'], album['AlbumTitle']))
|
||||||
do_sorted_search(album, new, losslessOnly)
|
do_sorted_search(album, new, losslessOnly)
|
||||||
@@ -233,7 +350,7 @@ def sort_search_results(resultlist, album, new, albumlength):
|
|||||||
priority = 1
|
priority = 1
|
||||||
# add a search provider priority (weighted based on position)
|
# add a search provider priority (weighted based on position)
|
||||||
i = next((i for i, word in enumerate(preferred_words) if word in result[3].lower()), None)
|
i = next((i for i, word in enumerate(preferred_words) if word in result[3].lower()), None)
|
||||||
if i != None:
|
if i is not None:
|
||||||
priority += round((len(preferred_words) - i) / float(len(preferred_words)),2)
|
priority += round((len(preferred_words) - i) / float(len(preferred_words)),2)
|
||||||
|
|
||||||
temp_list.append((result[0],result[1],result[2],result[3],result[4],priority))
|
temp_list.append((result[0],result[1],result[2],result[3],result[4],priority))
|
||||||
@@ -622,8 +739,8 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
torrent_name = helpers.replace_illegal_chars(folder_name) + '.torrent'
|
torrent_name = helpers.replace_illegal_chars(folder_name) + '.torrent'
|
||||||
download_path = os.path.join(headphones.TORRENTBLACKHOLE_DIR, torrent_name)
|
download_path = os.path.join(headphones.TORRENTBLACKHOLE_DIR, torrent_name)
|
||||||
|
|
||||||
if bestqual[2].startswith("magnet:"):
|
if bestqual[2].lower().startswith("magnet:"):
|
||||||
if headphones.OPEN_MAGNET_LINKS:
|
if headphones.MAGNET_LINKS == 1:
|
||||||
try:
|
try:
|
||||||
if headphones.SYS_PLATFORM == 'win32':
|
if headphones.SYS_PLATFORM == 'win32':
|
||||||
os.startfile(bestqual[2])
|
os.startfile(bestqual[2])
|
||||||
@@ -637,37 +754,51 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error opening magnet link: %s" % str(e))
|
logger.error("Error opening magnet link: %s" % str(e))
|
||||||
return
|
return
|
||||||
else:
|
elif headphones.MAGNET_LINKS == 2:
|
||||||
logger.error("Cannot save magnet files to blackhole. Please switch your torrent downloader to Transmission or uTorrent or allow Headphones to try to open magnet links")
|
# Procedure adapted from CouchPotato
|
||||||
return
|
torrent_hash = calculate_torrent_hash(bestqual[2])
|
||||||
|
|
||||||
else:
|
# Randomize list of services
|
||||||
try:
|
services = TORRENT_TO_MAGNET_SERVICES[:]
|
||||||
|
random.shuffle(services)
|
||||||
|
|
||||||
if bestqual[3] == 'rutracker.org':
|
for service in services:
|
||||||
download_path = rutracker.get_torrent(bestqual[2], headphones.TORRENTBLACKHOLE_DIR)
|
data = request.request_content(service % torrent_hash)
|
||||||
if not download_path:
|
|
||||||
return
|
if data and "torcache" in data:
|
||||||
|
if not torrent_to_file(download_path, data):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Extract folder name from torrent
|
||||||
|
folder_name = read_torrent_name(download_path,
|
||||||
|
bestqual[0])
|
||||||
|
|
||||||
|
# Break for loop
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
#Write the torrent file to a path derived from the TORRENTBLACKHOLE_DIR and file name.
|
# No service succeeded
|
||||||
with open(download_path, 'wb') as fp:
|
logger.warning("Unable to convert magnet with hash " \
|
||||||
fp.write(data)
|
"'%s' into a torrent file.", torrent_hash)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logger.error("Cannot save magnet link in blackhole. " \
|
||||||
|
"Please switch your torrent downloader to " \
|
||||||
|
"Transmission or uTorrent, or allow Headphones " \
|
||||||
|
"to open or convert magnet links")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if bestqual[3] == "rutracker.org":
|
||||||
|
download_path = rutracker.get_torrent(bestqual[2],
|
||||||
|
headphones.TORRENTBLACKHOLE_DIR)
|
||||||
|
|
||||||
try:
|
if not download_path:
|
||||||
os.chmod(download_path, int(headphones.FILE_PERMISSIONS, 8))
|
return
|
||||||
except:
|
else:
|
||||||
logger.error("Could not change permissions for file: %s", download_path)
|
if not torrent_to_file(download_path, data):
|
||||||
|
return
|
||||||
|
|
||||||
# Open the fresh torrent file again so we can extract the
|
# Extract folder name from torrent
|
||||||
# proper torrent name Used later in post-processing.
|
folder_name = read_torrent_name(download_path, bestqual[0])
|
||||||
with open(download_path, 'rb') as fp:
|
|
||||||
torrent_info = bdecode(fp.read())
|
|
||||||
|
|
||||||
folder_name = torrent_info['info'].get('name', '')
|
|
||||||
logger.info('Torrent folder name: %s' % folder_name)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Couldn\'t get name from Torrent file: %s. Defaulting to torrent title' % e)
|
|
||||||
folder_name = bestqual[0]
|
|
||||||
|
|
||||||
elif headphones.TORRENT_DOWNLOADER == 1:
|
elif headphones.TORRENT_DOWNLOADER == 1:
|
||||||
logger.info("Sending torrent to Transmission")
|
logger.info("Sending torrent to Transmission")
|
||||||
@@ -699,8 +830,8 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
logger.exception("Unhandled exception")
|
logger.exception("Unhandled exception")
|
||||||
|
|
||||||
# Set Seed Ratio
|
# Set Seed Ratio
|
||||||
seed_ratio = getSeedRatio(bestqual[3])
|
seed_ratio = get_seed_ratio(bestqual[3])
|
||||||
if seed_ratio != None:
|
if seed_ratio is not None:
|
||||||
transmission.setSeedRatio(torrentid, seed_ratio)
|
transmission.setSeedRatio(torrentid, seed_ratio)
|
||||||
|
|
||||||
else:# if headphones.TORRENT_DOWNLOADER == 2:
|
else:# if headphones.TORRENT_DOWNLOADER == 2:
|
||||||
@@ -714,7 +845,7 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
utorrent.labelTorrent(torrentid)
|
utorrent.labelTorrent(torrentid)
|
||||||
else:
|
else:
|
||||||
file_or_url = bestqual[2]
|
file_or_url = bestqual[2]
|
||||||
torrentid = CalculateTorrentHash(file_or_url, data)
|
torrentid = calculate_torrent_hash(file_or_url, data)
|
||||||
folder_name = utorrent.addTorrent(file_or_url, torrentid)
|
folder_name = utorrent.addTorrent(file_or_url, torrentid)
|
||||||
|
|
||||||
if folder_name:
|
if folder_name:
|
||||||
@@ -731,8 +862,8 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
logger.exception("Unhandled exception")
|
logger.exception("Unhandled exception")
|
||||||
|
|
||||||
# Set Seed Ratio
|
# Set Seed Ratio
|
||||||
seed_ratio = getSeedRatio(bestqual[3])
|
seed_ratio = get_seed_ratio(bestqual[3])
|
||||||
if seed_ratio != None:
|
if seed_ratio is not None:
|
||||||
utorrent.setSeedRatio(torrentid, seed_ratio)
|
utorrent.setSeedRatio(torrentid, seed_ratio)
|
||||||
|
|
||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
@@ -740,7 +871,7 @@ def send_to_downloader(data, bestqual, album):
|
|||||||
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Snatched", folder_name, kind])
|
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Snatched", folder_name, kind])
|
||||||
|
|
||||||
# Store the torrent id so we can check later if it's finished seeding and can be removed
|
# Store the torrent id so we can check later if it's finished seeding and can be removed
|
||||||
if seed_ratio != None and seed_ratio != 0 and torrentid:
|
if seed_ratio is not None and seed_ratio != 0 and torrentid:
|
||||||
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Seed_Snatched", torrentid, kind])
|
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Seed_Snatched", torrentid, kind])
|
||||||
|
|
||||||
# notify
|
# notify
|
||||||
@@ -935,9 +1066,9 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
|
|
||||||
# Use proxy if specified
|
# Use proxy if specified
|
||||||
if headphones.KAT_PROXY_URL:
|
if headphones.KAT_PROXY_URL:
|
||||||
providerurl = url_fix(set_proxy(headphones.KAT_PROXY_URL))
|
providerurl = fix_url(set_proxy(headphones.KAT_PROXY_URL))
|
||||||
else:
|
else:
|
||||||
providerurl = url_fix("https://kickass.to")
|
providerurl = fix_url("https://kickass.to")
|
||||||
|
|
||||||
# Build URL
|
# Build URL
|
||||||
providerurl = providerurl + "/usearch/" + ka_term
|
providerurl = providerurl + "/usearch/" + ka_term
|
||||||
@@ -995,7 +1126,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
|
|
||||||
if headphones.WAFFLES:
|
if headphones.WAFFLES:
|
||||||
provider = "Waffles.fm"
|
provider = "Waffles.fm"
|
||||||
providerurl = url_fix("https://www.waffles.fm/browse.php")
|
providerurl = fix_url("https://www.waffles.fm/browse.php")
|
||||||
|
|
||||||
bitrate = None
|
bitrate = None
|
||||||
if headphones.PREFERRED_QUALITY == 3 or losslessOnly:
|
if headphones.PREFERRED_QUALITY == 3 or losslessOnly:
|
||||||
@@ -1186,9 +1317,9 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
|
|
||||||
# Use proxy if specified
|
# Use proxy if specified
|
||||||
if headphones.PIRATEBAY_PROXY_URL:
|
if headphones.PIRATEBAY_PROXY_URL:
|
||||||
providerurl = url_fix(set_proxy(headphones.PIRATEBAY_PROXY_URL))
|
providerurl = fix_url(set_proxy(headphones.PIRATEBAY_PROXY_URL))
|
||||||
else:
|
else:
|
||||||
providerurl = url_fix("https://thepiratebay.se")
|
providerurl = fix_url("https://thepiratebay.se")
|
||||||
|
|
||||||
# Build URL
|
# Build URL
|
||||||
providerurl = providerurl + "/search/" + tpb_term + "/0/7/" # 7 is sort by seeders
|
providerurl = providerurl + "/search/" + tpb_term + "/0/7/" # 7 is sort by seeders
|
||||||
@@ -1228,7 +1359,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
try:
|
try:
|
||||||
url = item.find("a", {"title":"Download this torrent"})['href']
|
url = item.find("a", {"title":"Download this torrent"})['href']
|
||||||
except TypeError:
|
except TypeError:
|
||||||
if headphones.OPEN_MAGNET_LINKS:
|
if headphones.MAGNET_LINKS != 0:
|
||||||
url = item.findAll("a")[3]['href']
|
url = item.findAll("a")[3]['href']
|
||||||
else:
|
else:
|
||||||
logger.info('"%s" only has a magnet link, skipping' % title)
|
logger.info('"%s" only has a magnet link, skipping' % title)
|
||||||
@@ -1252,7 +1383,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
|
|
||||||
if headphones.MININOVA:
|
if headphones.MININOVA:
|
||||||
provider = "Mininova"
|
provider = "Mininova"
|
||||||
providerurl = url_fix("http://www.mininova.org/rss/" + term + "/5")
|
providerurl = fix_url("http://www.mininova.org/rss/" + term + "/5")
|
||||||
|
|
||||||
if headphones.PREFERRED_QUALITY == 3 or losslessOnly:
|
if headphones.PREFERRED_QUALITY == 3 or losslessOnly:
|
||||||
categories = "7" #music
|
categories = "7" #music
|
||||||
@@ -1320,7 +1451,6 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None):
|
|||||||
def preprocess(resultlist):
|
def preprocess(resultlist):
|
||||||
|
|
||||||
for result in resultlist:
|
for result in resultlist:
|
||||||
|
|
||||||
if result[4] == 'torrent':
|
if result[4] == 'torrent':
|
||||||
#Get out of here if we're using Transmission
|
#Get out of here if we're using Transmission
|
||||||
if headphones.TORRENT_DOWNLOADER == 1: ## if not a magnet link still need the .torrent to generate hash... uTorrent support labeling
|
if headphones.TORRENT_DOWNLOADER == 1: ## if not a magnet link still need the .torrent to generate hash... uTorrent support labeling
|
||||||
@@ -1329,7 +1459,7 @@ def preprocess(resultlist):
|
|||||||
if result[3] == 'rutracker.org':
|
if result[3] == 'rutracker.org':
|
||||||
return True, result
|
return True, result
|
||||||
# Get out of here if it's a magnet link
|
# Get out of here if it's a magnet link
|
||||||
if result[2].startswith("magnet"):
|
if result[2].lower().startswith("magnet:"):
|
||||||
return True, result
|
return True, result
|
||||||
|
|
||||||
# Download the torrent file
|
# Download the torrent file
|
||||||
@@ -1344,48 +1474,9 @@ def preprocess(resultlist):
|
|||||||
return request.request_content(url=result[2], headers=headers), result
|
return request.request_content(url=result[2], headers=headers), result
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
headers = {'User-Agent': USER_AGENT}
|
headers = {'User-Agent': USER_AGENT}
|
||||||
|
|
||||||
if result[3] == 'headphones':
|
if result[3] == 'headphones':
|
||||||
return request.request_content(url=result[2], headers=headers, auth=(headphones.HPUSER, headphones.HPPASS)), result
|
return request.request_content(url=result[2], headers=headers, auth=(headphones.HPUSER, headphones.HPPASS)), result
|
||||||
else:
|
else:
|
||||||
return request.request_content(url=result[2], headers=headers), result
|
return request.request_content(url=result[2], headers=headers), result
|
||||||
|
|
||||||
def CalculateTorrentHash(link, data):
|
|
||||||
|
|
||||||
if link.startswith('magnet'):
|
|
||||||
tor_hash = re.findall('urn:btih:([\w]{32,40})', link)[0]
|
|
||||||
if len(tor_hash) == 32:
|
|
||||||
tor_hash = b16encode(b32decode(tor_hash)).lower()
|
|
||||||
else:
|
|
||||||
info = bdecode(data)["info"]
|
|
||||||
tor_hash = sha1(bencode(info)).hexdigest()
|
|
||||||
|
|
||||||
logger.debug('Torrent Hash: ' + str(tor_hash))
|
|
||||||
|
|
||||||
return tor_hash
|
|
||||||
|
|
||||||
def getSeedRatio(provider):
|
|
||||||
seed_ratio = ''
|
|
||||||
if provider == 'rutracker.org':
|
|
||||||
seed_ratio = headphones.RUTRACKER_RATIO
|
|
||||||
elif provider == 'Kick Ass Torrents':
|
|
||||||
seed_ratio = headphones.KAT_RATIO
|
|
||||||
elif provider == 'What.cd':
|
|
||||||
seed_ratio = headphones.WHATCD_RATIO
|
|
||||||
elif provider == 'The Pirate Bay':
|
|
||||||
seed_ratio = headphones.PIRATEBAY_RATIO
|
|
||||||
elif provider == 'Waffles.fm':
|
|
||||||
seed_ratio = headphones.WAFFLES_RATIO
|
|
||||||
elif provider == 'Mininova':
|
|
||||||
seed_ratio = headphones.MININOVA_RATIO
|
|
||||||
if seed_ratio != '':
|
|
||||||
try:
|
|
||||||
seed_ratio_float = float(seed_ratio)
|
|
||||||
except:
|
|
||||||
seed_ratio_float = None
|
|
||||||
logger.warn('Could not get Seed Ratio for %s' % provider)
|
|
||||||
return seed_ratio_float
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
@@ -1070,7 +1070,9 @@ class WebInterface(object):
|
|||||||
"prefer_torrents_0" : radio(headphones.PREFER_TORRENTS, 0),
|
"prefer_torrents_0" : radio(headphones.PREFER_TORRENTS, 0),
|
||||||
"prefer_torrents_1" : radio(headphones.PREFER_TORRENTS, 1),
|
"prefer_torrents_1" : radio(headphones.PREFER_TORRENTS, 1),
|
||||||
"prefer_torrents_2" : radio(headphones.PREFER_TORRENTS, 2),
|
"prefer_torrents_2" : radio(headphones.PREFER_TORRENTS, 2),
|
||||||
"open_magnet_links" : checked(headphones.OPEN_MAGNET_LINKS),
|
"magnet_links_0" : radio(headphones.MAGNET_LINKS, 0),
|
||||||
|
"magnet_links_1" : radio(headphones.MAGNET_LINKS, 1),
|
||||||
|
"magnet_links_2" : radio(headphones.MAGNET_LINKS, 2),
|
||||||
"log_dir" : headphones.LOG_DIR,
|
"log_dir" : headphones.LOG_DIR,
|
||||||
"cache_dir" : headphones.CACHE_DIR,
|
"cache_dir" : headphones.CACHE_DIR,
|
||||||
"interface_list" : interface_list,
|
"interface_list" : interface_list,
|
||||||
@@ -1188,7 +1190,7 @@ class WebInterface(object):
|
|||||||
numberofseeders=None, use_piratebay=0, piratebay_proxy_url=None, piratebay_ratio=None, use_kat=0, kat_proxy_url=None, kat_ratio=None, use_mininova=0, mininova_ratio=None, waffles=0, waffles_uid=None, waffles_passkey=None, waffles_ratio=None, whatcd=0, whatcd_username=None, whatcd_password=None, whatcd_ratio=None,
|
numberofseeders=None, use_piratebay=0, piratebay_proxy_url=None, piratebay_ratio=None, use_kat=0, kat_proxy_url=None, kat_ratio=None, use_mininova=0, mininova_ratio=None, waffles=0, waffles_uid=None, waffles_passkey=None, waffles_ratio=None, whatcd=0, whatcd_username=None, whatcd_password=None, whatcd_ratio=None,
|
||||||
rutracker=0, rutracker_user=None, rutracker_password=None, rutracker_ratio=None, rename_files=0, correct_metadata=0, cleanup_files=0, keep_nfo=0, add_album_art=0, album_art_format=None, embed_album_art=0, embed_lyrics=0, replace_existing_folders=False,
|
rutracker=0, rutracker_user=None, rutracker_password=None, rutracker_ratio=None, rename_files=0, correct_metadata=0, cleanup_files=0, keep_nfo=0, add_album_art=0, album_art_format=None, embed_album_art=0, embed_lyrics=0, replace_existing_folders=False,
|
||||||
destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, file_underscores=0, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0, remix=0, spokenword=0, audiobook=0, other=0, djmix=0, mixtape_street=0, broadcast=0, interview=0, demo=0,
|
destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, file_underscores=0, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0, remix=0, spokenword=0, audiobook=0, other=0, djmix=0, mixtape_street=0, broadcast=0, interview=0, demo=0,
|
||||||
autowant_upcoming=False, autowant_all=False, autowant_manually_added=False, keep_torrent_files=False, prefer_torrents=0, open_magnet_links=0, interface=None, log_dir=None, cache_dir=None, music_encoder=0, encoder=None, xldprofile=None,
|
autowant_upcoming=False, autowant_all=False, autowant_manually_added=False, keep_torrent_files=False, prefer_torrents=0, magnet_links=0, interface=None, log_dir=None, cache_dir=None, music_encoder=0, encoder=None, xldprofile=None,
|
||||||
bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0, subsonic_enabled=False, subsonic_host=None, subsonic_username=None, subsonic_password=None,
|
bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0, subsonic_enabled=False, subsonic_host=None, subsonic_username=None, subsonic_password=None,
|
||||||
delete_lossless_files=0, growl_enabled=0, growl_onsnatch=0, growl_host=None, growl_password=None, prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None,
|
delete_lossless_files=0, growl_enabled=0, growl_onsnatch=0, growl_host=None, growl_password=None, prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None,
|
||||||
xbmc_update=0, xbmc_notify=0, nma_enabled=False, nma_apikey=None, nma_priority=0, nma_onsnatch=0, pushalot_enabled=False, pushalot_apikey=None, pushalot_onsnatch=0, synoindex_enabled=False, lms_enabled=0, lms_host=None,
|
xbmc_update=0, xbmc_notify=0, nma_enabled=False, nma_apikey=None, nma_priority=0, nma_onsnatch=0, pushalot_enabled=False, pushalot_apikey=None, pushalot_onsnatch=0, synoindex_enabled=False, lms_enabled=0, lms_host=None,
|
||||||
@@ -1302,7 +1304,7 @@ class WebInterface(object):
|
|||||||
headphones.AUTOWANT_MANUALLY_ADDED = autowant_manually_added
|
headphones.AUTOWANT_MANUALLY_ADDED = autowant_manually_added
|
||||||
headphones.KEEP_TORRENT_FILES = keep_torrent_files
|
headphones.KEEP_TORRENT_FILES = keep_torrent_files
|
||||||
headphones.PREFER_TORRENTS = int(prefer_torrents)
|
headphones.PREFER_TORRENTS = int(prefer_torrents)
|
||||||
headphones.OPEN_MAGNET_LINKS = open_magnet_links
|
headphones.MAGNET_LINKS = int(magnet_links)
|
||||||
headphones.INTERFACE = interface
|
headphones.INTERFACE = interface
|
||||||
headphones.LOG_DIR = log_dir
|
headphones.LOG_DIR = log_dir
|
||||||
headphones.CACHE_DIR = cache_dir
|
headphones.CACHE_DIR = cache_dir
|
||||||
|
|||||||
Reference in New Issue
Block a user