Beispiel #1
0
class PaginateTestCase(unittest.TestCase):
    def setUp(self):
        self.fm = LastFM()
        self.query = 'winter'

    def page(self, results):
        new_results = self.fm.next_page(results)
        self.assertTrue(results != None, "No results found for this query.")
        self.assertTrue(new_results != None,
                        "No results found for the second page of this query")
        self.assertTrue(
            results['results']['opensearch:startIndex'] !=
            new_results['results']['opensearch:startIndex'],
            "The page did not correctly increment.")
        prev_results = self.fm.prev_page(new_results)
        self.assertDictEqual(
            prev_results, results,
            "The previous results don't match the first results provided")

    def test_artist_page_results(self):
        self.page(self.fm.artist.search(artist=self.query))

    def test_album_page_results(self):
        self.page(self.fm.album.search(album=self.query))

    def test_track_page_results(self):
        self.page(self.fm.track.search(track=self.query))
Beispiel #2
0
 def __init__(self, username):
     super(LastFMTrackListener, self).__init__()
     self._lfm_user = username
     self._lfm = LastFM(self._lfm_user)
     self._last_playing_music = None
     self._lastfm_music_track_change()
     gobject.timeout_add(self.INTERVAL, self._lastfm_periodic_check)
Beispiel #3
0
def get_dataset():
    debug_print("Obtaining dataset...")
    # save time by loading any existing dataset
    if os.path.isfile(DATASET_FILENAME):
        dataset = json.load(open(DATASET_FILENAME))
        if len(dataset) == DATASET_SIZE:
            debug_print("Existing dataset found!")
            return dataset

    dataset = {}
    artists = set()

    # initialize LastFM API object and get artist list
    lastreq = LastFM()
    response = lastreq.get_artists(DATASET_SIZE)

    # initialize all artist tag sets
    for artist in response["artists"]["artist"]:
        dataset[artist["name"]] = set()

    # get tags for each artist
    count = 1
    for artist in dataset.keys():
        debug_print("Acquiring tags for artist " + str(count) + " of " +
                    str(DATASET_SIZE))
        response = lastreq.get_toptags(artist)
        for tag in response["toptags"]["tag"]:
            dataset[artist].add(tag["name"])
        count += 1

    # save the dataset, because it probably took a while to get
    debug_print("Dataset complete. Saving...")
    json.dump(dataset, open(DATASET_FILENAME, 'wb'), default=set_default)

    return dataset
Beispiel #4
0
def get_dataset():
  debug_print("Obtaining dataset...")
  # save time by loading any existing dataset
  if os.path.isfile(DATASET_FILENAME):
    dataset = json.load(open(DATASET_FILENAME))
    if len(dataset) == DATASET_SIZE:
      debug_print("Existing dataset found!")
      return dataset

  dataset = {}
  artists = set()

  # initialize LastFM API object and get artist list
  lastreq  = LastFM()
  response = lastreq.get_artists(DATASET_SIZE)

  # initialize all artist tag sets
  for artist in response["artists"]["artist"]:
    dataset[artist["name"]] = set()

  # get tags for each artist
  count = 1
  for artist in dataset.keys():
    debug_print("Acquiring tags for artist " + str(count) + " of " + str(DATASET_SIZE))
    response = lastreq.get_toptags(artist)
    for tag in response["toptags"]["tag"]:
      dataset[artist].add(tag["name"])
    count += 1

  # save the dataset, because it probably took a while to get
  debug_print("Dataset complete. Saving...")
  json.dump(dataset, open(DATASET_FILENAME, 'wb'), default=set_default)

  return dataset
Beispiel #5
0
 def __init__(self):
     self.__youtube = Youtube()
     self.__spotify = Spotify()
     self.__editor = TagEditor()
     self.__last = LastFM()
     self.__apple = AppleMusic()
     self.__deezer = Deezer()
Beispiel #6
0
 def __init__(self, metadatautils=None):
     '''Initialize - optionaly provide our base MetadataUtils class'''
     if not metadatautils:
         from metadatautils import MetadataUtils
         self.metadatautils = MetadataUtils
     else:
         self.metadatautils = metadatautils
     self.cache = self.metadatautils.cache
     self.lastfm = LastFM()
     self.mbrainz = MusicBrainz()
     self.audiodb = TheAudioDb()
    def OnScrobble(self, event):
        """Scrobbles using LastFM and sets a confirmation dialog"""

        try:
            lfm = LastFM()
            starttime = int(time.time())
            lfm.scrobble(self.artistText.GetValue(), self.titleText.GetValue(), starttime)
            wx.MessageBox("Scrobbled: {} - {}".format(
                self.artistText.GetValue(), self.titleText.GetValue()),
                    "Done", wx.OK)
            self.artistText.SetValue("")
            self.titleText.SetValue("")
        except lastfm.pylast.WSError as e:
            wx.MessageBox(str(e), 'Uh Oh', wx.OK | wx.ICON_ERROR)
class LastFMTrackListener(gobject.GObject):
	__gsignals__ = {
		'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, (object,)),
	}

	# polling period in milliseconds
	INTERVAL = 60000 #LastFM.MAX_DELAY * 250 # 1/4 of LastFM's delay (in s)

	_instance = None
	@classmethod
	def get(cls, username):
		if cls._instance is None:
			cls._instance = cls(username)
		else:
			cls._instance._lfm.setUsername(username)
		return cls._instance
	
	def __init__(self, username):
		super(LastFMTrackListener, self).__init__()
		self._lfm_user = username
		self._lfm = LastFM(self._lfm_user)
		self._last_playing_music = None
		self._lastfm_music_track_change()
		gobject.timeout_add(self.INTERVAL, self._lastfm_periodic_check)
		
	def _lastfm_properties_extract(self, song_tuple):
		if song_tuple:
			info = LastFMTrackInfo()
			info.title = song_tuple[LastFM.NAME]
			info.album = song_tuple[LastFM.ALBUM]
			info.artist = song_tuple[LastFM.ARTIST]
			return info
		return None

	def _lastfm_periodic_check(self):
		if self._lfm.updateData():
			self._lastfm_music_track_change()
		return True

	def _lastfm_music_track_change(self):
		info = self._lastfm_properties_extract(
			self._lfm.getLastRecentSong())
		self._last_playing_music = info
		self.emit('music-track-changed', info)

	def get_playing_track(self):
		'''Return a LastFMTrackInfo for the currently playing
		song, or None if no song is playing'''
		return self._last_playing_music
Beispiel #9
0
class LastFMTrackListener(gobject.GObject):
    __gsignals__ = {
        'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, (object, )),
    }

    # polling period in milliseconds
    INTERVAL = 60000  #LastFM.MAX_DELAY * 250 # 1/4 of LastFM's delay (in s)

    _instance = None

    @classmethod
    def get(cls, username):
        if cls._instance is None:
            cls._instance = cls(username)
        else:
            cls._instance._lfm.setUsername(username)
        return cls._instance

    def __init__(self, username):
        super(LastFMTrackListener, self).__init__()
        self._lfm_user = username
        self._lfm = LastFM(self._lfm_user)
        self._last_playing_music = None
        self._lastfm_music_track_change()
        gobject.timeout_add(self.INTERVAL, self._lastfm_periodic_check)

    def _lastfm_properties_extract(self, song_tuple):
        if song_tuple:
            info = LastFMTrackInfo()
            info.title = song_tuple[LastFM.NAME]
            info.album = song_tuple[LastFM.ALBUM]
            info.artist = song_tuple[LastFM.ARTIST]
            return info
        return None

    def _lastfm_periodic_check(self):
        if self._lfm.updateData():
            self._lastfm_music_track_change()
        return True

    def _lastfm_music_track_change(self):
        info = self._lastfm_properties_extract(self._lfm.getLastRecentSong())
        self._last_playing_music = info
        self.emit('music-track-changed', info)

    def get_playing_track(self):
        '''Return a LastFMTrackInfo for the currently playing
		song, or None if no song is playing'''
        return self._last_playing_music
Beispiel #10
0
class API(object):

    def __init__(self):
        self.mb = MusicBrainz()
        self.lastfm = LastFM()

    def search(self, query, query_type):
        results = self.mb.search(query, query_type)[query_type+'s']
        objects = []

        for result in results:
            try:
                Artist.objects.get(mbid=result['id'])
            except Artist.DoesNotExist:

                artist_info = self.lastfm.get_artist_by_mbid(result['id'])

                if 'artist' in artist_info:
                    Artist(
                        name=artist_info['artist']['name'],
                        description=artist_info['artist']['bio']['content'],
                        mbid=result['id']
                    ).save()

        return objects
	def __init__(self, username):
		super(LastFMTrackListener, self).__init__()
		self._lfm_user = username
		self._lfm = LastFM(self._lfm_user)
		self._last_playing_music = None
		self._lastfm_music_track_change()
		gobject.timeout_add(self.INTERVAL, self._lastfm_periodic_check)
    def OnScrobble(self, event):
        """Scrobbles using LastFM and sets a confirmation dialog"""

        try:
            lfm = LastFM()
            starttime = int(time.time())
            lfm.scrobble(self.artistText.GetValue(), self.titleText.GetValue(),
                         starttime)
            wx.MessageBox(
                "Scrobbled: {} - {}".format(self.artistText.GetValue(),
                                            self.titleText.GetValue()), "Done",
                wx.OK)
            self.artistText.SetValue("")
            self.titleText.SetValue("")
        except lastfm.pylast.WSError as e:
            wx.MessageBox(str(e), 'Uh Oh', wx.OK | wx.ICON_ERROR)
Beispiel #13
0
 def setUp(self):
     self.fm = LastFM()
     self.artist_name = "Wintersleep"
     self.artist_mbid = 'cda8e877-fe39-4939-8b09-045d68617367'
     self.track_name = "Jaws of Life"
     self.album_name = "Untitled"
     self.track_mbid = 'e0b110b4-fef4-473a-9c42-207d3c92cae0'
Beispiel #14
0
 def __init__(self):
     mixer.init()
     self._paused = False
     self.currentTrack = None
     self.last = LastFM()
     self.offset = 0
     self.playQueue = Queue.Queue(-1) # queue of 'infinite' size
     self.previous = [] #using a list as a stack to hold previous plays
