def attach_context_menu(self, item, menu): colorCaution = getSetting('item_caution_color') login = getSetting('username') isOwner = True cmd = containerUpdate(self.make_url(nt=Flag.USERPLAYLISTS, id='', mode=Mode.VIEW)) menu.add(path='playlist', pos=1, label="Playlist", cmd=cmd, mode=Mode.VIEW) if login != self.get_property('owner/name'): isOwner = False if isOwner: url = self.make_url(nt=Flag.PLAYLIST, mode=Mode.VIEW, nm='set_as_current') menu.add(path='playlist/set_as_current', label=lang(30163), cmd=containerUpdate(url)) url = self.make_url(nt=Flag.PLAYLIST, nm='gui_rename') menu.add(path='playlist/rename', label=lang(30165), cmd=runPlugin(url)) else: url = self.make_url(nt=Flag.PLAYLIST, nm='subscribe') menu.add(path='playlist/subscribe', label=lang(30168), cmd=runPlugin(url)) url = self.make_url(nt=Flag.PLAYLIST, nm='gui_remove') menu.add(path='playlist/remove', label=lang(30166), cmd=runPlugin(url), color=colorCaution) super(Node_playlist, self).attach_context_menu(item, menu)
def makeListItem(self, replaceItems=False): colorItem = getSetting('item_default_color') colorPl = getSetting('item_section_color') label = self.get_label() image = self.get_image() owner = self.get_owner() url = self.make_url() if not self.is_my_playlist: label = '%s - %s' % (color(colorItem, owner), label) if self.b_is_current: fmt = getSetting('playlist_current_format') label = fmt % (color(colorPl, label)) item = xbmcgui.ListItem(label, owner, image, image, url) if not item: warn(self, "Error: Cannot make xbmc list item") return None item.setPath(url) ctxMenu = contextMenu() self.attach_context_menu(item, ctxMenu) item.addContextMenuItems(ctxMenu.getTuples(), replaceItems) return item
def get_ttl(self, key, *a, **ka): if len(a) > 0: if a[0] == '/track/getFileUrl': return 60 * 15 if 'user_id' in ka: return getSetting('cache_duration_middle', asInt=True) * 60 return getSetting('cache_duration_long', asInt=True) * 60
def __init__(self): self.data = {} self.defaultSection = "qobuz" self.color_default = getSetting("item_default_color") self.color_section = getSetting("item_section_color") formatStr = getSetting("item_section_format") try: test = formatStr % ("plop") except: formatStr = "[ %s ]" self.format_section = formatStr
def bootstrap_registry(self): from qobuz.api import api cache.base_path = config.path.cache api.stream_format = 6 if getSetting('streamtype') == 'flac' else 5 if not api.login(getSetting('username'), getSetting('password')): if api.status_code == 503: dialogServiceTemporarilyUnavailable() else: dialogLoginFailure() #@TODO sys.exit killing XBMC? FRODO BUG ? # sys.exit(1) containerRefresh() raise QobuzXbmcError( who=self, what='invalid_login', additional=None)
def __getFileUrl(self): hires = getSetting('hires_enabled', asBool=True) format_id = 6 if getSetting('streamtype') == 'flac' else 5 if hires and self.get_hires(): format_id = 27 if self.get_property('purchased') or self.get_parameter('purchased') == '1' or self.purchased: intent = "download" else: intent = "stream" data = api.get('/track/getFileUrl', format_id=format_id, track_id=self.nid, user_id=api.user_id, intent=intent) if not data: warn(self, "Cannot get stream type for track (network problem?)") return None return data
def __add_pagination_node(self, Dir, lvl=1, whiteFlag=Flag.NODE): """Helper/Called by build_down to add special node when pagination is required """ if self.pagination_next: colorItem = getSetting('color_item') params = config.app.bootstrap.params params['offset'] = self.pagination_next_offset params['nid'] = self.nid node = getNode(self.nt, params) node.data = self.data label = self.get_label() if label is None: if self.label2 is not None: label = self.label2 elif self.parent is not None: label = self.parent.get_label() else: label = '[no-label]' nextLabel = u'[ {} {} / {} ]'.format(color(colorItem, label), self.pagination_next_offset, self.pagination_total) node.label = nextLabel node.label2 = label self.add_child(node)
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit', asInt=True) self.data = None query = self.query if not query: from gui.util import Keyboard k = Keyboard('', 'My %s' % self.search_type) k.doModal() if not k.isConfirmed(): return False query = k.getText() query.strip() info(self, 'search_type: %s, query: %s' % (self.search_type, query)) source = self.source kwargs = {'query': query, 'limit': limit, } if source is not None: kwargs['source'] = source data = None if self.search_type == 'albums': data = api.get('/collection/getAlbums', **kwargs) elif self.search_type == 'artists': data = api.get('/collection/getArtists', **kwargs) elif self.search_type == 'tracks': data = api.get('/collection/getTracks', **kwargs) if data is None: return False self.data = data return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting("pagination_limit") data = qobuz.registry.get(name="article_listrubrics", id=self.nid, offset=self.offset, limit=limit) if not data: return False self.data = data["data"] return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/artist/getSimilarArtists', artist_id=self.nid, offset=self.offset, limit=limit) if not data: return False self.data = data return len(data['artists']['items'])
def delete_cache(self, playlist_id): limit = getSetting('pagination_limit') upkey = cache.make_key('/playlist/getUserPlaylists', limit=limit, offset=self.offset, user_id=api.user_id) pkey = cache.make_key('/playlist/get', playlist_id=playlist_id, offset=self.offset, limit=limit, extra='tracks') cache.delete(upkey) cache.delete(pkey)
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/purchase/getUserPurchases', limit=limit, offset=self.offset, user_id=api.user_id) if not data: warn(self, "Cannot fetch purchases data") return False self.data = data return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/artist/get', artist_id=self.nid, limit=limit, offset=self.offset, extra='albums') if not data: warn(self, "Build-down: Cannot fetch artist data") return False self.data = data return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/artist/getSimilarArtist', artist_id=self.nid, limit=limit, offset=self.offset, extra='albums') if not data: warn(self, "Cannot fetch albums for artist: " + self.get_label()) return False self.data = data return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit', asInt=True) data = api.get('/playlist/get', playlist_id=self.nid, offset=self.offset, limit=limit, extra='tracks') if not data: warn(self, "Build-down: Cannot fetch playlist data") return False self.data = data self.get_image() # Buld thumbnail if neeeded return True
def attach_context_menu(self, item, menu): colorWarn = getSetting('item_caution_color') url = self.make_url() menu.add(path='friend', label=self.name, cmd=containerUpdate(url)) cmd = runPlugin(self.make_url(nt=Flag.FRIEND, nm="remove")) menu.add(path='friend/remove', label='Remove', cmd=cmd, color=colorWarn) ''' Calling base class ''' super(Node_friend, self).attach_context_menu(item, menu)
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting("pagination_limit") data = api.get("/playlist/getPublicPlaylists", offset=self.offset, limit=limit, type="last-created") if not data: return False # @bug: we use pagination_limit as limit for the search so we don't # need offset... (Fixed if qobuz fix it :p) if not "total" in data["playlists"]: data["playlists"]["total"] = data["playlists"]["limit"] self.data = data return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/playlist/getUserPlaylists', limit=limit, offset=self.offset, user_id=api.user_id) if data is None: warn(self, "Build-down: Cannot fetch user playlists data") return False self.data = data return True
def __init__(self, parent=None, parameters=None): super(Node_user_playlists, self).__init__(parent, parameters) self.label = lang(30021) self.image = getImage('userplaylists') self.nt = Flag.USERPLAYLISTS self.content_type = 'files' display_by = self.get_parameter('display-by', default=None) if display_by is None: display_by = 'songs' self.set_display_by(display_by) display_cover = getSetting('userplaylists_display_cover', asBool=True) self.display_product_cover = display_cover
def populate(self, Dir, lvl, whiteFlag, blackFlag): self.add_child(getNode(Flag.USERPLAYLISTS)) if getSetting('show_recommendations', asBool=True): self.add_child(getNode(Flag.RECOMMENDATION)) self.add_child(getNode(Flag.PURCHASES)) self.add_child(getNode(Flag.FAVORITES)) if getSetting('search_enabled', asBool=True): search = getNode(Flag.SEARCH) search.search_type = 'albums' self.add_child(search) search = getNode(Flag.SEARCH) search.search_type = 'tracks' self.add_child(search) search = getNode(Flag.SEARCH) search.search_type = 'artists' self.add_child(search) collections = getNode(Flag.COLLECTIONS) self.add_child(collections) self.add_child(getNode(Flag.FRIENDS)) self.add_child(getNode(Flag.GENRE)) self.add_child(getNode(Flag.PUBLIC_PLAYLISTS)) return True
def __init__(self, parent, params): super(Node_album, self).__init__(parent, params) self.nt = Flag.ALBUM self.image = getImage('album') self.content_type = 'songs' self.is_special_purchase = False self.imageDefaultSize = 'large' self.label = 'Album' self.offset = self.get_parameter('offset') or 0 try: self.imageDefaultSize = getSetting('image_default_size') except Exception as e: warn(self, 'Cannot set image default size, Error: {}', e)
def populate(self, Dir, lvl, whiteFlag, blackFlag): login = getSetting('username') cid = self.get_current_playlist_id() for data in self.data['playlists']['items']: node = getNode(Flag.PLAYLIST, data=data) #if self.display_product_cover: # pass if cid and cid == node.nid: node.set_is_current(True) if node.get_owner() == login: node.set_is_my_playlist(True) self.add_child(node) return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = api.get('/genre/list', parent_id=self.nid, offset=self.offset, limit=limit) if not data: self.data = None return True # Nothing returned trigger reco build in build_down self.data = data genres = self.data['genres'] if 'parent' in genres and int(genres['parent']['level']) > 1: self.populate_reco(Dir, lvl, whiteFlag, blackFlag, genres['parent']['id']) return True
def gui_remove(self, playlist_id=None): if not playlist_id: playlist_id = self.nid if not playlist_id: notify_error(dialogHeading, 'Invalid playlist %s' % (str(playlist_id))) return False login = getSetting('username') offset = 0 limit = getSetting('pagination_limit') data = api.get('/playlist/get', playlist_id=playlist_id, limit=limit, offset=offset) name = '' if 'name' in data: name = data['name'] ok = xbmcgui.Dialog().yesno(lang(30166), lang(30054), color('FFFF0000', name)) if not ok: info(self, "Deleting playlist aborted...") return False res = False if data['owner']['name'] == login: info(self, "Deleting playlist: " + str(playlist_id)) res = api.playlist_delete(playlist_id=playlist_id) else: info(self, 'Unsuscribe playlist' + str(playlist_id)) res = api.playlist_unsubscribe(playlist_id=playlist_id) if not res: warn(self, "Cannot delete playlist with id " + str(playlist_id)) notify_error(lang(30183), lang(30186) + name) return False self.delete_cache(playlist_id) notify_log(lang(30183), (lang(30184) + "%s" + lang(30185)) % (name)) url = self.make_url(nt=Flag.USERPLAYLISTS, mode=Mode.VIEW, nm='', nid='') executeBuiltin(containerUpdate(url, True)) return False
def attach_context_menu(self, item, menu): if self.parent and (self.parent.nt & Flag.PLAYLIST == Flag.PLAYLIST): colorCaution = getSetting('item_caution_color') url = self.parent.make_url(nt=Flag.PLAYLIST, id=self.parent.nid, qid=self.get_playlist_track_id(), nm='gui_remove_track', mode=Mode.VIEW) menu.add(path='playlist/remove', label=lang(30075), cmd=runPlugin(url), color=colorCaution) ''' Calling base class ''' super(Node_track, self).attach_context_menu(item, menu)
def fetch(self, Dir, lvl, whiteFlag, blackFlag): if self.genre_type is None or self.genre_id is None: return True offset = self.offset or 0 limit = getSetting('pagination_limit') data = api.get('/album/getFeatured', type=RECOS_TYPE_IDS[int(self.genre_type)], genre_id=self.genre_id, limit=10, offset=offset) if data is None: warn(self, 'Cannot fetch data for recommendation') return False self.data = data return True
def run(self): """Building our tree, creating root node based on our node_type """ if not self.set_root_node(): warn(self, ("Cannot set root node (%s, %s)") % (str(self.node_type), str(self.root.get_parameter('nid')))) return False if self.root.hasWidget: return self.root.displayWidget() if self.has_method_parameter(): return self.execute_method_parameter() from qobuz.gui.directory import Directory Dir = Directory(self.root, self.nodes, withProgress=self.enable_progress) Dir.asList = self.asList Dir.handle = config.app.handle if getSetting('contextmenu_replaceitems', asBool=True): Dir.replaceItems = True try: ret = self.root.populating(Dir, self.depth, self.whiteFlag, self.blackFlag) except Qerror as e: Dir.end_of_directory(False) Dir = None warn(self, "Error while populating our directory: %s" % (repr(e))) return False if not self.asList: import xbmcplugin # @UnresolvedImport Dir.set_content(self.root.content_type) methods = [ xbmcplugin.SORT_METHOD_UNSORTED, xbmcplugin.SORT_METHOD_LABEL, xbmcplugin.SORT_METHOD_DATE, xbmcplugin.SORT_METHOD_TITLE, xbmcplugin.SORT_METHOD_VIDEO_YEAR, xbmcplugin.SORT_METHOD_GENRE, xbmcplugin.SORT_METHOD_ARTIST, xbmcplugin.SORT_METHOD_ALBUM, xbmcplugin.SORT_METHOD_PLAYLIST_ORDER, xbmcplugin.SORT_METHOD_TRACKNUM, ] [xbmcplugin.addSortMethod(handle=config.app.handle, sortMethod=method) for method in methods] return Dir.end_of_directory()
def _delete_cache(self): limit = getSetting('pagination_limit') keys = [] keys.append(cache.make_key('/favorite/getUserFavorites', user_id=api.user_id, limit=limit, offset=self.offset)) for kind in ['artists', 'albums', 'tracks']: keys.append(cache.make_key('/favorite/getUserFavorites', user_id=api.user_id, limit=limit, type=kind, offset=self.offset)) ret = False for key in keys: if cache.delete(key): ret = True return ret
def play(self, track_id, params={}): """Playing track given a track id """ track = getNode(Flag.TRACK, {'nid': track_id}) if not track.fetch(None, 1, Flag.TRACK, Flag.NONE): warn(self, "Cannot get track data") return False if not track.is_playable(): warn(self, "Cannot get streaming URL") return False if 'purchased' in params: track.parameters['purchased']= True item = track.makeListItem() track.item_add_playing_property(item) """Some tracks are not authorized for stream and a 60s sample is returned, in that case we overwrite the song duration """ if track.is_sample(): item.setInfo( 'music', infoLabels={ 'duration': 60, }) """Don't warn for free account (all songs except purchases are 60s limited) """ if not isFreeAccount(): notify_warn("Qobuz", "Sample returned") xbmcgui.Window(10000).setProperty(keyTrackId, track_id) """Notify """ if getSetting('notification_playingsong', asBool=True): notify_restriction(track) notifyH(lang(30132), track.get_label(), image=track.get_image()) """We are called from playlist... """ if config.app.handle == -1: super(QobuzPlayer, self).play(track.get_streaming_url(), item, False) else: setResolvedUrl(handle=config.app.handle, succeeded=True, listitem=item) return True
def fetch(self, Dir, lvl, whiteFlag, blackFlag): limit = getSetting('pagination_limit') data = None if self.search_type != 'all': data = api.get('/favorite/getUserFavorites', user_id=api.user_id, type=self.search_type, limit=limit, offset=self.offset) else: data = api.get('/favorite/getUserFavorites', user_id=api.user_id, limit=limit, offset=self.offset) if not data: warn(self, "Build-down: Cannot fetch favorites data") return False self.data = data return True