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']
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)
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
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(