Beispiel #15
0
 def __init__(self, metadatautils=None):
     '''Initialize - optionaly provide our base MetadataUtils class'''
     if not metadatautils:
         from metadatautils import MetadataUtils
         self.metadatautils = MetadataUtils
     else:
         self.metadatautils = metadatautils
     self.cache = self.metadatautils.cache
     self.lastfm = LastFM()
     self.mbrainz = MusicBrainz()
     self.audiodb = TheAudioDb()
Beispiel #16
0
    def search(self):
        self.albumBox.Clear()
        self.trackBox.Clear()
        try:
            lfm = LastFM()
            results = lfm.albumSearch(
                self.albumText.GetValue()).get_next_page()
            for result in results:
                self.albumBox.Append(
                    result.get_artist().name + " - " + result.get_title() +
                    " - " + result.get_release_date().split(',')[0], result)

            if len(results) == 0:
                wx.MessageBox(
                    "No matches found for {}".format(
                        self.albumText.GetValue()), 'Uh Oh',
                    wx.OK | wx.ICON_ERROR)
        except lastfm.pylast.WSError as e:
            wx.MessageBox(str(e), 'Uh Oh', wx.OK | wx.ICON_ERROR)
        except last.pylast.NetworkError as e:
            wx.MessageBox(str(e), 'Uh Oh', wx.OK | wx.ICON_ERROR)
Beispiel #17
0
 def onScrobbleAlbum(self, event):
     try:
         lfm = LastFM()
         selectedAlbum = self.albumBox.GetClientData(event.GetSelection())
         starttime = int(time.time()) - 90
         album = selectedAlbum.get_title()
         noTracks = 0
         for track in selectedAlbum.get_tracks():
             noTracks += 1
             starttime += 10
             artist = track.artist.name
             title = track.title
             lfm.scrobble(artist, title, starttime)
         #confirmation:
         wx.MessageBox(
             "Scrobbled: {} - {} ({} tracks).".format(
                 artist.encode('utf-8'), album.encode('utf-8'), noTracks),
             "Done", wx.OK)
     except lastfm.pylast.WSError as e:
         wx.MessageBox(str(e), 'Uh Oh', wx.OK | wx.ICON_ERROR)
     except wx._core.PyAssertionError:
         wx.MessageBox("Nothing selected to scrobble", 'Uh Oh',
                       wx.OK | wx.ICON_ERROR)
Beispiel #18
0
class API(object):
    def __init__(self):
        self.mb = MusicBrainz()
        self.lastfm = LastFM()

    def search(self, query, query_type):
        results = self.mb.search(query, query_type)[query_type + 's']
        objects = []

        for result in results:
            try:
                Artist.objects.get(mbid=result['id'])
            except Artist.DoesNotExist:

                artist_info = self.lastfm.get_artist_by_mbid(result['id'])

                if 'artist' in artist_info:
                    Artist(name=artist_info['artist']['name'],
                           description=artist_info['artist']['bio']['content'],
                           mbid=result['id']).save()

        return objects
Beispiel #19
0
class MusicDownloader(object):
    def __init__(self):
        self.__youtube = Youtube()
        self.__spotify = Spotify()
        self.__editor = TagEditor()
        self.__last = LastFM()
        self.__apple = AppleMusic()
        self.__deezer = Deezer()

    def __downloadMusicFromYoutube(self, name, uri, dur):

        #finding song on youtube
        self.__youtube.get(name, dur)

        #downloading video from youtube
        if self.__youtube.download(url=self.__youtube.getResult(),
                                   path=uri,
                                   filename=uri):
            #converting video to mp3 file
            self.__youtube.convertVideoToMusic(uri=uri)
            return True
        else:
            return False

    def __getSongInfoFromSpotify(self, uri):

        try:
            return self.__spotify.getSongInfo(uri)
        except:
            return None

    def getNameFromYoutube(self, url):
        return self.__youtube.getNameFromYoutube(url)

    def getData(self, uri):
        try:
            return self.__spotify.getSongInfo(uri)
        except:
            return None

    def getLastFMTags(self, name):
        return self.__last.get(name)

    def getYoutubeMusicInfo(self, url):
        return self.__youtube.getNameFromYoutube(url)

    def downloadBySpotifyUri(self, uri, path):

        #get info
        info = self.__getSongInfoFromSpotify(uri)

        if info:

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and download from YouTube and tagging
            if self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                               info['duration_ms']):

                self.__editor.setTags(data=info)

                cachepath = os.getcwd() + '/cache'
                fullpath = os.getcwd() + '/Downloads'

                if not os.path.exists(fullpath):
                    os.makedirs(fullpath)

                name = f'{info["artist"][0]} - {info["name"]}'

                os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                          f"{fullpath}/{getCorrect(name)}.mp3")

                print(path)

                if path:

                    os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                              f"{path}/{getCorrect(name)}.mp3")

                #deleting cache
                try:
                    shutil.rmtree(f"cache/{info['uri']}")
                except:
                    pass

                notify.send(f'{info["artist"][0]} - {info["name"]}')
                return True
        return False

    def downloadBySearchQuery(self, query, path=None):

        #get info
        info = self.__spotify.search(query=query)

        if not info:
            info = self.__last.get(query)

        if info:

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and download from YouTube and tagging
            self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                            info['duration_ms'])

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')
            return True, info
        else:
            return False, None

    def downloadBySpotifyUriFromFile(self, filename):
        try:

            with open(filename, 'r') as f:
                data = f.readlines()

        except FileNotFoundError:

            print(f'No such file or directory: "{filename}"')
            exit(2)

        #normalize
        try:
            data.remove('\n')
        except:
            pass
        links = [str(item).replace('\n', '') for item in data]

        for i, song in zip(range(len(links)), links):
            print(f'[{i+1}] - {song}')
            try:
                state = self.downloadBySpotifyUri(str(song).split(':')[-1])
                if not state:
                    notify.send(f'Failed to download', True)
            except:
                print('Something went wrong!')

    def downloadBySpotifyUriPlaylistMode(self, playlist_uri, path):

        user = Spotify.User()
        playlist = user.getPlaylistTracks(playlist_uri)

        for info, i in zip(playlist, range(len(playlist))):

            print(f'Downloading {i+1} of {len(playlist)}')

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and download from YouTube and tagging
            self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                            info['duration_ms'])

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')

    def downloadBySpotifyUriAlbumMode(self, album_uri, path):

        user = Spotify()
        playlist = user.getAlbum(album_uri)

        for info, i in zip(playlist['tracks'], range(len(playlist['tracks']))):

            print(f'Downloading {i+1} of {len(playlist["tracks"])}')

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and downloading from YouTube and tagging
            self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                            info['duration_ms'])

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')

    def downloadByDeezerUrl(self, url, path):

        link = str(str(url).split('/')[-1]).split('?')[0]

        #get info
        info = self.__deezer.getSongInfo(link)

        if info:

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and download from YouTube and tagging
            if self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                               info['duration_ms']):

                self.__editor.setTags(data=info)

                cachepath = os.getcwd() + '/cache'
                fullpath = os.getcwd() + '/Downloads'

                if not os.path.exists(fullpath):
                    os.makedirs(fullpath)

                name = f'{info["artist"][0]} - {info["name"]}'

                os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                          f"{fullpath}/{getCorrect(name)}.mp3")

                print(path)

                if path:

                    os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                              f"{path}/{getCorrect(name)}.mp3")

                #deleting cache
                try:
                    shutil.rmtree(f"cache/{info['uri']}")
                except:
                    pass

                notify.send(f'{info["artist"][0]} - {info["name"]}')
                return True
        return False

    def downloadByDeezerUrlAlbumMode(self, album_url, path):

        link = str(str(album_url).split('/')[-1]).split('?')[0]

        #get info
        playlist = self.__deezer.getAlbum(link)

        for info, i in zip(playlist['tracks'], range(len(playlist['tracks']))):

            print(f'Downloading {i+1} of {len(playlist["tracks"])}')

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and downloading from YouTube and tagging
            self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                            info['duration_ms'])

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')

    def downloadByDeezerUrlPlaylistMode(self, playlist_url, path):

        link = str(str(playlist_url).split('/')[-1]).split('?')[0]

        #get info
        playlist = self.__deezer.getPlaylist(link)

        for info, i in zip(playlist['tracks'], range(len(playlist['tracks']))):

            print(f'Downloading {i+1} of {len(playlist["tracks"])}')

            fixed_name = f'{info["artist"][0]} - {info["name"]}'
            fixed_name = fixed_name.replace('.', '')
            fixed_name = fixed_name.replace(',', '')
            fixed_name = fixed_name.replace("'", '')
            fixed_name = fixed_name.replace("/", "")

            #finding and download from YouTube and tagging
            self.__downloadMusicFromYoutube(fixed_name, info['uri'],
                                            info['duration_ms'])

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')

    def downloadFromYoutubeMusic(self, url, info, path):

        print(info)

        uri = info['uri']

        #downloading video from youtube
        if self.__youtube.download(url=url, path=uri, filename=uri):

            #converting video to mp3 file
            self.__youtube.convertVideoToMusic(uri=uri)

            self.__editor.setTags(data=info)

            cachepath = os.getcwd() + '/cache'
            fullpath = os.getcwd() + '/Downloads'

            if not os.path.exists(fullpath):
                os.makedirs(fullpath)

            name = f'{info["artist"][0]} - {info["name"]}'

            os.rename(f"{cachepath}/{info['uri']}/{info['uri']}.mp3",
                      f"{fullpath}/{getCorrect(name)}.mp3")

            if path:

                os.rename(f"{fullpath}/{getCorrect(name)}.mp3",
                          f"{path}/{getCorrect(name)}.mp3")

            #deleting cache
            try:
                shutil.rmtree(f"cache/{info['uri']}")
            except:
                pass

            notify.send(f'{info["artist"][0]} - {info["name"]}')
            return True, info
        else:
            return False, None

    def search(self, query):
        return self.__spotify.search(query=query)
