mirror of
				https://github.com/KevinMidboe/spotify-downloader.git
				synced 2025-10-29 18:00:15 +00:00 
			
		
		
		
	Drop python 2 compatibility (#107)
This commit is contained in:
		| @@ -1,6 +1,5 @@ | ||||
| language: python | ||||
| python: | ||||
|   - "2.7" | ||||
|   - "3.4" | ||||
|   - "3.5" | ||||
|   - "3.6" | ||||
|   | ||||
| @@ -17,7 +17,7 @@ Please follow the guide below | ||||
| - [ ] Other | ||||
|  | ||||
| #### System information | ||||
| - Your `python` version: `python 2.7` | ||||
| - Your `python` version: `python 3.x` | ||||
| - Your operating system: `Ubuntu 16.04` | ||||
|  | ||||
| ### Description | ||||
|   | ||||
| @@ -33,7 +33,7 @@ That's how your Music library will look like! | ||||
|  | ||||
| <img src="http://i.imgur.com/Dg8p9up.png" width="600"> | ||||
|  | ||||
| - This version supports Python 3, Python 2 compatibility was dropped. If you need to use Python 2 though, check out the `python2` branch. | ||||
| - **This version supports Python 3**, Python 2 compatibility was dropped because of the way it deals with unicode. If you need to use Python 2 though, check out the `python2` branch. | ||||
|  | ||||
| - Note: `play` and `lyrics` commands have been deprecated in the current brach since they were not of much use and created unnecessary clutter. You can still get them back by using `old` branch though. | ||||
|  | ||||
|   | ||||
| @@ -1,14 +1,10 @@ | ||||
| import subprocess | ||||
| import os | ||||
| import sys | ||||
|  | ||||
|  | ||||
| def song(input_song, output_song, avconv=False, verbose=False): | ||||
|     """Do the audio format conversion.""" | ||||
|     if not input_song == output_song: | ||||
|         if sys.version_info < (3, 0): | ||||
|             input_song = input_song.encode('utf-8') | ||||
|             output_song = output_song.encode('utf-8') | ||||
|         print('Converting {0} to {1}'.format( | ||||
|             input_song, output_song.split('.')[-1])) | ||||
|         if avconv: | ||||
|   | ||||
| @@ -1,26 +1,21 @@ | ||||
| from mutagen.easyid3 import EasyID3 | ||||
| from mutagen.id3 import ID3, APIC | ||||
| from mutagen.mp4 import MP4, MP4Cover | ||||
| import sys | ||||
|  | ||||
| # urllib2 is urllib.request in python3 | ||||
| try: | ||||
|     import urllib2 | ||||
| except ImportError: | ||||
|     import urllib.request as urllib2 | ||||
| import urllib.request | ||||
|  | ||||
|  | ||||
| def compare(file, metadata): | ||||
|     """Check if the input file title matches the expected title.""" | ||||
| def compare(music_file, metadata): | ||||
|     """Check if the input music file title matches the expected title.""" | ||||
|     already_tagged = False | ||||
|     try: | ||||
|         if file.endswith('.mp3'): | ||||
|             audiofile = EasyID3('Music/' + file) | ||||
|         if music_file.endswith('.mp3'): | ||||
|             audiofile = EasyID3('Music/' + music_file) | ||||
|             # fetch track title metadata | ||||
|             already_tagged = audiofile['title'][0] == metadata['name'] | ||||
|         elif file.endswith('.m4a'): | ||||
|         elif music_file.endswith('.m4a'): | ||||
|             tags = {'title': '\xa9nam'} | ||||
|             audiofile = MP4('Music/' + file) | ||||
|             audiofile = MP4('Music/' + music_file) | ||||
|             # fetch track title metadata | ||||
|             already_tagged = audiofile[tags['title']] == metadata['name'] | ||||
|     except (KeyError, TypeError): | ||||
| @@ -30,8 +25,6 @@ def compare(file, metadata): | ||||
|  | ||||
| def embed(music_file, meta_tags): | ||||
|     """Embed metadata.""" | ||||
|     if sys.version_info < (3, 0): | ||||
|         music_file = music_file.encode('utf-8') | ||||
|     if meta_tags is None: | ||||
|         print('Could not find meta-tags') | ||||
|         return None | ||||
| @@ -74,7 +67,7 @@ def embed_mp3(music_file, meta_tags): | ||||
|         audiofile['copyright'] = meta_tags['copyright'] | ||||
|     audiofile.save(v2_version=3) | ||||
|     audiofile = ID3('Music/' + music_file) | ||||
|     albumart = urllib2.urlopen(meta_tags['album']['images'][0]['url']) | ||||
|     albumart = urllib.request.urlopen(meta_tags['album']['images'][0]['url']) | ||||
|     audiofile["APIC"] = APIC(encoding=3, mime='image/jpeg', type=3, | ||||
|                              desc=u'Cover', data=albumart.read()) | ||||
|     albumart.close() | ||||
| @@ -117,7 +110,7 @@ def embed_m4a(music_file, meta_tags): | ||||
|         audiofile[tags['genre']] = meta_tags['genre'] | ||||
|     if meta_tags['copyright']: | ||||
|         audiofile[tags['copyright']] = meta_tags['copyright'] | ||||
|     albumart = urllib2.urlopen(meta_tags['album']['images'][0]['url']) | ||||
|     albumart = urllib.request.urlopen(meta_tags['album']['images'][0]['url']) | ||||
|     audiofile[tags['albumart']] = [MP4Cover( | ||||
|         albumart.read(), imageformat=MP4Cover.FORMAT_JPEG)] | ||||
|     albumart.close() | ||||
|   | ||||
							
								
								
									
										42
									
								
								core/misc.py
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								core/misc.py
									
									
									
									
									
								
							| @@ -1,20 +1,15 @@ | ||||
| import argparse | ||||
| import sys | ||||
| import os | ||||
| from slugify import slugify | ||||
| import argparse | ||||
| import spotipy.oauth2 as oauth2 | ||||
|  | ||||
| try: | ||||
|     from urllib2 import quote | ||||
| except ImportError: | ||||
|     from urllib.request import quote | ||||
|  | ||||
| from urllib.request import quote | ||||
| from slugify import slugify | ||||
|  | ||||
| def input_link(links): | ||||
|     """Let the user input a number.""" | ||||
|     while True: | ||||
|         try: | ||||
|             the_chosen_one = int(user_input('>> Choose your number: ')) | ||||
|             the_chosen_one = int(input('>> Choose your number: ')) | ||||
|             if 1 <= the_chosen_one <= len(links): | ||||
|                 return links[the_chosen_one - 1] | ||||
|             elif the_chosen_one == 0: | ||||
| @@ -25,14 +20,6 @@ def input_link(links): | ||||
|             print('Choose a valid number!') | ||||
|  | ||||
|  | ||||
| def user_input(string=''): | ||||
|     """Take input correctly for both Python 2 & 3.""" | ||||
|     if sys.version_info > (3, 0): | ||||
|         return input(string) | ||||
|     else: | ||||
|         return raw_input(string) | ||||
|  | ||||
|  | ||||
| def trim_song(file): | ||||
|     """Remove the first song from file.""" | ||||
|     with open(file, 'r') as file_in: | ||||
| @@ -88,14 +75,11 @@ def is_spotify(raw_song): | ||||
|  | ||||
| def generate_filename(title): | ||||
|     """Generate filename of the song to be downloaded.""" | ||||
|     # IMO python2 sucks dealing with unicode | ||||
|     title = fix_encoding(title) | ||||
|     title = fix_decoding(title) | ||||
|     title = title.replace(' ', '_') | ||||
|  | ||||
|     # slugify removes any special characters | ||||
|     filename = slugify(title, ok='-_()[]{}', lower=False) | ||||
|     return fix_encoding(filename) | ||||
|     return filename | ||||
|  | ||||
|  | ||||
| def generate_token(): | ||||
| @@ -109,26 +93,12 @@ def generate_token(): | ||||
|  | ||||
| def generate_search_url(song): | ||||
|     """Generate YouTube search URL for the given song.""" | ||||
|     # urllib2.quote() encodes URL with special characters | ||||
|     # urllib.request.quote() encodes URL with special characters | ||||
|     url = u"https://www.youtube.com/results?sp=EgIQAQ%253D%253D&q={0}".format( | ||||
|         quote(song)) | ||||
|     return url | ||||
|  | ||||
|  | ||||
| def fix_encoding(query): | ||||
|     """Fix encoding issues in Python 2.""" | ||||
|     if sys.version_info < (3, 0): | ||||
|         query = query.encode('utf-8') | ||||
|     return query | ||||
|  | ||||
|  | ||||
| def fix_decoding(query): | ||||
|     """Fix decoding issues in Python 2.""" | ||||
|     if sys.version_info < (3, 0): | ||||
|         query = query.decode('utf-8') | ||||
|     return query | ||||
|  | ||||
|  | ||||
| def filter_path(path): | ||||
|     os.chdir(sys.path[0]) | ||||
|     if not os.path.exists(path): | ||||
|   | ||||
							
								
								
									
										64
									
								
								spotdl.py
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								spotdl.py
									
									
									
									
									
								
							| @@ -9,22 +9,17 @@ from titlecase import titlecase | ||||
| from slugify import slugify | ||||
| import spotipy | ||||
| import pafy | ||||
| import urllib.request | ||||
| import sys | ||||
| import os | ||||
|  | ||||
| # urllib2 is urllib.request in python3 | ||||
| try: | ||||
|     import urllib2 | ||||
| except ImportError: | ||||
|     import urllib.request as urllib2 | ||||
|  | ||||
|  | ||||
| def generate_songname(raw_song): | ||||
|     """Generate a string of the format '[artist] - [song]' for the given song.""" | ||||
|     if misc.is_spotify(raw_song): | ||||
|         tags = generate_metadata(raw_song) | ||||
|         raw_song = u'{0} - {1}'.format(tags['artists'][0]['name'], tags['name']) | ||||
|     return misc.fix_encoding(raw_song) | ||||
|     return raw_song | ||||
|  | ||||
|  | ||||
| def generate_metadata(raw_song): | ||||
| @@ -63,7 +58,7 @@ def generate_youtube_url(raw_song): | ||||
|     """Search for the song on YouTube and generate an URL to its video.""" | ||||
|     song = generate_songname(raw_song) | ||||
|     search_url = misc.generate_search_url(song) | ||||
|     item = urllib2.urlopen(search_url).read() | ||||
|     item = urllib.request.urlopen(search_url).read() | ||||
|     # item = unicode(item, 'utf-8') | ||||
|     items_parse = BeautifulSoup(item, "html.parser") | ||||
|     check = 1 | ||||
| @@ -112,7 +107,7 @@ def go_pafy(raw_song): | ||||
|  | ||||
| def get_youtube_title(content, number=None): | ||||
|     """Get the YouTube video's title.""" | ||||
|     title = misc.fix_encoding(content.title) | ||||
|     title = content.title | ||||
|     if number is None: | ||||
|         return title | ||||
|     else: | ||||
| @@ -131,7 +126,7 @@ def feed_playlist(username): | ||||
|             # is None. Skip these. Also see Issue #91. | ||||
|             if playlist['name'] is not None: | ||||
|                 print(u'{0:>5}.| {1:<30} | ({2} tracks)'.format( | ||||
|                     check, misc.fix_encoding(playlist['name']), | ||||
|                     check, playlist['name'], | ||||
|                     playlist['tracks']['total'])) | ||||
|                 links.append(playlist) | ||||
|                 check += 1 | ||||
| @@ -145,11 +140,11 @@ def feed_playlist(username): | ||||
|     results = spotify.user_playlist( | ||||
|         playlist['owner']['id'], playlist['id'], fields='tracks,next') | ||||
|     print('') | ||||
|     file = u'{0}.txt'.format(slugify(playlist['name'], ok='-_()[]{}')) | ||||
|     print(u'Feeding {0} tracks to {1}'.format(playlist['tracks']['total'], file)) | ||||
|     text_file = u'{0}.txt'.format(slugify(playlist['name'], ok='-_()[]{}')) | ||||
|     print(u'Feeding {0} tracks to {1}'.format(playlist['tracks']['total'], text_file)) | ||||
|  | ||||
|     tracks = results['tracks'] | ||||
|     with open(file, 'a') as file_out: | ||||
|     with open(text_file, 'a') as file_out: | ||||
|         while True: | ||||
|             for item in tracks['items']: | ||||
|                 track = item['track'] | ||||
| @@ -186,21 +181,20 @@ def download_song(content): | ||||
|  | ||||
| def check_exists(music_file, raw_song, islist=True): | ||||
|     """Check if the input song already exists in the 'Music' folder.""" | ||||
|     files = os.listdir('Music') | ||||
|     for file in files: | ||||
|         if file.endswith('.temp'): | ||||
|             os.remove(u'Music/{0}'.format(file)) | ||||
|     songs = os.listdir('Music') | ||||
|     for song in songs: | ||||
|         if song.endswith('.temp'): | ||||
|             os.remove(u'Music/{0}'.format(song)) | ||||
|             continue | ||||
|         # check if any file with similar name is already present in Music/ | ||||
|         dfile = misc.fix_decoding(file) | ||||
|         umfile = misc.fix_decoding(misc.generate_filename(music_file)) | ||||
|         if dfile.startswith(umfile): | ||||
|         # check if any song with similar name is already present in Music/ | ||||
|         umfile = misc.generate_filename(music_file) | ||||
|         if song.startswith(umfile): | ||||
|             # check if the already downloaded song has correct metadata | ||||
|             already_tagged = metadata.compare(file, generate_metadata(raw_song)) | ||||
|             already_tagged = metadata.compare(song, generate_metadata(raw_song)) | ||||
|  | ||||
|             # if not, remove it and download again without prompt | ||||
|             if misc.is_spotify(raw_song) and not already_tagged: | ||||
|                 os.remove('Music/{0}'.format(file)) | ||||
|                 os.remove('Music/{0}'.format(song)) | ||||
|                 return False | ||||
|  | ||||
|             # do not prompt and skip the current song | ||||
| @@ -209,22 +203,21 @@ def check_exists(music_file, raw_song, islist=True): | ||||
|                 return True | ||||
|             # if downloading only single song, prompt to re-download | ||||
|             else: | ||||
|                 prompt = misc.user_input( | ||||
|                     'Song with same name has already been downloaded. ' | ||||
|                 prompt = input('Song with same name has already been downloaded. ' | ||||
|                                'Re-download? (y/n): ').lower() | ||||
|                 if prompt == 'y': | ||||
|                     os.remove('Music/{0}'.format(file)) | ||||
|                     os.remove('Music/{0}'.format(song)) | ||||
|                     return False | ||||
|                 else: | ||||
|                     return True | ||||
|     return False | ||||
|  | ||||
|  | ||||
| def grab_list(file): | ||||
| def grab_list(text_file): | ||||
|     """Download all songs from the list.""" | ||||
|     with open(file, 'r') as listed: | ||||
|     with open(text_file, 'r') as listed: | ||||
|         lines = (listed.read()).splitlines() | ||||
|     # ignore blank lines in file (if any) | ||||
|     # ignore blank lines in text_file (if any) | ||||
|     try: | ||||
|         lines.remove('') | ||||
|     except ValueError: | ||||
| @@ -244,12 +237,12 @@ def grab_list(file): | ||||
|             spotify = spotipy.Spotify(auth=new_token) | ||||
|             grab_single(raw_song, number=number) | ||||
|         # detect network problems | ||||
|         except (urllib2.URLError, TypeError, IOError): | ||||
|         except (urllib.request.URLError, TypeError, IOError): | ||||
|             lines.append(raw_song) | ||||
|             # remove the downloaded song from .txt | ||||
|             misc.trim_song(file) | ||||
|             misc.trim_song(text_file) | ||||
|             # and append it to the last line in .txt | ||||
|             with open(file, 'a') as myfile: | ||||
|             with open(text_file, 'a') as myfile: | ||||
|                 myfile.write(raw_song) | ||||
|             print('Failed to download song. Will retry after other songs.') | ||||
|             continue | ||||
| @@ -257,7 +250,7 @@ def grab_list(file): | ||||
|             misc.grace_quit() | ||||
|         finally: | ||||
|             print('') | ||||
|         misc.trim_song(file) | ||||
|         misc.trim_song(text_file) | ||||
|         number += 1 | ||||
|  | ||||
|  | ||||
| @@ -276,7 +269,6 @@ def grab_single(raw_song, number=None): | ||||
|  | ||||
|     # generate file name of the song to download | ||||
|     music_file = misc.generate_filename(content.title) | ||||
|     music_file = misc.fix_decoding(music_file) | ||||
|     if not check_exists(music_file, raw_song, islist=islist): | ||||
|         if download_song(content): | ||||
|             print('') | ||||
| @@ -285,7 +277,7 @@ def grab_single(raw_song, number=None): | ||||
|             convert.song(input_song, output_song, avconv=args.avconv, | ||||
|                          verbose=args.verbose) | ||||
|             if not args.input_ext == args.output_ext: | ||||
|                 os.remove('Music/{0}'.format(misc.fix_encoding(input_song))) | ||||
|                 os.remove('Music/{0}'.format(input_song)) | ||||
|             meta_tags = generate_metadata(raw_song) | ||||
|             if not args.no_metadata: | ||||
|                 metadata.embed(output_song, meta_tags) | ||||
| @@ -313,6 +305,6 @@ if __name__ == '__main__': | ||||
|     if args.song: | ||||
|         grab_single(raw_song=args.song) | ||||
|     elif args.list: | ||||
|         grab_list(file=args.list) | ||||
|         grab_list(text_file=args.list) | ||||
|     elif args.username: | ||||
|         feed_playlist(username=args.username) | ||||
|   | ||||
| @@ -32,7 +32,6 @@ def test_check_exists(): | ||||
|     expect_check = False | ||||
|     content = spotdl.go_pafy(raw_song) | ||||
|     music_file = spotdl.misc.generate_filename(content.title) | ||||
|     music_file = spotdl.misc.fix_decoding(music_file) | ||||
|     check = spotdl.check_exists(music_file, raw_song, islist=True) | ||||
|     assert check == expect_check | ||||
|  | ||||
| @@ -49,7 +48,6 @@ def test_convert(): | ||||
|     expect_convert = 0 | ||||
|     content = spotdl.go_pafy(raw_song) | ||||
|     music_file = spotdl.misc.generate_filename(content.title) | ||||
|     music_file = spotdl.misc.fix_decoding(music_file) | ||||
|     input_song = music_file + spotdl.args.input_ext | ||||
|     output_song = music_file + spotdl.args.output_ext | ||||
|     convert = spotdl.convert.song(input_song, output_song) | ||||
| @@ -60,7 +58,6 @@ def test_metadata(): | ||||
|     expect_metadata = True | ||||
|     content = spotdl.go_pafy(raw_song) | ||||
|     music_file = spotdl.misc.generate_filename(content.title) | ||||
|     music_file = spotdl.misc.fix_decoding(music_file) | ||||
|     meta_tags = spotdl.generate_metadata(raw_song) | ||||
|     output_song = music_file + spotdl.args.output_ext | ||||
|     metadata_output = spotdl.metadata.embed(output_song, meta_tags) | ||||
| @@ -73,8 +70,7 @@ def test_check_exists2(): | ||||
|     expect_check = True | ||||
|     content = spotdl.go_pafy(raw_song) | ||||
|     music_file = spotdl.misc.generate_filename(content.title) | ||||
|     music_file = spotdl.misc.fix_decoding(music_file) | ||||
|     input_song = music_file + spotdl.args.input_ext | ||||
|     os.remove('Music/' + spotdl.misc.fix_encoding(input_song)) | ||||
|     os.remove('Music/' + input_song) | ||||
|     check = spotdl.check_exists(music_file, raw_song, islist=True) | ||||
|     assert check == expect_check | ||||
|   | ||||
		Reference in New Issue
	
	Block a user