def get_station_tracks(self,
                           station_id,
                           num_tracks=25,
                           recently_played_ids=None):
        _cache = utils.get_cache_dir(['station-ids'])
        station_ids_cache = os.path.join(_cache, '%s.json' % station_id)

        if not recently_played_ids:
            if os.path.exists(station_ids_cache):
                with open(station_ids_cache, 'r') as f:
                    try:
                        recently_played_ids = json.loads(f.read())

                    except ValueError:
                        pass

        tracks = super(GMusic,
                       self).get_station_tracks(station_id, num_tracks,
                                                recently_played_ids)

        track_ids = []
        with open(station_ids_cache, 'w+') as f:
            for track in tracks:
                if 'trackId' in track:
                    track_ids.append(track['trackId'])

                elif 'storeId' in track:
                    track_ids.append(track['storeId'])

            f.write(json.dumps(track_ids))

        return tracks
    def get_my_library_artists(self, from_cache=True):
        _cache = os.path.join(utils.get_cache_dir(['library']), 'artists.json')

        artists = []
        if os.path.exists(_cache) and from_cache:
            with open(_cache, 'r') as f:
                artists = json.loads(f.read())
        else:
            songs = self.get_my_library_songs()
            songs = self._uniquify(songs, 'albumArtist')

            for song in songs:
                if ('artistId' not in song or 'title' not in song):
                    utils.log('Skipping broken entry:',
                              json.dumps(song),
                              lvl=xbmc.LOGERROR)
                    continue

                _art = thumbs.IMG_ARTIST
                if 'artistArtRef' in song and len(song['artistArtRef']) > 0:
                    _art = song['artistArtRef'][0]['url']

                artist = {
                    'artistId': song['artistId'][0],
                    'name': song['albumArtist'],
                    'artistArtRef': _art
                }

                artists.append(artist)

            artists = sorted(artists, key=itemgetter('name'))
            with open(_cache, 'w+') as f:
                f.write(json.dumps(artists))

        return artists
    def get_artist_info(self,
                        artist_id,
                        include_albums=True,
                        max_top_tracks=5,
                        max_rel_artist=5,
                        from_cache=False):
        # If a user uploaded a song where google can't match a artist,
        # an artistId does NOT exist.
        # Therefore we generate our own id in `get_my_library_songs`.
        # A call to googles backend will obviously return nothing
        # so we handle this case beforehand
        #
        # Note: Google artistIds always start with a capital A
        if not artist_id.startswith('A'):
            return []

        artist = None
        artists_cache = os.path.join(utils.get_cache_dir(['artists']),
                                     artist_id)

        if os.path.exists(artists_cache) and from_cache:
            with open(artists_cache, 'r') as f:
                try:
                    artist = json.loads(f.read())

                except:
                    pass

        if not artist:
            artist = super(GMusic,
                           self).get_artist_info(artist_id, include_albums,
                                                 max_top_tracks,
                                                 max_rel_artist)

        return artist
    def get_my_library_song_details(self, track_id):
        _cache = utils.get_cache_dir(['library', 'songs'])
        _cache = os.path.join(_cache, track_id)

        track = None
        if os.path.exists(_cache):
            with open(_cache, 'r') as f:
                track = json.loads(f.read())

        return track
    def get_station_categories(self, from_cache=True):
        _cache = os.path.join(utils.get_cache_dir(), 'station_categories.json')

        resp = None
        if os.path.exists(_cache) and from_cache:
            with open(_cache, 'r') as f:
                resp = json.loads(f.read())
        else:
            resp = self._make_call(mobileclient.GetStationCategories)

            with open(_cache, 'w+') as f:
                f.write(json.dumps(resp))

        return resp['root']['subcategories']
예제 #6
0
def _get_track_details(track_id, store_id=None):
    cache = os.path.join(utils.get_cache_dir(['tracks']), track_id)

    if os.path.exists(cache):
        with open(cache, 'r') as f:
            track = json.loads(f.read())

    elif store_id:
        try:
            track = GMUSIC.get_track_info(store_track_id=track_id)

        except Exception:
            pass

    else:
        track = None

    return track
    def search(self, query=None, cached=False, max_results=50):
        """Queries Google Music for content.

        Args:
            query (str): A query to search for
            cached (bool): If set, the query will be ignored and
                the result of the last search will be returned.

        Returns:
            Search results matching the query, from the cache or
            None if cache was requested but none existent
        """
        _cache = os.path.join(utils.get_cache_dir(), 'search_results.json')

        if query and not cached:
            return super(GMusic, self).search(query, max_results)

        if cached and os.path.exists(_cache):
            with open(_cache, 'r') as f:
                return json.loads(f.read())

        return None
    def get_listen_now_situations(self, from_cache=True):
        _cache = os.path.join(utils.get_cache_dir(), 'situations.json')

        resp = None
        if os.path.exists(_cache) and from_cache:
            with open(_cache, 'r') as f:
                try:
                    resp = json.loads(f.read())

                except:
                    pass

        if not resp:
            resp = self._make_call(mobileclient.ListListenNowSituations)

            with open(_cache, 'w+') as f:
                f.write(json.dumps(resp))

        if resp:
            return (resp['primaryHeader'], resp['situations'])

        else:
            return (None, None)