Beispiel #20
0
 def setUp(self):
     self.fm = LastFM()
     self.artist_name = 'Wintersleep'
     self.album_name = "New Inheritors"
     self.album_mbid = '3f46329d-b15c-494b-912e-b802a5a8a3bb'
Beispiel #21
0
 def setUp(self):
     self.fm = LastFM()
     self.artist_name = 'Wintersleep'
     self.artist_mbid = 'cda8e877-fe39-4939-8b09-045d68617367'
Beispiel #22
0
import telebot
from lastfm import LastFM

TelegramBot = telebot.TeleBot('734127522:AAGBKswjLU9gXLmiEQVbee6D5_PAMJIDtLs')
LastFM = LastFM()


@TelegramBot.message_handler(content_types=['text'])
def get_text_messages(message):
    """
    Main function of bot, which reads messages and does various outputs, according to the input
    :param message:
    :return:
    """
    if message.text == '/help':
        TelegramBot.send_message(message.from_user.id,
                                 "/help - помощь. \n"
                                 " /artist_albums - показать топ альбомы артиста. \n "
                                 "/artist_tracks - показать треки артиста. \n "
                                 "/similar_tracks - показать похожие треки")
    else:
        if LastFM.state == 'state: home':
            if message.text == '/artist_albums':
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
                LastFM.state = 'state: /artist_albums. phase: get_artist'
            elif message.text == '/artist_tracks':
                LastFM.state = 'state: /artist_tracks. phase: get_artist'
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
            elif message.text == '/similar_tracks':
                LastFM.state = 'state: /similar_tracks. phase: get_artist'
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
Beispiel #23
0
def get_text_messages(message):
    """
    Main function of bot, which reads messages and does various outputs, according to the input
    :param message:
    :return:
    """
    if message.text == '/help':
        TelegramBot.send_message(message.from_user.id,
                                 "/help - помощь. \n"
                                 " /artist_albums - показать топ альбомы артиста. \n "
                                 "/artist_tracks - показать треки артиста. \n "
                                 "/similar_tracks - показать похожие треки")
    else:
        if LastFM.state == 'state: home':
            if message.text == '/artist_albums':
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
                LastFM.state = 'state: /artist_albums. phase: get_artist'
            elif message.text == '/artist_tracks':
                LastFM.state = 'state: /artist_tracks. phase: get_artist'
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
            elif message.text == '/similar_tracks':
                LastFM.state = 'state: /similar_tracks. phase: get_artist'
                TelegramBot.send_message(message.from_user.id, "Напиши артиста")
            else:
                TelegramBot.send_message(message.from_user.id, "Напиши /help.")
        elif LastFM.state == 'state: /artist_albums. phase: get_artist':
            LastFM.artist = message.text
            LastFM.state = 'state: /artist_albums. phase: get_num'
            TelegramBot.send_message(message.from_user.id, "Напиши сколько вывести альбомов")
        elif LastFM.state == 'state: /artist_albums. phase: get_num':
            try:
                LastFM.num = int(message.text)
                data_sender(message, LastFM.artist_albums(LastFM.artist, LastFM.num))
            except Exception:
                TelegramBot.send_message(message.from_user.id, 'Error')
            LastFM.state = 'state: home'
        elif LastFM.state == 'state: /artist_tracks. phase: get_artist':
            LastFM.artist = message.text
            LastFM.state = 'state: /artist_tracks. phase: get_num'
            TelegramBot.send_message(message.from_user.id, "Напиши сколько вывести треков")
        elif LastFM.state == 'state: /artist_tracks. phase: get_num':
            try:
                LastFM.num = int(message.text)
                data_sender(message, LastFM.artist_tracks(LastFM.artist, LastFM.num))
            except Exception:
                TelegramBot.send_message(message.from_user.id, 'Error')
            LastFM.state = 'state: home'
        elif LastFM.state == 'state: /similar_tracks. phase: get_artist':
            LastFM.artist = message.text
            LastFM.state = 'state: /similar_tracks. phase: get_track'
            TelegramBot.send_message(message.from_user.id, "Напиши трек")
        elif LastFM.state == 'state: /similar_tracks. phase: get_track':
            LastFM.track = message.text
            LastFM.state = 'state: /similar_tracks. phase: get_num'
            TelegramBot.send_message(message.from_user.id, "Напиши сколько")
        elif LastFM.state == 'state: /similar_tracks. phase: get_num':
            try:
                LastFM.num = int(message.text)
                data_sender(message, LastFM.artist_tracks(LastFM.artist, LastFM.num))
            except Exception:
                TelegramBot.send_message(message.from_user.id, 'Error')
            LastFM.state = 'state: home'
