diff --git a/r&d/spotify_search.py b/r&d/spotify_search.py new file mode 100644 index 0000000..56ee21c --- /dev/null +++ b/r&d/spotify_search.py @@ -0,0 +1,104 @@ +import re + +import spotipy +from spotipy.oauth2 import SpotifyClientCredentials + + +CLIENT_ID = 'e4198f6a3f7b48029366f22528b5dc66' +CLIENT_SECRET = 'ba057d0621a5496bbb64edccf758bde5' + + +class SpotifySearcher: + """Searches spotify for song, album, and playlist metadata.""" + + def authorize(self, client_id=None, client_secret=None): + """Authorizes this class with spotify using client ids + :rtype: returns self class + """ + + if not client_id: + client_id = 'e4198f6a3f7b48029366f22528b5dc66' + if not client_secret: + client_secret = 'ba057d0621a5496bbb64edccf758bde5' + + try: + creds = SpotifyClientCredentials(client_id, client_secret) + self.authorized = True + self.spotify = spotipy.Spotify(client_credentials_manager=creds) + except Exception: + self.authorized = False + self.spotify = spotipy.Spotify() + + return self + + def find_song(self, song_title, artist_name, limit=50, offset=0): + """Searches spotify for a song and grabs its metadata + :param song_title: a string, the title of the song you're looking for + :param artist_name: a string, the artist of the above song + :rtype: a dictionary of metadata about the song + """ + songs = self.spotify.search(q=song_title, type="track")["tracks"] + + for song in songs["items"]: + if _simplify(song_title) in _simplify(song["name"]) and \ + _simplify(artist_name) in _simplify(song["artists"][0]["name"]): + return song + + if songs['next']: + return self.find_song(song_title, artist_name, + offset=offset + limit) + else: + print("There were no songs found by that name with that artist") + + def find_album(self, album_title, artist_name=None, limit=50, offset=0): + """Searches spotify for an album and grabs its contents and metadata + :param album_title: a string, the title of the album + :param artist_name: a string, the name of the artist of the album + :rtype: a dictionary of metadata about the album + """ + query = album_title + if artist_name: + query += " " + artist_name + albums = self.spotify.search(q=query, type="album")['albums'] + + for album in albums['items']: + if _simplify(album_title) in _simplify(album["name"]): + return self.spotify.album(album['uri']) + + if albums['next']: + return self.find_album(album_title, artist_name, + offset=offset + limit) + else: + print("There were no albums found by that name with that artist") + + def find_playlist(self, playlist_title, username, limit=50, offset=0): + """Searches spotify for a playlist and grabs its contents and metadata + :param playlist_title: a string, the title of the playlist + :param username: a string, the username of the playlist creator/owner + :rtype: a dictionary of metadata about the playlist + """ + playlists = [] + playlists = self.spotify.user_playlists(username, limit, offset) + + for playlist in playlists['items']: + print(playlist['name']) + if _simplify(playlist_title) in _simplify(playlist['name']): + return self.spotify.user_playlist(username, playlist['id']) + + if playlists['next']: + return self.find_playlist(playlist_title, username, + offset=offset + limit) + else: + print("There were no playlists by that name found.") + + +def _simplify(string): + """Lowercases and strips all non alphanumeric characters from the string + :param string: a string to be modified + :rtype: the modified string + """ + if type(string) == bytes: + string = string.decode() + return re.sub(r'[^a-zA-Z0-9]+', '', string.lower()) + +print((SpotifySearcher().authorize().find_song("Bohemian Rhapsody", "Queenn"))) \ No newline at end of file diff --git a/r&d/tagger.py b/r&d/tagger.py new file mode 100644 index 0000000..c19ac7b --- /dev/null +++ b/r&d/tagger.py @@ -0,0 +1,67 @@ +import sys + +if sys.version_info[0] >= 3: + from urllib.request import urlopen +elif sys.version_info[0] < 3: + from urllib import quote_plus, quote + from urllib import urlopen + +from mutagen.mp3 import EasyMP3 +from mutagen.easyid3 import EasyID3, EasyID3KeyError +from mutagen.id3 import APIC, ID3 + + +class Tagger: + """Attaches ID3 tags to MP3 files.""" + + def __init__(self, location): + """Initializes the class and generates ID3 tags for the mp3 + :param location: a string, the location of the mp3 that you want ID3 + tags on + """ + EasyID3.RegisterTextKey("comment", "COMM") + self.location = location + self.mp3 = EasyID3(self.location) + + def add_tag(self, tag, data): + """Adds a tag to the mp3 file you specified in __init__ and saves it + :param tag: a string, the name of the tag you want to add to the mp3 + valid tag names: + "title", "artist", "album", "genre", "tracknumber" (string), + "discnumber" (string), + "compilation" ("1" for true, "" for false) + :param data: a string, the data that you want to attach to the mp3 + under the specified tag name + """ + # For valid tags: `EasyID3.valid_keys.keys()` + self.mp3[tag] = data + self.mp3.save() + + def read_tag(self, tag): + """Tries to read a tag from the initialized mp3 file + :param tag: a string, the name of the tag you want to read + :rtype: an array with a string inside. The string inside the array is + the data you're requesting. If there's no tag associated or no data + attached with your requested tag, a blank array will be returned. + """ + try: + return self.mp3[tag] + except EasyID3KeyError or KeyError: + return [] + + def add_album_art(self, image_url): + """Adds album art to the initialized mp3 file + :param image_url: a string, the url of the image you want to attach to + the mp3 + """ + mp3 = EasyMP3(self.location, ID3=ID3) + mp3.tags.add( + APIC( + encoding = 3, + mime = 'image/png', + type = 3, + desc = 'cover', + data = urlopen(image_url).read() + ) + ) + mp3.save() \ No newline at end of file diff --git a/r&d/youtube_search.py b/r&d/youtube_search.py index 5401f9d..1037827 100644 --- a/r&d/youtube_search.py +++ b/r&d/youtube_search.py @@ -121,7 +121,9 @@ def _simplify(string): :param string: a string to be modified :rtype: the modified string """ - return re.sub(r'[^a-zA-Z0-9]+', '', string) + if type(string) == bytes: + string = string.decode() + return re.sub(r'[^a-zA-Z0-9]+', '', string.lower()) def _count_garbage_phrases(video_title, song_title):