예제 #9
0
import xbmcgui

import mapper

from addon.gmusic_wrapper import GMusic
from addon import utils
from addon import listing
from addon import thumbs

from addon import ADDON
from addon import URL

MPR = mapper.Mapper.get()
gmusic = GMusic.get(debug_logging=False)
_cache_dir = utils.get_cache_dir()


@MPR.s_url('/browse/listen-now/')
def listen_now():
    ifl = xbmcgui.ListItem(utils.translate(30045))
    ifl.setArt({'thumb': thumbs.IMG_IFL, 'poster': thumbs.IMG_IFL})

    albums = xbmcgui.ListItem(utils.translate(30023))
    albums.setArt({'thumb': thumbs.IMG_ALBUM, 'poster': thumbs.IMG_ALBUM})

    stations = xbmcgui.ListItem(utils.translate(30021))
    stations.setArt({
        'thumb': thumbs.IMG_STATION,
        'poster': thumbs.IMG_STATION
    })
    def get_my_library_songs(self, from_cache=True):
        _cache = os.path.join(utils.get_cache_dir(['library']), 'songs.json')
        _song_cache_path = utils.get_cache_dir(['library', 'songs'])

        songs = None
        if os.path.exists(_cache) and from_cache:
            with open(_cache, 'r') as f:
                songs = json.loads(f.read())

        else:
            generator = self.get_all_songs(incremental=True,
                                           include_deleted=False)

            tmp = []
            for songs in generator:
                tmp += songs

            songs = tmp

            # Generate artistId and albumId in case they are
            # missing (applies to user uploaded songs without
            # a matching entry in googles database)
            for i, song in enumerate(songs):
                if ('title' not in song or 'album' not in song
                        or 'artist' not in song):
                    utils.log('Skipping broken entry:',
                              json.dumps(song),
                              lvl=xbmc.LOGERROR)
                    continue

                if 'artistId' not in song:
                    songs[i]['artistId'] = [str(uuid.uuid4())]

                if 'albumId' not in song:
                    songs[i]['albumId'] = str(uuid.uuid4())

            with open(_cache, 'w+') as f:
                f.write(json.dumps(songs))

            # Save each song as separate file
            # for easier and quicker access
            for song in songs:
                # Main id file
                _target = os.path.join(_song_cache_path, song['id'])
                with open(os.path.join(_target), 'w+') as f:
                    f.write(json.dumps(song))

                # Other available ids which we create symlinks for
                for _id in ['trackId', 'storeId']:
                    if _id not in song:
                        continue

                    _link = os.path.join(_song_cache_path, song[_id])
                    if os.path.exists(_link) and os.path.islink(_link):
                        continue

                    try:
                        # On unix systems we simply create a symlink
                        os.symlink(_target, _link)

                    except:
                        # On other systems (*cough* windows *cough*) we just
                        # write another version of the file
                        with open(os.path.join(_link), 'w+') as f:
                            f.write(json.dumps(song))

        return songs