Beispiel #24
0
class MusicArtwork(object):
    '''get metadata and artwork for music'''

    def __init__(self, metadatautils=None):
        '''Initialize - optionaly provide our base MetadataUtils class'''
        if not metadatautils:
            from metadatautils import MetadataUtils
            self.metadatautils = MetadataUtils
        else:
            self.metadatautils = metadatautils
        self.cache = self.metadatautils.cache
        self.lastfm = LastFM()
        self.mbrainz = MusicBrainz()
        self.audiodb = TheAudioDb()

    def get_music_artwork(self, artist, album, track, disc, ignore_cache=False, flush_cache=False, manual=False):
        '''
            get music metadata by providing artist and/or album/track
            returns combined result of artist and album metadata
        '''
        if artist == track or album == track:
            track = ""
        artists = self.get_all_artists(artist, track)
        album = self.get_clean_title(album)
        track = self.get_clean_title(track)

        # retrieve artist and album details
        artist_details = self.get_artists_metadata(artists, album, track,
                                                   ignore_cache=ignore_cache, flush_cache=flush_cache, manual=manual)
        album_artist = artist_details.get("albumartist", artists[0])
        if album or track:
            album_details = self.get_album_metadata(album_artist, album, track, disc,
                                                    ignore_cache=ignore_cache, flush_cache=flush_cache, manual=manual)
        else:
            album_details = {"art": {}}

        # combine artist details and album details
        details = extend_dict(album_details, artist_details)

        # combine artist plot and album plot as extended plot
        if artist_details.get("plot") and album_details.get("plot"):
            details["extendedplot"] = "%s  --  %s" % (album_details["plot"], artist_details["plot"])
        else:
            details["extendedplot"] = details.get("plot", "")

        # append track title to results
        if track:
            details["title"] = track

        # return the endresult
        return details

    def music_artwork_options(self, artist, album, track, disc):
        '''show options for music artwork'''
        options = []
        options.append(self.metadatautils.addon.getLocalizedString(32028))  # Refresh item (auto lookup)
        options.append(self.metadatautils.addon.getLocalizedString(32036))  # Choose art
        options.append(self.metadatautils.addon.getLocalizedString(32034))  # Open addon settings
        header = self.metadatautils.addon.getLocalizedString(32015)
        dialog = xbmcgui.Dialog()
        ret = dialog.select(header, options)
        del dialog
        if ret == 0:
            # Refresh item (auto lookup)
            self.get_music_artwork(artist, album, track, disc, ignore_cache=True)
        elif ret == 1:
            # Choose art
            self.get_music_artwork(artist, album, track, disc, ignore_cache=True, manual=True)
        elif ret == 2:
            # Open addon settings
            xbmc.executebuiltin("Addon.OpenSettings(%s)" % ADDON_ID)

    def get_artists_metadata(self, artists, album, track, ignore_cache=False, flush_cache=False, manual=False):
        '''collect artist metadata for all artists'''
        artist_details = {"art": {}}
        # for multi artist songs/albums we grab details from all artists
        if len(artists) == 1:
            # single artist
            artist_details = self.get_artist_metadata(
                artists[0], album, track, ignore_cache=ignore_cache, flush_cache=flush_cache, manual=manual)
            artist_details["albumartist"] = artists[0]
        else:
            # multi-artist track
            # The first artist with details is considered the main artist
            # all others are assumed as featuring artists
            artist_details = {"art": {}}
            feat_artist_details = []
            for artist in artists:
                if not (artist_details.get("plot") or artist_details.get("art")):
                    # get main artist details
                    artist_details["albumartist"] = artist
                    artist_details = self.get_artist_metadata(
                        artist, album, track, ignore_cache=ignore_cache, manual=manual)
                else:
                    # assume featuring artist
                    feat_artist_details.append(self.get_artist_metadata(
                        artist, album, track, ignore_cache=ignore_cache, manual=manual))

            # combined images to use as multiimage (for all artists)
            # append featuring artist details
            for arttype in ["banners", "fanarts", "clearlogos", "thumbs"]:
                combined_art = []
                for artist_item in [artist_details] + feat_artist_details:
                    art = artist_item["art"].get(arttype, [])
                    if isinstance(art, list):
                        for item in art:
                            if item not in combined_art:
                                combined_art.append(item)
                    else:
                        for item in self.metadatautils.kodidb.files(art):
                            if item["file"] not in combined_art:
                                combined_art.append(item["file"])
                if combined_art:
                    # use the extrafanart plugin entry to display multi images
                    artist_details["art"][arttype] = "plugin://script.skin.helper.service/"\
                        "?action=extrafanart&fanarts=%s" % quote_plus(repr(combined_art))
                    # also set extrafanart path
                    if arttype == "fanarts":
                        artist_details["art"]["extrafanart"] = artist_details["art"][arttype]
        # return the result
        return artist_details

    # pylint: disable-msg=too-many-local-variables
    def get_artist_metadata(self, artist, album, track, ignore_cache=False, flush_cache=False, manual=False):
        '''collect artist metadata for given artist'''
        details = {"art": {}}
        cache_str = "music_artwork.artist.%s" % artist.lower()
        # retrieve details from cache
        cache = self.metadatautils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(self.get_artist_kodi_metadata(artist), cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "artist")
        else:
            # nothing in cache - start metadata retrieval
            log_msg("get_artist_metadata --> artist: %s - album: %s - track: %s" % (artist, album, track))
            details["cachestr"] = cache_str
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(details, self.get_artist_kodi_metadata(artist))
            # get artwork from songlevel path
            if details.get("diskpath") and self.metadatautils.addon.getSetting("music_art_musicfolders") == "true":
                details["art"] = extend_dict(details["art"], self.lookup_artistart_in_folder(details["diskpath"]))
                local_path = details["diskpath"]
            # get artwork from custom folder
            if self.metadatautils.addon.getSetting("music_art_custom") == "true":
                custom_path = self.metadatautils.addon.getSetting("music_art_custom_path").decode("utf-8")
                if custom_path:
                    diskpath = self.get_customfolder_path(custom_path, artist)
                    log_msg("custom path on disk for artist: %s --> %s" % (artist, diskpath))
                    if diskpath:
                        details["art"] = extend_dict(details["art"], self.lookup_artistart_in_folder(diskpath))
                        local_path_custom = diskpath
                        details["customartpath"] = diskpath
            # lookup online metadata
            if self.metadatautils.addon.getSetting("music_art_scraper") == "true":
                if not album and not track:
                    album = details.get("ref_album")
                    track = details.get("ref_track")
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_artistid = details.get("musicbrainzartistid", self.get_mb_artist_id(artist, album, track))
                details["musicbrainzartistid"] = mb_artistid
                if mb_artistid:
                    # get artwork from fanarttv
                    if self.metadatautils.addon.getSetting("music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(details["art"], self.metadatautils.fanarttv.artist(mb_artistid))
                    # get metadata from theaudiodb
                    if self.metadatautils.addon.getSetting("music_art_scraper_adb") == "true":
                        details = extend_dict(details, self.audiodb.artist_info(mb_artistid))
                    # get metadata from lastfm
                    if self.metadatautils.addon.getSetting("music_art_scraper_lfm") == "true":
                        details = extend_dict(details, self.lastfm.artist_info(mb_artistid))
                    # download artwork to music folder
                    if local_path and self.metadatautils.addon.getSetting("music_art_download") == "true":
                        details["art"] = download_artwork(local_path, details["art"])
                    # download artwork to custom folder
                    if local_path_custom and self.metadatautils.addon.getSetting("music_art_download_custom") == "true":
                        details["art"] = download_artwork(local_path_custom, details["art"])
                    # fix extrafanart
                    if details["art"].get("fanarts"):
                        for count, item in enumerate(details["art"]["fanarts"]):
                            details["art"]["fanart.%s" % count] = item
                        if not details["art"].get("extrafanart") and len(details["art"]["fanarts"]) > 1:
                            details["art"]["extrafanart"] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(details["art"]["fanarts"]))
                    # multi-image path for all images for each arttype
                    for arttype in ["banners", "clearlogos", "thumbs"]:
                        art = details["art"].get(arttype, [])
                        if len(art) > 1:
                            # use the extrafanart plugin entry to display multi images
                            details["art"][arttype] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(art))
        # set default details
        if not details.get("artist"):
            details["artist"] = artist
        if details["art"].get("thumb"):
            details["art"]["artistthumb"] = details["art"]["thumb"]

        # always store results in cache and return results
        self.metadatautils.cache.set(cache_str, details)
        return details

    def get_album_metadata(self, artist, album, track, disc, ignore_cache=False, flush_cache=False, manual=False):
        '''collect all album metadata'''
        cache_str = "music_artwork.album.%s.%s.%s" % (artist.lower(), album.lower(), disc.lower())
        if not album:
            cache_str = "music_artwork.album.%s.%s" % (artist.lower(), track.lower())
        details = {"art": {}}
        details["cachestr"] = cache_str

        # retrieve details from cache
        cache = self.metadatautils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(self.get_album_kodi_metadata(artist, album, track, disc), cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "album")
        else:
            # nothing in cache - start metadata retrieval
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(details, self.get_album_kodi_metadata(artist, album, track, disc))
            # get artwork from songlevel path
            if details.get("diskpath") and self.metadatautils.addon.getSetting("music_art_musicfolders") == "true":
                details["art"] = extend_dict(details["art"], self.lookup_albumart_in_folder(details["diskpath"]))
                local_path = details["diskpath"]
            # get artwork from custom folder
            if self.metadatautils.addon.getSetting("music_art_custom") == "true":
                custom_path = self.metadatautils.addon.getSetting("music_art_custom_path").decode("utf-8")
                if custom_path:
                    diskpath = self.get_custom_album_path(custom_path, artist, album, disc)
                    if diskpath:
                        details["art"] = extend_dict(details["art"], self.lookup_albumart_in_folder(diskpath))
                        local_path_custom = diskpath
                        details["customartpath"] = diskpath
            # lookup online metadata
            if self.metadatautils.addon.getSetting("music_art_scraper") == "true":
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_albumid = details.get("musicbrainzalbumid")
                if not mb_albumid:
                    mb_albumid = self.get_mb_album_id(artist, album, track)
                if mb_albumid:
                    # get artwork from fanarttv
                    if self.metadatautils.addon.getSetting("music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(details["art"], self.metadatautils.fanarttv.album(mb_albumid))
                    # get metadata from theaudiodb
                    if self.metadatautils.addon.getSetting("music_art_scraper_adb") == "true":
                        details = extend_dict(details, self.audiodb.album_info(mb_albumid))
                    # get metadata from lastfm
                    if self.metadatautils.addon.getSetting("music_art_scraper_lfm") == "true":
                        details = extend_dict(details, self.lastfm.album_info(mb_albumid))
                    # metadata from musicbrainz
                    if not details.get("year") or not details.get("genre"):
                        details = extend_dict(details, self.mbrainz.get_albuminfo(mb_albumid))
                    # musicbrainz thumb as last resort
                    if not details["art"].get("thumb"):
                        details["art"]["thumb"] = self.mbrainz.get_albumthumb(mb_albumid)
                    # download artwork to music folder
                    if local_path and self.metadatautils.addon.getSetting("music_art_download") == "true":
                        details["art"] = download_artwork(local_path, details["art"])
                    # download artwork to custom folder
                    if local_path_custom and self.metadatautils.addon.getSetting("music_art_download_custom") == "true":
                        details["art"] = download_artwork(local_path_custom, details["art"])
        # set default details
        if not details.get("album") and details.get("title"):
            details["album"] = details["title"]
        if details["art"].get("thumb"):
            details["art"]["albumthumb"] = details["art"]["thumb"]

        # store results in cache and return results
        self.metadatautils.cache.set(cache_str, details)
        return details

    # pylint: enable-msg=too-many-local-variables

    def get_artist_kodi_metadata(self, artist):
        '''get artist details from the kodi database'''
        details = {}
        filters = [{"operator": "is", "field": "artist", "value": artist}]
        result = self.metadatautils.kodidb.artists(filters=filters, limits=(0, 1))
        if result:
            details = result[0]
            details["title"] = details["artist"]
            details["plot"] = strip_newlines(details["description"])
            if details["musicbrainzartistid"] and isinstance(details["musicbrainzartistid"], list):
                details["musicbrainzartistid"] = details["musicbrainzartistid"][0]
            filters = [{"artistid": details["artistid"]}]
            artist_albums = self.metadatautils.kodidb.albums(filters=filters)
            details["albums"] = []
            details["albumsartist"] = []
            details["albumscompilations"] = []
            details["tracks"] = []
            bullet = "•".decode("utf-8")
            details["albums.formatted"] = u""
            details["tracks.formatted"] = u""
            details["tracks.formatted2"] = u""
            details["albumsartist.formatted"] = u""
            details["albumscompilations.formatted"] = u""
            # enumerate albums for this artist
            for artist_album in artist_albums:
                details["albums"].append(artist_album["label"])
                details["albums.formatted"] += u"%s %s [CR]" % (bullet, artist_album["label"])
                if artist in artist_album["displayartist"]:
                    details["albumsartist"].append(artist_album["label"])
                    details["albumsartist.formatted"] += u"%s %s [CR]" % (bullet, artist_album["label"])
                else:
                    details["albumscompilations"].append(artist_album["label"])
                    details["albumscompilations.formatted"] += u"%s %s [CR]" % (bullet, artist_album["label"])
                # enumerate songs for this album
                filters = [{"albumid": artist_album["albumid"]}]
                album_tracks = self.metadatautils.kodidb.songs(filters=filters)
                if album_tracks:
                    # retrieve path on disk by selecting one song for this artist
                    if not details.get("ref_track") and not len(artist_album["artistid"]) > 1:
                        song_path = album_tracks[0]["file"]
                        details["diskpath"] = self.get_artistpath_by_songpath(song_path, artist)
                        details["ref_album"] = artist_album["title"]
                        details["ref_track"] = album_tracks[0]["title"]
                    for album_track in album_tracks:
                        details["tracks"].append(album_track["title"])
                        tr_title = album_track["title"]
                        if album_track["track"]:
                            tr_title = "%s. %s" % (album_track["track"], album_track["title"])
                        details["tracks.formatted"] += u"%s %s [CR]" % (bullet, tr_title)
                        duration = album_track["duration"]
                        total_seconds = int(duration)
                        minutes = total_seconds / 60
                        seconds = total_seconds - (minutes * 60)
                        duration = "%s:%s" % (minutes, str(seconds).zfill(2))
                        details["tracks.formatted2"] += u"%s %s (%s)[CR]" % (bullet, tr_title, duration)
            details["albumcount"] = len(details["albums"])
            details["albumsartistcount"] = len(details["albumsartist"])
            details["albumscompilationscount"] = len(details["albumscompilations"])
            # do not retrieve artwork from item as there's no way to write it back
            # and it will already be retrieved if user enables to get the artwork from the song path
        return details

    def get_album_kodi_metadata(self, artist, album, track, disc):
        '''get album details from the kodi database'''
        details = {}
        filters = [{"operator": "contains", "field": "artist", "value": artist}]
        if artist and track and not album:
            # get album by track
            filters.append({"operator": "contains", "field": "title", "value": track})
            result = self.metadatautils.kodidb.songs(filters=filters)
            for item in result:
                album = item["album"]
                break
        if artist and album:
            filters.append({"operator": "contains", "field": "album", "value": album})
            result = self.metadatautils.kodidb.albums(filters=filters)
            if result:
                details = result[0]
                details["plot"] = strip_newlines(details["description"])
                filters = [{"albumid": details["albumid"]}]
                album_tracks = self.metadatautils.kodidb.songs(filters=filters)
                details["tracks"] = []
                bullet = "•".decode("utf-8")
                details["tracks.formatted"] = u""
                details["tracks.formatted2"] = ""
                details["runtime"] = 0
                for item in album_tracks:
                    details["tracks"].append(item["title"])
                    details["tracks.formatted"] += u"%s %s [CR]" % (bullet, item["title"])
                    duration = item["duration"]
                    total_seconds = int(duration)
                    minutes = total_seconds / 60
                    seconds = total_seconds - (minutes * 60)
                    duration = "%s:%s" % (minutes, str(seconds).zfill(2))
                    details["runtime"] += item["duration"]
                    details["tracks.formatted2"] += u"%s %s (%s)[CR]" % (bullet, item["title"], duration)
                    if not details.get("diskpath"):
                        if not disc or item["disc"] == int(disc):
                            details["diskpath"] = self.get_albumpath_by_songpath(item["file"])
                details["art"] = {}
                details["songcount"] = len(album_tracks)
                # get album total duration pretty printed as mm:ss
                total_seconds = int(details["runtime"])
                minutes = total_seconds / 60
                seconds = total_seconds - (minutes * 60)
                details["duration"] = "%s:%s" % (minutes, str(seconds).zfill(2))
                # do not retrieve artwork from item as there's no way to write it back
                # and it will already be retrieved if user enables to get the artwork from the song path
        return details

    def get_mb_artist_id(self, artist, album, track):
        '''lookup musicbrainz artist id with query of artist and album/track'''
        artistid = self.mbrainz.get_artist_id(artist, album, track)
        if not artistid and self.metadatautils.addon.getSetting("music_art_scraper_lfm") == "true":
            artistid = self.lastfm.get_artist_id(artist, album, track)
        if not artistid and self.metadatautils.addon.getSetting("music_art_scraper_adb") == "true":
            artistid = self.audiodb.get_artist_id(artist, album, track)
        return artistid

    def get_mb_album_id(self, artist, album, track):
        '''lookup musicbrainz album id with query of artist and album/track'''
        albumid = self.mbrainz.get_album_id(artist, album, track)
        if not albumid and self.metadatautils.addon.getSetting("music_art_scraper_lfm") == "true":
            albumid = self.lastfm.get_album_id(artist, album, track)
        if not albumid and self.metadatautils.addon.getSetting("music_art_scraper_adb") == "true":
            albumid = self.audiodb.get_album_id(artist, album, track)
        return albumid

    def manual_set_music_artwork(self, details, mediatype):
        '''manual override artwork options'''
        from utils import manual_set_artwork
        if mediatype == "artist" and "artist" in details:
            header = "%s: %s" % (xbmc.getLocalizedString(13511), details["artist"])
        else:
            header = "%s: %s" % (xbmc.getLocalizedString(13511), xbmc.getLocalizedString(558))
        changemade, artwork = manual_set_artwork(details["art"], mediatype, header)
        # save results if any changes made
        if changemade:
            details["art"] = artwork
            refresh_needed = False
            download_art = self.metadatautils.addon.getSetting("music_art_download") == "true"
            download_art_custom = self.metadatautils.addon.getSetting("music_art_download_custom") == "true"
            # download artwork to music folder if needed
            if details.get("diskpath") and download_art:
                details["art"] = download_artwork(details["diskpath"], details["art"])
                refresh_needed = True
            # download artwork to custom folder if needed
            if details.get("customartpath") and download_art_custom:
                details["art"] = download_artwork(details["customartpath"], details["art"])
                refresh_needed = True
            # reload skin to make sure new artwork is visible
            if refresh_needed:
                xbmc.sleep(500)
                xbmc.executebuiltin("ReloadSkin()")
        # return endresult
        return details

    @staticmethod
    def get_artistpath_by_songpath(songpath, artist):
        '''get the artist path on disk by listing the song's path'''
        result = ""
        if "\\" in songpath:
            delim = "\\"
        else:
            delim = "/"
        # just move up the directory tree (max 3 levels) untill we find the directory
        for trypath in [songpath.rsplit(delim, 2)[0] + delim,
                        songpath.rsplit(delim, 3)[0] + delim, songpath.rsplit(delim, 1)[0] + delim]:
            if trypath.split(delim)[-2].lower() == artist.lower():
                result = trypath
                break
        return result

    @staticmethod
    def get_albumpath_by_songpath(songpath):
        '''get the album path on disk by listing the song's path'''
        if "\\" in songpath:
            delim = "\\"
        else:
            delim = "/"
        return songpath.rsplit(delim, 1)[0] + delim

    @staticmethod
    def lookup_artistart_in_folder(folderpath):
        '''lookup artwork in given folder'''
        artwork = {}
        files = xbmcvfs.listdir(folderpath)[1]
        for item in files:
            item = item.decode("utf-8")
            if item in ["banner.jpg", "clearart.png", "poster.png", "fanart.jpg", "landscape.jpg"]:
                key = item.split(".")[0]
                artwork[key] = folderpath + item
            elif item == "logo.png":
                artwork["clearlogo"] = folderpath + item
            elif item == "folder.jpg":
                artwork["thumb"] = folderpath + item
        # extrafanarts
        efa_path = folderpath + "extrafanart/"
        if xbmcvfs.exists(efa_path):
            files = xbmcvfs.listdir(efa_path)[1]
            artwork["fanarts"] = []
            if files:
                artwork["extrafanart"] = efa_path
                for item in files:
                    item = efa_path + item.decode("utf-8")
                    artwork["fanarts"].append(item)
        return artwork

    @staticmethod
    def lookup_albumart_in_folder(folderpath):
        '''lookup artwork in given folder'''
        artwork = {}
        files = xbmcvfs.listdir(folderpath)[1]
        for item in files:
            item = item.decode("utf-8")
            if item in ["cdart.png", "disc.png"]:
                artwork["discart"] = folderpath + item
            if item == "thumbback.jpg":
                artwork["thumbback"] = folderpath + item
            if item == "spine.jpg":
                artwork["spine"] = folderpath + item
            elif item == "folder.jpg":
                artwork["thumb"] = folderpath + item
        return artwork

    def get_custom_album_path(self, custom_path, artist, album, disc):
        '''try to locate the custom path for the album'''
        artist_path = self.get_customfolder_path(custom_path, artist)
        album_path = ""
        if artist_path:
            album_path = self.get_customfolder_path(artist_path, album)
            if album_path and disc:
                if "\\" in album_path:
                    delim = "\\"
                else:
                    delim = "/"
                dirs = xbmcvfs.listdir(album_path)[0]
                for directory in dirs:
                    directory = directory.decode("utf-8")
                    if disc in directory:
                        return os.path.join(album_path, directory) + delim
        return album_path

    def get_customfolder_path(self, customfolder, foldername, sublevel=False):
        '''search recursively (max 2 levels) for a specific folder'''
        cachestr = "customfolder_path.%s.%s" % (customfolder, foldername)
        folder_path = self.cache.get(cachestr)
        if not folder_path:
            if "\\" in customfolder:
                delim = "\\"
            else:
                delim = "/"
            dirs = xbmcvfs.listdir(customfolder)[0]
            for strictness in [1, 0.95, 0.9, 0.8]:
                for directory in dirs:
                    directory = directory.decode("utf-8")
                    curpath = os.path.join(customfolder, directory) + delim
                    match = SM(None, foldername.lower(), directory.lower()).ratio()
                    if match >= strictness:
                        folder_path = curpath
                    elif not sublevel:
                        # check if our requested path is in a sublevel of the current path
                        # restrict the number of sublevels to just one for now for performance reasons
                        folder_path = self.get_customfolder_path(curpath, foldername, True)
                    if folder_path:
                        break
                if folder_path:
                    break
            if not sublevel:
                self.cache.set(cachestr, folder_path)
        return folder_path

    @staticmethod
    def get_clean_title(title):
        '''strip all unwanted characters from track name'''
        title = title.split("/")[0]
        title = title.split("(")[0]
        title = title.split("[")[0]
        title = title.split("ft.")[0]
        title = title.split("Ft.")[0]
        title = title.split("Feat.")[0]
        title = title.split("Featuring")[0]
        title = title.split("featuring")[0]
        return title.strip()

    @staticmethod
    def get_all_artists(artist, track):
        '''extract multiple artists from both artist and track string'''
        artists = []
        feat_artists = []

        # fix for band names which actually contain the kodi splitter (slash) in their name...
        specials = ["AC/DC"]  # to be completed with more artists
        for special in specials:
            if special in artist:
                artist = artist.replace(special, special.replace("/", ""))

        for splitter in ["ft.", "feat.", "featuring", "Ft.", "Feat.", "Featuring"]:
            # replace splitter by kodi default splitter for easier split all later
            artist = artist.replace(splitter, u"/")

            # extract any featuring artists from trackname
            if splitter in track:
                track_parts = track.split(splitter)
                if len(track_parts) > 1:
                    feat_artist = track_parts[1].replace(")", "").replace("(", "").strip()
                    feat_artists.append(feat_artist)

        # break all artists string into list
        all_artists = artist.split("/") + feat_artists
        for item in all_artists:
            item = item.strip()
            if item not in artists:
                artists.append(item)
            # & can be a both a splitter or part of artist name
            for item2 in item.split("&"):
                item2 = item2.strip()
                if item2 not in artists:
                    artists.append(item2)
        return artists
Beispiel #25
0
 def __init__(self):
     self.mb = MusicBrainz()
     self.lastfm = LastFM()
Beispiel #26
0
class MusicArtwork(object):
    '''get metadata and artwork for music'''
    def __init__(self, metadatautils=None):
        '''Initialize - optionaly provide our base MetadataUtils class'''
        if not metadatautils:
            from metadatautils import MetadataUtils
            self.metadatautils = MetadataUtils
        else:
            self.metadatautils = metadatautils
        self.cache = self.metadatautils.cache
        self.lastfm = LastFM()
        self.mbrainz = MusicBrainz()
        self.audiodb = TheAudioDb()

    def get_music_artwork(self,
                          artist,
                          album,
                          track,
                          disc,
                          ignore_cache=False,
                          flush_cache=False,
                          manual=False):
        '''
            get music metadata by providing artist and/or album/track
            returns combined result of artist and album metadata
        '''
        if artist == track or album == track:
            track = ""
        artists = self.get_all_artists(artist, track)
        album = self.get_clean_title(album)
        track = self.get_clean_title(track)

        # retrieve artist and album details
        artist_details = self.get_artists_metadata(artists,
                                                   album,
                                                   track,
                                                   ignore_cache=ignore_cache,
                                                   flush_cache=flush_cache,
                                                   manual=manual)
        album_artist = artist_details.get("albumartist", artist)
        if album or track:
            album_details = self.get_album_metadata(album_artist,
                                                    album,
                                                    track,
                                                    disc,
                                                    ignore_cache=ignore_cache,
                                                    flush_cache=flush_cache,
                                                    manual=manual)
        else:
            album_details = {"art": {}}

        # combine artist details and album details
        details = extend_dict(album_details, artist_details)

        # combine artist plot and album plot as extended plot
        if artist_details.get("plot") and album_details.get("plot"):
            details["extendedplot"] = "%s  --  %s" % (album_details["plot"],
                                                      artist_details["plot"])
        else:
            details["extendedplot"] = details.get("plot", "")

        # append track title to results
        if track:
            details["title"] = track

        # return the endresult
        return details

    def music_artwork_options(self, artist, album, track, disc):
        '''show options for music artwork'''
        options = []
        options.append(self.metadatautils.addon.getLocalizedString(
            32028))  # Refresh item (auto lookup)
        options.append(
            self.metadatautils.addon.getLocalizedString(32036))  # Choose art
        options.append(self.metadatautils.addon.getLocalizedString(
            32034))  # Open addon settings
        header = self.metadatautils.addon.getLocalizedString(32015)
        dialog = xbmcgui.Dialog()
        ret = dialog.select(header, options)
        del dialog
        if ret == 0:
            # Refresh item (auto lookup)
            self.get_music_artwork(artist,
                                   album,
                                   track,
                                   disc,
                                   ignore_cache=True)
        elif ret == 1:
            # Choose art
            self.get_music_artwork(artist,
                                   album,
                                   track,
                                   disc,
                                   ignore_cache=True,
                                   manual=True)
        elif ret == 2:
            # Open addon settings
            xbmc.executebuiltin("Addon.OpenSettings(%s)" % ADDON_ID)

    def get_artists_metadata(self,
                             artists,
                             album,
                             track,
                             ignore_cache=False,
                             flush_cache=False,
                             manual=False):
        '''collect artist metadata for all artists'''
        artist_details = {"art": {}}
        # for multi artist songs/albums we grab details from all artists
        if len(artists) == 1:
            # single artist
            artist_details = self.get_artist_metadata(
                artists[0],
                album,
                track,
                ignore_cache=ignore_cache,
                flush_cache=flush_cache,
                manual=manual)
            artist_details["albumartist"] = artists[0]
        else:
            # multi-artist track
            # The first artist with details is considered the main artist
            # all others are assumed as featuring artists
            artist_details = {"art": {}}
            feat_artist_details = {"art": {}}
            for artist in artists:
                if not (artist_details.get("plot")
                        or artist_details.get("art")):
                    # get main artist details
                    artist_details["albumartist"] = artist
                    artist_details = self.get_artist_metadata(
                        artist,
                        album,
                        track,
                        ignore_cache=ignore_cache,
                        manual=manual)
                else:
                    # assume featuring artist
                    feat_artist_details = extend_dict(
                        feat_artist_details,
                        self.get_artist_metadata(artist,
                                                 album,
                                                 track,
                                                 ignore_cache=ignore_cache,
                                                 manual=manual))

            # combined images to use as multiimage (for all artists)
            # append featuring artist details
            for arttype in ["banners", "fanarts", "clearlogos", "thumbs"]:
                art = artist_details["art"].get(arttype, [])
                art += feat_artist_details["art"].get(arttype, [])
                if art:
                    # use the extrafanart plugin entry to display multi images
                    artist_details["art"][arttype] = "plugin://script.skin.helper.service/"\
                        "?action=extrafanart&fanarts=%s" % quote_plus(repr(art))
                    # also set extrafanart path
                    if arttype == "fanarts":
                        artist_details["art"]["extrafanart"] = artist_details[
                            "art"][arttype]
        # return the result
        return artist_details

    # pylint: disable-msg=too-many-local-variables
    def get_artist_metadata(self,
                            artist,
                            album,
                            track,
                            ignore_cache=False,
                            flush_cache=False,
                            manual=False):
        '''collect artist metadata for given artist'''
        details = {"art": {}}
        cache_str = "music_artwork.artist.%s" % artist.lower()
        # retrieve details from cache
        cache = self.metadatautils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(self.get_artist_kodi_metadata(artist), cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "artist")
        else:
            # nothing in cache - start metadata retrieval
            log_msg(
                "get_artist_metadata --> artist: %s - album: %s - track: %s" %
                (artist, album, track))
            details["cachestr"] = cache_str
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(details,
                                  self.get_artist_kodi_metadata(artist))
            # get artwork from songlevel path
            if details.get("diskpath") and self.metadatautils.addon.getSetting(
                    "music_art_musicfolders") == "true":
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_artistart_in_folder(details["diskpath"]))
                local_path = details["diskpath"]
            # get artwork from custom folder
            if self.metadatautils.addon.getSetting(
                    "music_art_custom") == "true":
                custom_path = self.metadatautils.addon.getSetting(
                    "music_art_custom_path").decode("utf-8")
                if custom_path:
                    diskpath = self.get_customfolder_path(custom_path, artist)
                    log_msg("custom path on disk for artist: %s --> %s" %
                            (artist, diskpath))
                    if diskpath:
                        details["art"] = extend_dict(
                            details["art"],
                            self.lookup_artistart_in_folder(diskpath))
                        local_path_custom = diskpath
                        details["customartpath"] = diskpath
            # lookup online metadata
            if self.metadatautils.addon.getSetting(
                    "music_art_scraper") == "true":
                if not album and not track:
                    album = details.get("ref_album")
                    track = details.get("ref_track")
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_artistid = details.get(
                    "musicbrainzartistid",
                    self.get_mb_artist_id(artist, album, track))
                details["musicbrainzartistid"] = mb_artistid
                if mb_artistid:
                    # get artwork from fanarttv
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(
                            details["art"],
                            self.metadatautils.fanarttv.artist(mb_artistid))
                    # get metadata from theaudiodb
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_adb") == "true":
                        details = extend_dict(
                            details, self.audiodb.artist_info(mb_artistid))
                    # get metadata from lastfm
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_lfm") == "true":
                        details = extend_dict(
                            details, self.lastfm.artist_info(mb_artistid))
                    # download artwork to music folder
                    if local_path and self.metadatautils.addon.getSetting(
                            "music_art_download") == "true":
                        details["art"] = download_artwork(
                            local_path, details["art"])
                    # download artwork to custom folder
                    if local_path_custom and self.metadatautils.addon.getSetting(
                            "music_art_download_custom") == "true":
                        details["art"] = download_artwork(
                            local_path_custom, details["art"])
                    # fix extrafanart
                    if details["art"].get("fanarts"):
                        for count, item in enumerate(
                                details["art"]["fanarts"]):
                            details["art"]["fanart.%s" % count] = item
                        if not details["art"].get("extrafanart") and len(
                                details["art"]["fanarts"]) > 1:
                            details["art"]["extrafanart"] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(details["art"]["fanarts"]))
                    # multi-image path for all images for each arttype
                    for arttype in ["banners", "clearlogos", "thumbs"]:
                        art = details["art"].get(arttype, [])
                        if len(art) > 1:
                            # use the extrafanart plugin entry to display multi images
                            details["art"][arttype] = "plugin://script.skin.helper.service/"\
                                "?action=extrafanart&fanarts=%s" % quote_plus(repr(art))
        # set default details
        if not details.get("artist"):
            details["artist"] = artist
        if details["art"].get("thumb"):
            details["art"]["artistthumb"] = details["art"]["thumb"]

        # always store results in cache and return results
        self.metadatautils.cache.set(cache_str, details)
        return details

    def get_album_metadata(self,
                           artist,
                           album,
                           track,
                           disc,
                           ignore_cache=False,
                           flush_cache=False,
                           manual=False):
        '''collect all album metadata'''
        cache_str = "music_artwork.album.%s.%s.%s" % (
            artist.lower(), album.lower(), disc.lower())
        if not album:
            cache_str = "music_artwork.album.%s.%s" % (artist.lower(),
                                                       track.lower())
        details = {"art": {}}
        details["cachestr"] = cache_str

        # retrieve details from cache
        cache = self.metadatautils.cache.get(cache_str)
        if not cache and flush_cache:
            # nothing to do - just return empty results
            return details
        elif cache and flush_cache:
            # only update kodi metadata for updated counts etc
            details = extend_dict(
                self.get_album_kodi_metadata(artist, album, track, disc),
                cache)
        elif cache and not ignore_cache:
            # we have a valid cache - return that
            details = cache
        elif cache and manual:
            # user wants to manually override the artwork in the cache
            details = self.manual_set_music_artwork(cache, "album")
        else:
            # nothing in cache - start metadata retrieval
            local_path = ""
            local_path_custom = ""
            # get metadata from kodi db
            details = extend_dict(
                details,
                self.get_album_kodi_metadata(artist, album, track, disc))
            # get artwork from songlevel path
            if details.get("diskpath") and self.metadatautils.addon.getSetting(
                    "music_art_musicfolders") == "true":
                details["art"] = extend_dict(
                    details["art"],
                    self.lookup_albumart_in_folder(details["diskpath"]))
                local_path = details["diskpath"]
            # get artwork from custom folder
            if self.metadatautils.addon.getSetting(
                    "music_art_custom") == "true":
                custom_path = self.metadatautils.addon.getSetting(
                    "music_art_custom_path").decode("utf-8")
                if custom_path:
                    diskpath = self.get_custom_album_path(
                        custom_path, artist, album, disc)
                    if diskpath:
                        details["art"] = extend_dict(
                            details["art"],
                            self.lookup_albumart_in_folder(diskpath))
                        local_path_custom = diskpath
                        details["customartpath"] = diskpath
            # lookup online metadata
            if self.metadatautils.addon.getSetting(
                    "music_art_scraper") == "true":
                # prefer the musicbrainzid that is already in the kodi database - only perform lookup if missing
                mb_albumid = details.get("musicbrainzalbumid")
                if not mb_albumid:
                    mb_albumid = self.get_mb_album_id(artist, album, track)
                if mb_albumid:
                    # get artwork from fanarttv
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_fatv") == "true":
                        details["art"] = extend_dict(
                            details["art"],
                            self.metadatautils.fanarttv.album(mb_albumid))
                    # get metadata from theaudiodb
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_adb") == "true":
                        details = extend_dict(
                            details, self.audiodb.album_info(mb_albumid))
                    # get metadata from lastfm
                    if self.metadatautils.addon.getSetting(
                            "music_art_scraper_lfm") == "true":
                        details = extend_dict(
                            details, self.lastfm.album_info(mb_albumid))
                    # metadata from musicbrainz
                    if not details.get("year") or not details.get("genre"):
                        details = extend_dict(
                            details, self.mbrainz.get_albuminfo(mb_albumid))
                    # musicbrainz thumb as last resort
                    if not details["art"].get("thumb"):
                        details["art"]["thumb"] = self.mbrainz.get_albumthumb(
                            mb_albumid)
                    # download artwork to music folder
                    if local_path and self.metadatautils.addon.getSetting(
                            "music_art_download") == "true":
                        details["art"] = download_artwork(
                            local_path, details["art"])
                    # download artwork to custom folder
                    if local_path_custom and self.metadatautils.addon.getSetting(
                            "music_art_download_custom") == "true":
                        details["art"] = download_artwork(
                            local_path_custom, details["art"])
        # set default details
        if not details.get("album") and details.get("title"):
            details["album"] = details["title"]
        if details["art"].get("thumb"):
            details["art"]["albumthumb"] = details["art"]["thumb"]

        # store results in cache and return results
        self.metadatautils.cache.set(cache_str, details)
        return details

    # pylint: enable-msg=too-many-local-variables

    def get_artist_kodi_metadata(self, artist):
        '''get artist details from the kodi database'''
        details = {}
        filters = [{"operator": "is", "field": "artist", "value": artist}]
        result = self.metadatautils.kodidb.artists(filters=filters,
                                                   limits=(0, 1))
        if result:
            details = result[0]
            details["title"] = details["artist"]
            details["plot"] = strip_newlines(details["description"])
            if details["musicbrainzartistid"] and isinstance(
                    details["musicbrainzartistid"], list):
                details["musicbrainzartistid"] = details[
                    "musicbrainzartistid"][0]
            filters = [{"artistid": details["artistid"]}]
            artist_albums = self.metadatautils.kodidb.albums(filters=filters)
            details["albums"] = []
            details["albumsartist"] = []
            details["albumscompilations"] = []
            details["tracks"] = []
            bullet = "•".decode("utf-8")
            details["albums.formatted"] = u""
            details["tracks.formatted"] = u""
            details["tracks.formatted2"] = u""
            details["albumsartist.formatted"] = u""
            details["albumscompilations.formatted"] = u""
            # enumerate albums for this artist
            for artist_album in artist_albums:
                details["albums"].append(artist_album["label"])
                details["albums.formatted"] += u"%s %s [CR]" % (
                    bullet, artist_album["label"])
                if artist in artist_album["displayartist"]:
                    details["albumsartist"].append(artist_album["label"])
                    details["albumsartist.formatted"] += u"%s %s [CR]" % (
                        bullet, artist_album["label"])
                else:
                    details["albumscompilations"].append(artist_album["label"])
                    details[
                        "albumscompilations.formatted"] += u"%s %s [CR]" % (
                            bullet, artist_album["label"])
                # enumerate songs for this album
                filters = [{"albumid": artist_album["albumid"]}]
                album_tracks = self.metadatautils.kodidb.songs(filters=filters)
                if album_tracks:
                    # retrieve path on disk by selecting one song for this artist
                    if not details.get("ref_track") and not len(
                            artist_album["artistid"]) > 1:
                        song_path = album_tracks[0]["file"]
                        details["diskpath"] = self.get_artistpath_by_songpath(
                            song_path, artist)
                        details["ref_album"] = artist_album["title"]
                        details["ref_track"] = album_tracks[0]["title"]
                    for album_track in album_tracks:
                        details["tracks"].append(album_track["title"])
                        tr_title = album_track["title"]
                        if album_track["track"]:
                            tr_title = "%s. %s" % (album_track["track"],
                                                   album_track["title"])
                        details["tracks.formatted"] += u"%s %s [CR]" % (
                            bullet, tr_title)
                        duration = album_track["duration"]
                        total_seconds = int(duration)
                        minutes = total_seconds / 60
                        seconds = total_seconds - (minutes * 60)
                        duration = "%s:%s" % (minutes, str(seconds).zfill(2))
                        details["tracks.formatted2"] += u"%s %s (%s)[CR]" % (
                            bullet, tr_title, duration)
            details["albumcount"] = len(details["albums"])
            details["albumsartistcount"] = len(details["albumsartist"])
            details["albumscompilationscount"] = len(
                details["albumscompilations"])
            # do not retrieve artwork from item as there's no way to write it back
            # and it will already be retrieved if user enables to get the artwork from the song path
        return details

    def get_album_kodi_metadata(self, artist, album, track, disc):
        '''get album details from the kodi database'''
        details = {}
        filters = [{"operator": "is", "field": "album", "value": album}]
        filters.append({"operator": "is", "field": "artist", "value": artist})
        if artist and track and not album:
            # get album by track
            result = self.metadatautils.kodidb.songs(filters=filters)
            for item in result:
                album = item["album"]
                break
        if artist and album:
            result = self.metadatautils.kodidb.albums(filters=filters)
            if result:
                details = result[0]
                details["plot"] = strip_newlines(details["description"])
                filters = [{"albumid": details["albumid"]}]
                album_tracks = self.metadatautils.kodidb.songs(filters=filters)
                details["tracks"] = []
                bullet = "•".decode("utf-8")
                details["tracks.formatted"] = u""
                details["tracks.formatted2"] = ""
                details["runtime"] = 0
                for item in album_tracks:
                    details["tracks"].append(item["title"])
                    details["tracks.formatted"] += u"%s %s [CR]" % (
                        bullet, item["title"])
                    duration = item["duration"]
                    total_seconds = int(duration)
                    minutes = total_seconds / 60
                    seconds = total_seconds - (minutes * 60)
                    duration = "%s:%s" % (minutes, str(seconds).zfill(2))
                    details["runtime"] += item["duration"]
                    details["tracks.formatted2"] += u"%s %s (%s)[CR]" % (
                        bullet, item["title"], duration)
                    if not details.get("diskpath"):
                        if not disc or item["disc"] == int(disc):
                            details[
                                "diskpath"] = self.get_albumpath_by_songpath(
                                    item["file"])
                details["art"] = {}
                details["songcount"] = len(album_tracks)
                # get album total duration pretty printed as mm:ss
                total_seconds = int(details["runtime"])
                minutes = total_seconds / 60
                seconds = total_seconds - (minutes * 60)
                details["duration"] = "%s:%s" % (minutes,
                                                 str(seconds).zfill(2))
                # do not retrieve artwork from item as there's no way to write it back
                # and it will already be retrieved if user enables to get the artwork from the song path
        return details

    def get_mb_artist_id(self, artist, album, track):
        '''lookup musicbrainz artist id with query of artist and album/track'''
        artistid = self.mbrainz.get_artist_id(artist, album, track)
        if not artistid and self.metadatautils.addon.getSetting(
                "music_art_scraper_lfm") == "true":
            artistid = self.lastfm.get_artist_id(artist, album, track)
        if not artistid and self.metadatautils.addon.getSetting(
                "music_art_scraper_adb") == "true":
            artistid = self.audiodb.get_artist_id(artist, album, track)
        return artistid

    def get_mb_album_id(self, artist, album, track):
        '''lookup musicbrainz album id with query of artist and album/track'''
        albumid = self.mbrainz.get_album_id(artist, album, track)
        if not albumid and self.metadatautils.addon.getSetting(
                "music_art_scraper_lfm") == "true":
            albumid = self.lastfm.get_album_id(artist, album, track)
        if not albumid and self.metadatautils.addon.getSetting(
                "music_art_scraper_adb") == "true":
            albumid = self.audiodb.get_album_id(artist, album, track)
        return albumid

    def manual_set_music_artwork(self, details, mediatype):
        '''manual override artwork options'''
        from utils import manual_set_artwork
        if mediatype == "artist" and "artist" in details:
            header = "%s: %s" % (xbmc.getLocalizedString(13511),
                                 details["artist"])
        else:
            header = "%s: %s" % (xbmc.getLocalizedString(13511),
                                 xbmc.getLocalizedString(558))
        changemade, artwork = manual_set_artwork(details["art"], mediatype,
                                                 header)
        # save results if any changes made
        if changemade:
            details["art"] = artwork
            refresh_needed = False
            download_art = self.metadatautils.addon.getSetting(
                "music_art_download") == "true"
            download_art_custom = self.metadatautils.addon.getSetting(
                "music_art_download_custom") == "true"
            # download artwork to music folder if needed
            if details.get("diskpath") and download_art:
                details["art"] = download_artwork(details["diskpath"],
                                                  details["art"])
                refresh_needed = True
            # download artwork to custom folder if needed
            if details.get("customartpath") and download_art_custom:
                details["art"] = download_artwork(details["customartpath"],
                                                  details["art"])
                refresh_needed = True
            # reload skin to make sure new artwork is visible
            if refresh_needed:
                xbmc.sleep(500)
                xbmc.executebuiltin("ReloadSkin()")
        # return endresult
        return details

    @staticmethod
    def get_artistpath_by_songpath(songpath, artist):
        '''get the artist path on disk by listing the song's path'''
        result = ""
        if "\\" in songpath:
            delim = "\\"
        else:
            delim = "/"
        # just move up the directory tree (max 3 levels) untill we find the directory
        for trypath in [
                songpath.rsplit(delim, 2)[0] + delim,
                songpath.rsplit(delim, 3)[0] + delim,
                songpath.rsplit(delim, 1)[0] + delim
        ]:
            if trypath.split(delim)[-2].lower() == artist.lower():
                result = trypath
                break
        return result

    @staticmethod
    def get_albumpath_by_songpath(songpath):
        '''get the album path on disk by listing the song's path'''
        if "\\" in songpath:
            delim = "\\"
        else:
            delim = "/"
        return songpath.rsplit(delim, 1)[0] + delim

    @staticmethod
    def lookup_artistart_in_folder(folderpath):
        '''lookup artwork in given folder'''
        artwork = {}
        files = xbmcvfs.listdir(folderpath)[1]
        for item in files:
            item = item.decode("utf-8")
            if item in [
                    "banner.jpg", "clearart.png", "poster.png", "fanart.jpg",
                    "landscape.jpg"
            ]:
                key = item.split(".")[0]
                artwork[key] = folderpath + item
            elif item == "logo.png":
                artwork["clearlogo"] = folderpath + item
            elif item == "folder.jpg":
                artwork["thumb"] = folderpath + item
        # extrafanarts
        efa_path = folderpath + "extrafanart/"
        if xbmcvfs.exists(efa_path):
            files = xbmcvfs.listdir(efa_path)[1]
            artwork["fanarts"] = []
            if files:
                artwork["extrafanart"] = efa_path
                for item in files:
                    item = efa_path + item.decode("utf-8")
                    artwork["fanarts"].append(item)
        return artwork

    @staticmethod
    def lookup_albumart_in_folder(folderpath):
        '''lookup artwork in given folder'''
        artwork = {}
        files = xbmcvfs.listdir(folderpath)[1]
        for item in files:
            item = item.decode("utf-8")
            if item in ["cdart.png", "disc.png"]:
                artwork["discart"] = folderpath + item
            elif item == "folder.jpg":
                artwork["thumb"] = folderpath + item
        return artwork

    def get_custom_album_path(self, custom_path, artist, album, disc):
        '''try to locate the custom path for the album'''
        artist_path = self.get_customfolder_path(custom_path, artist)
        album_path = ""
        if artist_path:
            album_path = self.get_customfolder_path(artist_path, album)
            if album_path and disc:
                if "\\" in album_path:
                    delim = "\\"
                else:
                    delim = "/"
                dirs = xbmcvfs.listdir(album_path)[0]
                for directory in dirs:
                    directory = directory.decode("utf-8")
                    if disc in directory:
                        return os.path.join(album_path, directory) + delim
        return album_path

    def get_customfolder_path(self, customfolder, foldername, sublevel=False):
        '''search recursively (max 2 levels) for a specific folder'''
        cachestr = "customfolder_path.%s.%s" % (customfolder, foldername)
        folder_path = self.cache.get(cachestr)
        if not folder_path:
            if "\\" in customfolder:
                delim = "\\"
            else:
                delim = "/"
            dirs = xbmcvfs.listdir(customfolder)[0]
            for strictness in [1, 0.95, 0.9, 0.8]:
                for directory in dirs:
                    directory = directory.decode("utf-8")
                    curpath = os.path.join(customfolder, directory) + delim
                    match = SM(None, foldername.lower(),
                               directory.lower()).ratio()
                    if match >= strictness:
                        folder_path = curpath
                    elif not sublevel:
                        # check if our requested path is in a sublevel of the current path
                        # restrict the number of sublevels to just one for now for performance reasons
                        folder_path = self.get_customfolder_path(
                            curpath, foldername, True)
                    if folder_path:
                        break
                if folder_path:
                    break
            if not sublevel:
                self.cache.set(cachestr, folder_path)
        return folder_path

    @staticmethod
    def get_clean_title(title):
        '''strip all unwanted characters from track name'''
        title = title.split("/")[0]
        title = title.split("(")[0]
        title = title.split("[")[0]
        title = title.split("ft.")[0]
        title = title.split("Ft.")[0]
        title = title.split("Feat.")[0]
        title = title.split("Featuring")[0]
        title = title.split("featuring")[0]
        return title.strip()

    @staticmethod
    def get_all_artists(artist, track):
        '''extract multiple artists from both artist and track string'''
        artists = []
        feat_artists = []

        # fix for band names which actually contain the kodi splitter (slash) in their name...
        specials = ["AC/DC"]  # to be completed with more artists
        for special in specials:
            if special in artist:
                artist = artist.replace(special, special.replace("/", ""))

        for splitter in [
                "ft.", "feat.", "featuring", "Ft.", "Feat.", "Featuring"
        ]:
            # replace splitter by kodi default splitter for easier split all later
            artist = artist.replace(splitter, u"/")

            # extract any featuring artists from trackname
            if splitter in track:
                track_parts = track.split(splitter)
                if len(track_parts) > 1:
                    feat_artist = track_parts[1].replace(")", "").replace(
                        "(", "").strip()
                    feat_artists.append(feat_artist)

        # break all artists string into list
        all_artists = artist.split("/") + feat_artists
        for item in all_artists:
            item = item.strip()
            if item not in artists:
                artists.append(item)
            # & can be a both a splitter or part of artist name
            for item2 in item.split("&"):
                item2 = item2.strip()
                if item2 not in artists:
                    artists.append(item2)
        return artists
