From cd57668b92bf33fe3009c3c4760833ca8c05aafa Mon Sep 17 00:00:00 2001 From: Ade Date: Tue, 15 Aug 2017 17:25:37 +1200 Subject: [PATCH 01/14] allow .aif --- headphones/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/headphones/__init__.py b/headphones/__init__.py index 2bd3bf9c..c6acc763 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -87,7 +87,7 @@ LATEST_VERSION = None COMMITS_BEHIND = None LOSSY_MEDIA_FORMATS = ["mp3", "aac", "ogg", "ape", "m4a", "asf", "wma", "opus"] -LOSSLESS_MEDIA_FORMATS = ["flac", "aiff"] +LOSSLESS_MEDIA_FORMATS = ["flac", "aiff", "aif"] MEDIA_FORMATS = LOSSY_MEDIA_FORMATS + LOSSLESS_MEDIA_FORMATS MIRRORLIST = ["musicbrainz.org", "headphones", "custom"] From bdf55f8662c99cfd32f94a63271368b03500fb7d Mon Sep 17 00:00:00 2001 From: Ade Date: Sat, 19 Aug 2017 08:42:04 +1200 Subject: [PATCH 02/14] replace torcache --- headphones/searcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 0dc81b54..109901e0 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -43,7 +43,8 @@ from bencode import bencode, bdecode TORRENT_TO_MAGNET_SERVICES = [ # 'https://zoink.it/torrent/%s.torrent', # 'http://torrage.com/torrent/%s.torrent', - 'https://torcache.net/torrent/%s.torrent', + # 'https://torcache.net/torrent/%s.torrent', + 'http://itorrents.org/torrent/%s.torrent', ] # Persistent Apollo.rip API object @@ -878,12 +879,11 @@ def send_to_downloader(data, bestqual, album): services = TORRENT_TO_MAGNET_SERVICES[:] random.shuffle(services) headers = {'User-Agent': USER_AGENT} - headers['Referer'] = 'https://torcache.net/' for service in services: data = request.request_content(service % torrent_hash, headers=headers) - if data and "torcache" in data: + if data: if not torrent_to_file(download_path, data): return # Extract folder name from torrent From 4d575787cd3ae8cf527bbf41e3de7572afd575b6 Mon Sep 17 00:00:00 2001 From: Ade Date: Thu, 24 Aug 2017 20:48:15 +1200 Subject: [PATCH 03/14] last.fm import fix Fixes #2753 --- headphones/lastfm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/headphones/lastfm.py b/headphones/lastfm.py index 8f906d5f..db3e1aec 100644 --- a/headphones/lastfm.py +++ b/headphones/lastfm.py @@ -149,7 +149,10 @@ def getTagTopArtists(tag, limit=50): logger.debug("Fetched %d artists from Last.FM", len(artists)) for artist in artists: - artist_mbid = artist["mbid"] + try: + artist_mbid = artist["mbid"] + except KeyError: + continue if not any(artist_mbid in x for x in results): artistlist.append(artist_mbid) From 9c2bfcf7d87e8873221daa78ae586a5ab6423b8d Mon Sep 17 00:00:00 2001 From: Ade Date: Mon, 28 Aug 2017 20:54:19 +1200 Subject: [PATCH 04/14] Scan Artist exception handling --- headphones/webserve.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/headphones/webserve.py b/headphones/webserve.py index 6d95712a..f1fbbfbe 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -353,9 +353,13 @@ class WebInterface(object): if not os.path.isdir(artistfolder.encode(headphones.SYS_ENCODING)): logger.debug("Cannot find directory: " + artistfolder) continue - threading.Thread(target=librarysync.libraryScan, - kwargs={"dir": artistfolder, "artistScan": True, "ArtistID": ArtistID, - "ArtistName": artist_name}).start() + try: + threading.Thread(target=librarysync.libraryScan, + kwargs={"dir": artistfolder, "artistScan": True, "ArtistID": ArtistID, + "ArtistName": artist_name}).start() + except Exception as e: + logger.error('Unable to complete the scan: %s' % e) + raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID) @cherrypy.expose From e7062a671054041c7c84f8bb3a38a42294a3f6b5 Mon Sep 17 00:00:00 2001 From: Ade Date: Sat, 2 Sep 2017 19:14:37 +1200 Subject: [PATCH 05/14] Jackett/Torznab v2 api Fixes #2999 --- data/interfaces/default/config.html | 6 +++--- headphones/searcher.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 3859d4a7..28888cae 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -720,8 +720,8 @@
- - e.g. http://localhost:9117/torznab/iptorrents + + e.g. http://localhost:9117/api/v2.0/indexers/demonoid/results/torznab/
@@ -744,7 +744,7 @@
- +
diff --git a/headphones/searcher.py b/headphones/searcher.py index 109901e0..96a45c76 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1318,7 +1318,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, } data = request.request_feed( - url=torznab_host[0] + '/api?', + url=torznab_host[0], params=params, headers=headers ) From 9197f27a505c3f128aa8de0cee77778cc620eec5 Mon Sep 17 00:00:00 2001 From: Ade Date: Thu, 7 Sep 2017 22:26:30 +1200 Subject: [PATCH 06/14] Jackett provider formatting --- headphones/searcher.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 96a45c76..692b3378 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1305,8 +1305,12 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, provider = torznab_host[0] + # Format Jackett provider + if "api/v2.0/indexers" in torznab_host[0]: + provider = "Jackett_" + provider.split("/indexers/",1)[1].split('/',1)[0] + # Request results - logger.info('Parsing results from %s using search term: %s' % (torznab_host[0], term)) + logger.info('Parsing results from %s using search term: %s' % (provider, term)) headers = {'User-Agent': USER_AGENT} params = { @@ -1325,7 +1329,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, # Process feed if data: if not len(data.entries): - logger.info(u"No results found from %s for %s", torznab_host[0], term) + logger.info(u"No results found from %s for %s", provider, term) else: for item in data.entries: try: From c8057676db72dad891ea7c44aed1ea62d621cbc8 Mon Sep 17 00:00:00 2001 From: Ade Date: Thu, 7 Sep 2017 22:48:54 +1200 Subject: [PATCH 07/14] pep --- headphones/searcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 692b3378..2fc5e78d 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1307,7 +1307,7 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, # Format Jackett provider if "api/v2.0/indexers" in torznab_host[0]: - provider = "Jackett_" + provider.split("/indexers/",1)[1].split('/',1)[0] + provider = "Jackett_" + provider.split("/indexers/", 1)[1].split('/', 1)[0] # Request results logger.info('Parsing results from %s using search term: %s' % (provider, term)) From 867f75a681f2fe4b0fa1787e84b9cff184c768e1 Mon Sep 17 00:00:00 2001 From: Noam Date: Sun, 10 Sep 2017 02:15:36 +0300 Subject: [PATCH 08/14] Check _if_ WebUI daemons exist before checking _how many_ exist, fix #3010 --- headphones/deluge.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/headphones/deluge.py b/headphones/deluge.py index 78647b0c..fbb0b8e2 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -379,7 +379,8 @@ def _get_auth(): return None delugeweb_hosts = json.loads(response.text)['result'] - if len(delugeweb_hosts) == 0: + # Check if delugeweb_hosts is None before checking its length + if not delugeweb_hosts or len(delugeweb_hosts) == 0: logger.error('Deluge: WebUI does not contain daemons') return None From 0b6f263985b3ea5f46aa3a6cf50eb6f86536849e Mon Sep 17 00:00:00 2001 From: Noam Date: Mon, 11 Sep 2017 19:38:01 +0300 Subject: [PATCH 09/14] Added UTF-8 header for encoding issues --- headphones/deluge.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/headphones/deluge.py b/headphones/deluge.py index fbb0b8e2..e17a6995 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + # This file is part of Headphones. # # Headphones is free software: you can redistribute it and/or modify From 4c3b60be68fa4b1732f7553bdf959cbe94cdc8fc Mon Sep 17 00:00:00 2001 From: Noam Date: Sun, 17 Sep 2017 01:40:04 +0300 Subject: [PATCH 10/14] UnicodeDecodeError printing torrent name containing unicode --- headphones/deluge.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/headphones/deluge.py b/headphones/deluge.py index e17a6995..99bd1382 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -170,7 +170,10 @@ def addTorrent(link, data=None, name=None): # 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, str(torrentfile)[:40])) + try: + logger.debug('Deluge: Sending Deluge torrent with name %s and content [%s...]' % (name, str(torrentfile)[:40])) + except UnicodeDecodeError: + logger.debug('Deluge: Sending Deluge torrent with name %s and content [%s...]' % (name.decode('utf-8'), str(torrentfile)[:40])) result = {'type': 'torrent', 'name': name, 'content': torrentfile} From b7af246340fa5d5fea30d40d472705ae7b5ae9c2 Mon Sep 17 00:00:00 2001 From: Noam Date: Sun, 17 Sep 2017 02:10:30 +0300 Subject: [PATCH 11/14] Try encoding torrent name utf-8 in params --- headphones/deluge.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/headphones/deluge.py b/headphones/deluge.py index 99bd1382..07699b0b 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -471,7 +471,8 @@ def _add_torrent_file(result): 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')), {}], + "params": [result['name'].encode('utf8') + '.torrent', + b64encode(result['content'].encode('utf8')), {}], "id": 2}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) @@ -484,7 +485,8 @@ def _add_torrent_file(result): # this time let's try leaving the encoding as is logger.debug('Deluge: There was a decoding issue, let\'s try again') post_data = json.dumps({"method": "core.add_torrent_file", - "params": [result['name'] + '.torrent', b64encode(result['content']), {}], + "params": [result['name'] + '.torrent', + b64encode(result['content']), {}], "id": 22}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) From 68c551c8285942348341f69c640eafd029a63a82 Mon Sep 17 00:00:00 2001 From: Noam Date: Sun, 17 Sep 2017 02:40:09 +0300 Subject: [PATCH 12/14] Try DEcoding torrent name utf-8 in params --- headphones/deluge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/headphones/deluge.py b/headphones/deluge.py index 07699b0b..5eb27849 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -471,7 +471,7 @@ def _add_torrent_file(result): 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'].encode('utf8') + '.torrent', + "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, @@ -485,7 +485,7 @@ def _add_torrent_file(result): # this time let's try leaving the encoding as is logger.debug('Deluge: There was a decoding issue, let\'s try again') post_data = json.dumps({"method": "core.add_torrent_file", - "params": [result['name'] + '.torrent', + "params": [result['name'].decode('utf8') + '.torrent', b64encode(result['content']), {}], "id": 22}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, From 0828643c0943688dd72d60c7e3c78e9a36012810 Mon Sep 17 00:00:00 2001 From: Ade Date: Tue, 26 Sep 2017 11:06:34 +1300 Subject: [PATCH 13/14] Replace windows file/folder problem characters --- headphones/helpers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/headphones/helpers.py b/headphones/helpers.py index 05f6108b..6a117fc1 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -22,6 +22,7 @@ import time import sys import tempfile import glob +from unidecode import unidecode from beets import logging as beetslogging import six @@ -223,7 +224,11 @@ def replace_illegal_chars(string, type="file"): if type == "file": string = re.sub('[\?"*:|<>/]', '_', string) if type == "folder": - string = re.sub('[:\?<>"|]', '_', string) + string = re.sub('[:\?<>"|*]', '_', string) + + # Asciify windows file/folder names + if sys.platform == "win32": + string = unidecode(string) return string From f9d73da31b127d57d79144365b3ea89d872cb366 Mon Sep 17 00:00:00 2001 From: Ade Date: Sun, 22 Oct 2017 09:43:55 +1300 Subject: [PATCH 14/14] Remove unidecode for windows file names --- headphones/helpers.py | 6 ------ headphones/webserve.py | 16 ++++++++-------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/headphones/helpers.py b/headphones/helpers.py index 6a117fc1..acc64fd3 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -22,7 +22,6 @@ import time import sys import tempfile import glob -from unidecode import unidecode from beets import logging as beetslogging import six @@ -225,11 +224,6 @@ def replace_illegal_chars(string, type="file"): string = re.sub('[\?"*:|<>/]', '_', string) if type == "folder": string = re.sub('[:\?<>"|*]', '_', string) - - # Asciify windows file/folder names - if sys.platform == "win32": - string = unidecode(string) - return string diff --git a/headphones/webserve.py b/headphones/webserve.py index f1fbbfbe..9d703a5c 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -348,17 +348,17 @@ class WebInterface(object): dirs = set(dirs) - for dir in dirs: - artistfolder = os.path.join(dir, folder) - if not os.path.isdir(artistfolder.encode(headphones.SYS_ENCODING)): - logger.debug("Cannot find directory: " + artistfolder) - continue - try: + try: + for dir in dirs: + artistfolder = os.path.join(dir, folder) + if not os.path.isdir(artistfolder.encode(headphones.SYS_ENCODING)): + logger.debug("Cannot find directory: " + artistfolder) + continue threading.Thread(target=librarysync.libraryScan, kwargs={"dir": artistfolder, "artistScan": True, "ArtistID": ArtistID, "ArtistName": artist_name}).start() - except Exception as e: - logger.error('Unable to complete the scan: %s' % e) + except Exception as e: + logger.error('Unable to complete the scan: %s' % e) raise cherrypy.HTTPRedirect("artistPage?ArtistID=%s" % ArtistID)