def build_song_listitems(tracks,
                         station_id=None,
                         my_library=False,
                         my_library_playlist=False):
    tracks_cache = utils.get_cache_dir(['tracks'])

    items = []
    for elem in tracks:
        # Applies to e.g. search results
        if 'track' in elem:
            track = elem['track']
        else:
            track = elem

        # Try to get an id, otherwise we skip
        # Important, always try to get a trackId first, than
        # storeId and than id
        if 'trackId' in track:
            track_id = track['trackId']

        elif 'storeId' in track:
            track_id = track['storeId']

        elif 'id' in track:
            track_id = track['id']

        else:
            continue

        # In case of playlists, user uploaded songs come without
        # metadata (title, album, etc.)
        # All we can do at this point is to check the library cache
        # entry and use the informations from there (if it exists)
        #
        # We only do this if the title is missing as other metadata
        # isn't as important and we don't want to do this to often
        if 'title' not in track:
            _track = GMUSIC.get_my_library_song_details(track_id)
            if _track:
                track = _track

        track_title = track.get('title', '')
        album_art = thumbs.IMG_TRACK
        fanart = None

        if 'albumArtRef' in track and len(track['albumArtRef']) > 0:
            album_art = track['albumArtRef'][0]['url']

        if 'artistArtRef' in track and len(track['artistArtRef']) > 0:
            fanart = track['artistArtRef'][0]['url'] + '=s1920'

        item = xbmcgui.ListItem(track_title)

        item.setArt({
            'thumb': album_art,
            'poster': album_art,
            # 'fanart' : fanart
        })

        item.setInfo(
            'music', {
                'mediatype': 'song',
                'title': track_title,
                'tracknumber': track('trackNumber', ''),
                'year': track('year', ''),
                'genre': track('genre', ''),
                'album': track('album', ''),
                'artist': track('artist', ''),
                'rating': track('rating', ''),
                'playcount': track('playCount', ''),
            })

        menu_items = []

        if not my_library and 'id' not in track:
            # Add "Add to library" to context menu
            menu_items.append((
                utils.translate(30037), 'XBMC.RunPlugin(%s)' %
                utils.build_url(url=URL,
                                paths=['my-library', 'add', 'track', track_id],
                                r_path=True,
                                r_query=True)))

        # Add "Add to playlist" to context menu
        menu_items.append(
            (utils.translate(30038), 'XBMC.RunPlugin(%s)' %
             utils.build_url(url=URL,
                             paths=['my-library', 'playlist', 'add'],
                             queries={'track_id': track_id},
                             r_path=True,
                             r_query=True)))

        if my_library_playlist:
            # Add "Remove from playlist" to context menu
            if 'id' in elem:
                menu_items.append((
                    utils.translate(30062), 'XBMC.RunPlugin(%s)' %
                    utils.build_url(url=URL,
                                    paths=['my-library', 'playlist', 'remove'],
                                    queries={'entry_id': elem['id']},
                                    r_path=True,
                                    r_query=True)))

        # Add "Start radio" to context menu
        menu_items.append(
            (utils.translate(30036), 'XBMC.RunPlugin(%s)' %
             utils.build_url(url=URL,
                             paths=['play', 'station'],
                             queries={
                                 'track_id': track_id,
                                 'station_name': track_title.encode('utf-8')
                             },
                             r_path=True,
                             r_query=True)))

        # Add "Go to Artist" to context menu
        if 'artistId' in track and len(track['artistId']) > 0:
            menu_items.append(
                (utils.translate(30034),
                 'Container.Update(%s)' % utils.build_url(
                     url=URL,
                     paths=['browse', 'artist', track['artistId'][0]],
                     r_path=True,
                     r_query=True)))

        # Add "Go to Album" to context menu
        if 'albumId' in track:
            menu_items.append(
                (utils.translate(30035), 'Container.Update(%s)' %
                 utils.build_url(url=URL,
                                 paths=['browse', 'album', track['albumId']],
                                 r_path=True,
                                 r_query=True)))

        # Add "Rate song" to context menu
        menu_items.append((utils.translate(30041), 'XBMC.RunPlugin(%s)' %
                           utils.build_url(url=URL,
                                           paths=['rate'],
                                           queries={'track_id': track_id},
                                           r_path=True,
                                           r_query=True)))

        if my_library and 'id' in track:
            # Add "Remove from library" to context menu
            menu_items.append(
                (utils.translate(30061),
                 'XBMC.RunPlugin(%s)' % utils.build_url(
                     url=URL,
                     paths=['my-library', 'remove', 'track', track['id']],
                     r_path=True,
                     r_query=True)))

        item.addContextMenuItems(items=menu_items)

        item.setProperty('IsPlayable', 'true')
        item.setProperty('Music', 'true')
        item.setProperty('mimetype', 'audio/mpeg')

        # We cache everything so :play_track: doesn't have to fetch those
        # informations again
        with open(os.path.join(tracks_cache, track_id), 'w+') as f:
            f.write(json.dumps(track))

        queries = {}
        if station_id:
            queries['station_id'] = station_id

        items.append((utils.build_url(url=URL,
                                      paths=['play', 'track', track_id],
                                      queries=queries,
                                      r_path=True,
                                      r_query=True), item, False))

    # Clean up the tracks directory
    for _file in os.listdir(tracks_cache):
        _file = os.path.join(tracks_cache, _file)
        m_time = os.stat(_file).st_mtime

        # If older than 24h we remove it
        if m_time < time.time() - 86400:
            os.remove(_file)

    return items
예제 #12
0
import xbmcgui

import mapper

from addon.gmusic_wrapper import GMusic
from addon import utils
from addon import listing
from addon import thumbs

from addon import URL


MPR = mapper.Mapper.get()
GMUSIC = GMusic.get(debug_logging=False)
_CACHE_DIR = utils.get_cache_dir()


@MPR.s_url('/browse/browse-stations/')
def browse_stations():
    categories = GMUSIC.get_station_categories(False)

    items = []
    for category in categories:
        item = xbmcgui.ListItem(category['display_name'])
        item.setArt({
            'thumb': thumbs.IMG_STATION,
            'poster': thumbs.IMG_STATION
        })

        items.append((
            utils.build_url(