Beispiel #27
0
 def setUp(self):
     self.fm = LastFM()
     self.query = 'winter'
Beispiel #28
0

def writeRawData(data, page):
    track_file = 'db/tracks-%05d.db' % page
    with open(track_file, 'w') as db:
        pickle.dump(data, db)
        db.close()
    registerLastPage(page)


def itertracks(tracks):
    return (t for t in tracks.findall('recenttracks/track') if t.get('nowplaying') is None)


if __name__ == '__main__':
    service = LastFM('7cc9edbf1289e55d01f6d0b6a6fd159b', 'lsdr')
    starting_page = startingPage(service)

    for page in reversed(range(starting_page)):
        print 'processing page %s now...' % str(page)
        tracks = service.fetch('user.getrecenttracks', limit='200', page=str(page))
        data   = [extractTrackData(t) for t in itertracks(tracks)]
        # print data

        writeRawData(data, page)


'''
# Tratando o UTS timestamp
__timestamp_tuple = time.gmtime(float(UTS))
__timestamp = time.time.asctime(__timestamp_tuple)
Beispiel #29
0
 def __init__(self):
     self.mb = MusicBrainz()
     self.lastfm = LastFM()
Beispiel #30
0
class MusicPlayer(object):
    """the music playing class."""
    def __init__(self):
        mixer.init()
        self._paused = False
        self.currentTrack = None
        self.last = LastFM()
        self.offset = 0
        self.playQueue = Queue.Queue(-1) # queue of 'infinite' size
        self.previous = [] #using a list as a stack to hold previous plays

    @property
    def paused(self):
        """Boolean, for determining if the music is paused"""
        return self._paused
    @paused.setter
    def paused(self, value):
        self._paused = value

    @property
    def scrobblingEnabled(self):
        """Boolean, for determining if scrobbling is Enabled"""
        return self._scrobblingEnabled
    @scrobblingEnabled.setter
    def scrobblingEnabled(self, value):
        self._scrobblingEnabled = value

    def update(self):
        #if the playback is over half way (last.fm regulation) then scrobble it
        if self.currentTrack != None and mixer.music.get_pos() / 1000  >= self.currentTrack.length/2:
            if not self.currentTrack.scrobbled:
                self.last.scrobble(self.currentTrack.artist, self.currentTrack.title, self.currentTrack.time)
                self.currentTrack.scrobbled = True
        """Checks if the playing track is over and if so, changes it. returns changed if the track has changed"""
        if self.currentTrack != None and (mixer.music.get_pos() / 1000 ) >= self.currentTrack.length:
            self.setNext()
            return 'changed'

    def setNext(self, event=None):
        if not self.playQueue.empty():
            if self.currentTrack != None:
                self.previous.append(self.currentTrack.path)

            trackname = self.playQueue.get()
            self.currentTrack = Track(trackname)
            mixer.music.load(trackname)
            self.offset = 0
            self.play()

    def setPrevious(self, event=None):
        if len(self.previous) > 0:
            trackname = self.previous.pop()
            self.currentTrack = Track(trackname)
            mixer.music.load(trackname)
            self.play()

    def play(self):
        try:
            if self.currentTrack != None:
                if not self.paused:
                    mixer.music.play()
                else:
                    mixer.music.unpause()
                    self._paused = False
                self.last.nowPlaying(self.currentTrack.artist, self.currentTrack.title)
            else:
                raise Exception("No track loaded")

        except pygame.error as error:
             raise error

    def pause(self):
        if mixer.music.get_busy() and not self.paused:
         mixer.music.pause()
         self._paused = True

    def stop(self):
        mixer.music.stop()

    def seek(self, position):
        if self.currentTrack != None:
            self.stop()
            self.offset = position
            pygame.mixer.music.play(0, position)

    def setVolume(self, vol):
        mixer.music.set_volume(vol)

    def load(self, toLoad):
        if not self.playQueue.empty():
            self.playQueue = Queue.Queue(-1)#empty the queue

        if isinstance(toLoad, basestring): #checking if a string or a list
            toLoad = toLoad.encode('utf-8')
            print toLoad

            if os.path.isdir(toLoad): # we've been given a directory
                os.chdir(toLoad)
                for track in glob.glob('*.mp3'):
                    print track
                    self.playQueue.put(track)

            elif os.path.isfile(toLoad): #a file from the dirctrl
                self.playQueue.put(toLoad)

        else: # a list from the file -> open dialogue
            for track in toLoad:
                track = track.encode('utf-8')
                self.playQueue.put(track)

        self.setNext()

    def getPos(self):
        return  mixer.music.get_pos() + self.offset

    def quit(self):
        pygame.quit()