diff --git a/data/interfaces/default/index.html b/data/interfaces/default/index.html
index 260c0a1a..e7becc61 100644
--- a/data/interfaces/default/index.html
+++ b/data/interfaces/default/index.html
@@ -36,7 +36,7 @@
"aTargets": [0],
"mData":"ArtistID",
"mRender": function ( data, type, full ) {
- return '
';
+ return '';
}
},
{
diff --git a/headphones/cache.py b/headphones/cache.py
index 0e946677..4b3df58c 100644
--- a/headphones/cache.py
+++ b/headphones/cache.py
@@ -14,11 +14,17 @@
# along with Headphones. If not, see .
import os
+from six.moves.urllib.parse import urlencode
import headphones
from headphones import db, helpers, logger, lastfm, request, mb
-LASTFM_API_KEY = "690e1ed3bc00bc91804cd8f7fe5ed6d4"
+# LASTFM_API_KEY = "690e1ed3bc00bc91804cd8f7fe5ed6d4"
+LASTFM_API_KEY = "a1c959f36a912a165d73c4dc5b9520f5"
+
+FANART_URL = 'https://webservice.fanart.tv/v3/music/'
+FANART_PROJECT_KEY = '22b73c9603eba09d0c855f2d2bdba31c'
+FANART_CLIENT_KEY = '919b389a18a3f0b2c916090022ab3c7a'
class Cache(object):
@@ -96,6 +102,11 @@ class Cache(object):
def _is_current(self, filename=None, date=None):
if filename:
+
+ # 2019 last.fm no longer allows access to artist images, for now we'll keep the cached artist image if it exists and get new from fanart.tv
+ if self.id_type == 'artist' and 'fanart' not in filename:
+ return True
+
base_filename = os.path.basename(filename)
date = base_filename.split('.')[1]
@@ -211,20 +222,34 @@ class Cache(object):
if ArtistID:
self.id_type = 'artist'
- data = lastfm.request_lastfm("artist.getinfo", mbid=ArtistID, api_key=LASTFM_API_KEY)
+
+ # 2019 last.fm no longer allows access to artist images, try fanart.tv instead
+ image_url = None
+ thumb_url = None
+ data = request.request_json(FANART_URL + ArtistID, whitelist_status_code=404,
+ headers={'api-key': FANART_PROJECT_KEY, 'client-key': FANART_CLIENT_KEY})
if not data:
return
- try:
- image_url = data['artist']['image'][-1]['#text']
- except (KeyError, IndexError):
- logger.debug('No artist image found')
- image_url = None
+ if data.get('artistthumb'):
+ image_url = data['artistthumb'][0]['url']
+ elif data.get('artistbackground'):
+ image_url = data['artistbackground'][0]['url']
+ # elif data.get('hdmusiclogo'):
+ # image_url = data['hdmusiclogo'][0]['url']
- thumb_url = self._get_thumb_url(data)
- if not thumb_url:
- logger.debug('No artist thumbnail image found')
+ # fallback to 1st album cover if none of the above
+ elif 'albums' in data:
+ for mbid, art in data.get('albums', dict()).items():
+ if 'albumcover' in art:
+ image_url = art['albumcover'][0]['url']
+ break
+
+ if image_url:
+ thumb_url = image_url
+ else:
+ logger.debug('No artist image found on fanart.tv for Artist Id: %s', self.id)
else:
@@ -283,6 +308,7 @@ class Cache(object):
"""
myDB = db.DBConnection()
+ fanart = False
# Since lastfm uses release ids rather than release group ids for albums, we have to do a artist + album search for albums
# Exception is when adding albums manually, then we should use release id
@@ -311,15 +337,42 @@ class Cache(object):
except KeyError:
logger.debug('No artist bio found')
self.info_content = None
- try:
- image_url = data['artist']['image'][-1]['#text']
- except KeyError:
- logger.debug('No artist image found')
- image_url = None
- thumb_url = self._get_thumb_url(data)
- if not thumb_url:
- logger.debug('No artist thumbnail image found')
+ # 2019 last.fm no longer allows access to artist images, try fanart.tv instead
+ image_url = None
+ thumb_url = None
+ data = request.request_json(FANART_URL + self.id, whitelist_status_code=404,
+ headers={'api-key': FANART_PROJECT_KEY, 'client-key': FANART_CLIENT_KEY})
+
+ if data.get('artistthumb'):
+ image_url = data['artistthumb'][0]['url']
+ elif data.get('artistbackground'):
+ image_url = data['artistbackground'][0]['url']
+ # elif data.get('hdmusiclogo'):
+ # image_url = data['hdmusiclogo'][0]['url']
+
+ # fallback to 1st album cover if none of the above
+ elif 'albums' in data:
+ for mbid, art in data.get('albums', dict()).items():
+ if 'albumcover' in art:
+ image_url = art['albumcover'][0]['url']
+ break
+
+ # finally, use 1st album cover from last.fm
+ if image_url:
+ fanart = True
+ thumb_url = image_url
+ else:
+ dbalbum = myDB.action(
+ 'SELECT ArtworkURL, ThumbURL FROM albums WHERE ArtworkURL IS NOT NULL AND ArtistID=?',
+ [self.id]).fetchone()
+ if dbalbum:
+ fanart = True
+ image_url = dbalbum['ArtworkURL']
+ thumb_url = dbalbum['ThumbURL']
+
+ if not image_url:
+ logger.debug('No artist image found on fanart.tv for Artist Id: %s', self.id)
else:
dbalbum = myDB.action(
@@ -427,7 +480,11 @@ class Cache(object):
ext = os.path.splitext(image_url)[1]
- artwork_path = os.path.join(self.path_to_art_cache,
+ if fanart:
+ artwork_path = os.path.join(self.path_to_art_cache,
+ self.id + '_fanart_' + '.' + helpers.today() + ext)
+ else:
+ artwork_path = os.path.join(self.path_to_art_cache,
self.id + '.' + helpers.today() + ext)
try:
with open(artwork_path, 'wb') as f:
@@ -443,7 +500,9 @@ class Cache(object):
# as it's missing/outdated.
if thumb_url and self.query_type in ['thumb', 'artwork'] and not (
self.thumb_files and self._is_current(self.thumb_files[0])):
- artwork = request.request_content(thumb_url, timeout=20)
+
+ if not (self.query_type == 'artwork' and 'fanart' in thumb_url and artwork):
+ artwork = request.request_content(thumb_url, timeout=20)
if artwork:
# Make sure the artwork dir exists:
@@ -466,11 +525,34 @@ class Cache(object):
ext = os.path.splitext(image_url)[1]
- thumb_path = os.path.join(self.path_to_art_cache,
- 'T_' + self.id + '.' + helpers.today() + ext)
+ if fanart:
+ thumb_path = os.path.join(self.path_to_art_cache,
+ 'T_' + self.id + '_fanart_' + '.' + helpers.today() + ext)
+ else:
+ thumb_path = os.path.join(self.path_to_art_cache,
+ 'T_' + self.id + '.' + helpers.today() + ext)
try:
- with open(thumb_path, 'wb') as f:
- f.write(artwork)
+ if self.id_type != 'artist':
+ with open(thumb_path, 'wb') as f:
+ f.write(artwork)
+ else:
+
+ # 2019 last.fm no longer allows access to artist images, use the fanart.tv image to create a thumb
+ artwork_thumb = None
+ if 'fanart' in thumb_url:
+ # Create thumb using image resizing service
+ artwork_path = '{0}?{1}'.format('http://images.weserv.nl/', urlencode({
+ 'url': thumb_url.replace('http://', ''),
+ 'w': 300,
+ }))
+ artwork_thumb = request.request_content(artwork_path, timeout=20, whitelist_status_code=404)
+
+ if artwork_thumb:
+ with open(thumb_path, 'wb') as f:
+ f.write(artwork_thumb)
+ else:
+ with open(thumb_path, 'wb') as f:
+ f.write(artwork)
os.chmod(thumb_path, int(headphones.CONFIG.FILE_PERMISSIONS, 8))
except (OSError, IOError) as e:
@@ -486,7 +568,7 @@ def getArtwork(ArtistID=None, AlbumID=None):
if not artwork_path:
return None
- if artwork_path.startswith('http://'):
+ if artwork_path.startswith(('http://', 'https://')):
return artwork_path
else:
artwork_file = os.path.basename(artwork_path)
@@ -500,7 +582,7 @@ def getThumb(ArtistID=None, AlbumID=None):
if not artwork_path:
return None
- if artwork_path.startswith('http://'):
+ if artwork_path.startswith(('http://', 'https://')):
return artwork_path
else:
thumbnail_file = os.path.basename(artwork_path)
diff --git a/headphones/librarysync.py b/headphones/librarysync.py
index a04d3535..dbf9fb4b 100644
--- a/headphones/librarysync.py
+++ b/headphones/librarysync.py
@@ -364,6 +364,11 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None,
for artist in unique_artists:
+ if not artist:
+ continue
+
+ logger.info('Processing artist: %s' % artist)
+
# check if artist is already in the db
artist_lookup = "\"" + artist.replace("\"", "\"\"") + "\""
@@ -399,20 +404,23 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None,
# [artist]))
# )
- havetracks = (
- len(myDB.select(
- 'SELECT ArtistID From tracks WHERE ArtistID = ? AND Location IS NOT NULL',
- [artistid])) + len(myDB.select(
- 'SELECT ArtistName FROM have WHERE ArtistName LIKE ' + artist_lookup + ' AND Matched = "Failed"'))
- )
+ try:
+ havetracks = (
+ len(myDB.select(
+ 'SELECT ArtistID From tracks WHERE ArtistID = ? AND Location IS NOT NULL',
+ [artistid])) + len(myDB.select(
+ 'SELECT ArtistName FROM have WHERE ArtistName LIKE ' + artist_lookup + ' AND Matched = "Failed"'))
+ )
+ except Exception as e:
+ logger.warn('Error updating counts for artist: %s: %s' % (artist, e))
# Note: some people complain about having "artist have tracks" > # of tracks total in artist official releases
# (can fix by getting rid of second len statement)
- myDB.action('UPDATE artists SET HaveTracks = ? WHERE ArtistID = ?', [havetracks, artistid])
-
- # Update albums to downloaded
if havetracks:
+ myDB.action('UPDATE artists SET HaveTracks = ? WHERE ArtistID = ?', [havetracks, artistid])
+
+ # Update albums to downloaded
update_album_status(ArtistID=artistid)
logger.info('Found %i new artists' % len(new_artist_list))
@@ -436,11 +444,16 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None,
logger.info('Updating artist track counts')
artist_lookup = "\"" + ArtistName.replace("\"", "\"\"") + "\""
- havetracks = len(
- myDB.select('SELECT ArtistID FROM tracks WHERE ArtistID = ? AND Location IS NOT NULL',
- [ArtistID])) + len(myDB.select(
- 'SELECT ArtistName FROM have WHERE ArtistName LIKE ' + artist_lookup + ' AND Matched = "Failed"'))
- myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, ArtistID])
+ try:
+ havetracks = len(
+ myDB.select('SELECT ArtistID FROM tracks WHERE ArtistID = ? AND Location IS NOT NULL',
+ [ArtistID])) + len(myDB.select(
+ 'SELECT ArtistName FROM have WHERE ArtistName LIKE ' + artist_lookup + ' AND Matched = "Failed"'))
+ except Exception as e:
+ logger.warn('Error updating counts for artist: %s: %s' % (ArtistName, e))
+
+ if havetracks:
+ myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, ArtistID])
# Moved above to call for each artist
# if not append:
diff --git a/headphones/mb.py b/headphones/mb.py
index c087d6b9..7d9b9c50 100644
--- a/headphones/mb.py
+++ b/headphones/mb.py
@@ -793,3 +793,27 @@ def getArtistForReleaseGroup(rgid):
return False
else:
return releaseGroup['artist-credit'][0]['artist']['name']
+
+
+def getArtistRelationships(artistid):
+ """
+ Returns list of relationship urls. e.g. Discogs, Wikipedia etc.
+ """
+ urls = []
+ artist = None
+ try:
+ with mb_lock:
+ info = musicbrainzngs.get_artist_by_id(artistid, includes='url-rels')
+ except musicbrainzngs.WebServiceError as e:
+ logger.warn(
+ 'Attempt to query MusicBrainz for %s failed "%s"' % (artistid, str(e)))
+ mb_lock.snooze(5)
+ if 'artist' in info:
+ artist = info['artist']
+ if 'url-relation-list' in artist:
+ for l in artist['url-relation-list']:
+ urls.append({
+ 'type': l['type'],
+ 'url': l['target']
+ })
+ return urls
diff --git a/headphones/notifiers.py b/headphones/notifiers.py
index 15e5e310..5f3e8620 100644
--- a/headphones/notifiers.py
+++ b/headphones/notifiers.py
@@ -1017,7 +1017,7 @@ class Email(object):
class TELEGRAM(object):
- def notify(self, message, status):
+ def notify(self, message, status, rgid=None, image=None):
if not headphones.CONFIG.TELEGRAM_ENABLED:
return
@@ -1030,22 +1030,34 @@ class TELEGRAM(object):
userid = headphones.CONFIG.TELEGRAM_USERID
# Construct message
- payload = {'chat_id': userid, 'text': status + ': ' + message}
+ message = '\n\n' + 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))
+ # MusicBrainz link
+ if rgid:
+ message += '\n\n MusicBrainz' % rgid
+
+ # Send image
+ response = None
+ if image:
+ image_file = {'photo': (image, open(image, "rb"))}
+ payload = {'chat_id': userid, 'parse_mode': "HTML", 'caption': status + message}
+ try:
+ response = requests.post(TELEGRAM_API % (token, "sendPhoto"), data=payload, files=image_file)
+ except Exception, e:
+ logger.info(u'Telegram notify failed: ' + str(e))
+ # Sent text
+ else:
+ payload = {'chat_id': userid, 'parse_mode': "HTML", 'text': status + message}
+ 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 '
- u'(token=%s). Response: [%s]',
- (token, response.text))
+ if response and not response.status_code == 200:
+ logger.info("Could not send notification to TelegramBot (token=%s). Response: [%s]", token, response.text)
sent_successfuly = False
logger.info(u"Telegram notifications sent.")
diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py
index b2f7126b..5c7f4ebe 100755
--- a/headphones/postprocessor.py
+++ b/headphones/postprocessor.py
@@ -586,7 +586,7 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
if headphones.CONFIG.TELEGRAM_ENABLED:
logger.info(u"Telegram request")
telegram = notifiers.TELEGRAM()
- telegram.notify(pushmessage, statusmessage)
+ telegram.notify(statusmessage, pushmessage)
if headphones.CONFIG.TWITTER_ENABLED:
logger.info(u"Sending Twitter notification")
diff --git a/headphones/searcher.py b/headphones/searcher.py
index 1e51dc58..d7536b22 100644
--- a/headphones/searcher.py
+++ b/headphones/searcher.py
@@ -1075,8 +1075,12 @@ def send_to_downloader(data, bestqual, album):
slack.notify(name, "Download started")
if headphones.CONFIG.TELEGRAM_ENABLED and headphones.CONFIG.TELEGRAM_ONSNATCH:
logger.info(u"Sending Telegram notification")
+ from headphones import cache
+ c = cache.Cache()
+ album_art = c.get_artwork_from_cache(None, rgid)
telegram = notifiers.TELEGRAM()
- telegram.notify(name, "Download started")
+ message = 'Snatched from ' + provider + '. ' + name
+ telegram.notify(message, "Snatched: " + title, rgid, image=album_art)
if headphones.CONFIG.TWITTER_ENABLED and headphones.CONFIG.TWITTER_ONSNATCH:
logger.info(u"Sending Twitter notification")
twitter = notifiers.TwitterNotifier()
diff --git a/lib/requests/__init__.py b/lib/requests/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/adapters.py b/lib/requests/adapters.py
old mode 100644
new mode 100755
diff --git a/lib/requests/api.py b/lib/requests/api.py
old mode 100644
new mode 100755
diff --git a/lib/requests/auth.py b/lib/requests/auth.py
old mode 100644
new mode 100755
diff --git a/lib/requests/cacert.pem b/lib/requests/cacert.pem
old mode 100644
new mode 100755
diff --git a/lib/requests/certs.py b/lib/requests/certs.py
old mode 100644
new mode 100755
diff --git a/lib/requests/compat.py b/lib/requests/compat.py
old mode 100644
new mode 100755
diff --git a/lib/requests/cookies.py b/lib/requests/cookies.py
old mode 100644
new mode 100755
diff --git a/lib/requests/exceptions.py b/lib/requests/exceptions.py
old mode 100644
new mode 100755
diff --git a/lib/requests/hooks.py b/lib/requests/hooks.py
old mode 100644
new mode 100755
diff --git a/lib/requests/models.py b/lib/requests/models.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/README.rst b/lib/requests/packages/README.rst
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/__init__.py b/lib/requests/packages/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/__init__.py b/lib/requests/packages/chardet/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/big5freq.py b/lib/requests/packages/chardet/big5freq.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/big5prober.py b/lib/requests/packages/chardet/big5prober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/chardistribution.py b/lib/requests/packages/chardet/chardistribution.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/charsetgroupprober.py b/lib/requests/packages/chardet/charsetgroupprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/charsetprober.py b/lib/requests/packages/chardet/charsetprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/codingstatemachine.py b/lib/requests/packages/chardet/codingstatemachine.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/compat.py b/lib/requests/packages/chardet/compat.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/constants.py b/lib/requests/packages/chardet/constants.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/cp949prober.py b/lib/requests/packages/chardet/cp949prober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/escprober.py b/lib/requests/packages/chardet/escprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/escsm.py b/lib/requests/packages/chardet/escsm.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/eucjpprober.py b/lib/requests/packages/chardet/eucjpprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/euckrfreq.py b/lib/requests/packages/chardet/euckrfreq.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/euckrprober.py b/lib/requests/packages/chardet/euckrprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/euctwfreq.py b/lib/requests/packages/chardet/euctwfreq.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/euctwprober.py b/lib/requests/packages/chardet/euctwprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/gb2312freq.py b/lib/requests/packages/chardet/gb2312freq.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/gb2312prober.py b/lib/requests/packages/chardet/gb2312prober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/hebrewprober.py b/lib/requests/packages/chardet/hebrewprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/jisfreq.py b/lib/requests/packages/chardet/jisfreq.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/jpcntx.py b/lib/requests/packages/chardet/jpcntx.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langbulgarianmodel.py b/lib/requests/packages/chardet/langbulgarianmodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langcyrillicmodel.py b/lib/requests/packages/chardet/langcyrillicmodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langgreekmodel.py b/lib/requests/packages/chardet/langgreekmodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langhebrewmodel.py b/lib/requests/packages/chardet/langhebrewmodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langhungarianmodel.py b/lib/requests/packages/chardet/langhungarianmodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/langthaimodel.py b/lib/requests/packages/chardet/langthaimodel.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/latin1prober.py b/lib/requests/packages/chardet/latin1prober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/mbcharsetprober.py b/lib/requests/packages/chardet/mbcharsetprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/mbcsgroupprober.py b/lib/requests/packages/chardet/mbcsgroupprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/mbcssm.py b/lib/requests/packages/chardet/mbcssm.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/sbcharsetprober.py b/lib/requests/packages/chardet/sbcharsetprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/sbcsgroupprober.py b/lib/requests/packages/chardet/sbcsgroupprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/sjisprober.py b/lib/requests/packages/chardet/sjisprober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/universaldetector.py b/lib/requests/packages/chardet/universaldetector.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/chardet/utf8prober.py b/lib/requests/packages/chardet/utf8prober.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/__init__.py b/lib/requests/packages/urllib3/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/_collections.py b/lib/requests/packages/urllib3/_collections.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/connection.py b/lib/requests/packages/urllib3/connection.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/connectionpool.py b/lib/requests/packages/urllib3/connectionpool.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/contrib/__init__.py b/lib/requests/packages/urllib3/contrib/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/contrib/appengine.py b/lib/requests/packages/urllib3/contrib/appengine.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/contrib/ntlmpool.py b/lib/requests/packages/urllib3/contrib/ntlmpool.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/contrib/pyopenssl.py b/lib/requests/packages/urllib3/contrib/pyopenssl.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/exceptions.py b/lib/requests/packages/urllib3/exceptions.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/fields.py b/lib/requests/packages/urllib3/fields.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/filepost.py b/lib/requests/packages/urllib3/filepost.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/packages/__init__.py b/lib/requests/packages/urllib3/packages/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/packages/ordered_dict.py b/lib/requests/packages/urllib3/packages/ordered_dict.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/packages/six.py b/lib/requests/packages/urllib3/packages/six.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py b/lib/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py b/lib/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/poolmanager.py b/lib/requests/packages/urllib3/poolmanager.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/request.py b/lib/requests/packages/urllib3/request.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/response.py b/lib/requests/packages/urllib3/response.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/__init__.py b/lib/requests/packages/urllib3/util/__init__.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/connection.py b/lib/requests/packages/urllib3/util/connection.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/request.py b/lib/requests/packages/urllib3/util/request.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/response.py b/lib/requests/packages/urllib3/util/response.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/retry.py b/lib/requests/packages/urllib3/util/retry.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/ssl_.py b/lib/requests/packages/urllib3/util/ssl_.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/timeout.py b/lib/requests/packages/urllib3/util/timeout.py
old mode 100644
new mode 100755
diff --git a/lib/requests/packages/urllib3/util/url.py b/lib/requests/packages/urllib3/util/url.py
old mode 100644
new mode 100755
diff --git a/lib/requests/sessions.py b/lib/requests/sessions.py
old mode 100644
new mode 100755
diff --git a/lib/requests/status_codes.py b/lib/requests/status_codes.py
old mode 100644
new mode 100755
diff --git a/lib/requests/structures.py b/lib/requests/structures.py
old mode 100644
new mode 100755
diff --git a/lib/requests/utils.py b/lib/requests/utils.py
old mode 100644
new mode 100755