class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.datatype = 'main' self.title = '网易云音乐' self.datalist = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助'] self.offset = 0 self.index = 0 self.presentsongs = [] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = STEP self.stack = [] self.djstack = [] self.userid = None self.username = None try: sfile = file(home + "/netease-musicbox/flavor.json",'r') data = json.loads(sfile.read()) self.collection = data['collection'] self.account = data['account'] sfile.close() except: self.collection = [] self.account = {} def start(self): self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack key = self.screen.getch() self.ui.screen.refresh() # 退出 if key == ord('q'): break # 上移 elif key == ord('k'): self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx-1 ) # 下移 elif key == ord('j'): self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx+1 ) # 向上翻页 elif key == ord('u'): if offset == 0: continue self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index-step)//step*step # 向下翻页 elif key == ord('d'): if offset + step >= len( datalist ): continue self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index+step)//step*step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord('f'): self.search() # 播放下一曲 elif key == ord(']'): if len(self.presentsongs) == 0: continue self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord('['): if len(self.presentsongs) == 0: continue self.player.prev() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): if datatype == 'songs': self.presentsongs = ['songs', title, datalist, offset, index] elif datatype == 'djchannels': self.presentsongs = ['djchannels', title, datalist, offset, index] self.player.play(datatype, datalist, idx) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.presentsongs) == 0: continue self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.presentsongs[0] self.title = self.presentsongs[1] self.datalist = self.presentsongs[2] self.offset = self.presentsongs[3] self.index = self.presentsongs[4] # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append( datalist[idx] ) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append( datalist[idx] ) # 加载收藏歌曲 elif key == ord('c'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if datatype != 'main' and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx ) elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab('https://github.com/vellow/NetEase-MusicBox') elif key == ord('w'): if datatype == 'songs': self.player.download() self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.player.stop() sfile = file(home + "/netease-musicbox/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection } sfile.write(json.dumps(data)) sfile.close() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append( [datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 该歌单包含的歌曲 elif datatype == 'playlists': playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: songs = netease.top_songlist() self.datalist = netease.dig_info(songs, 'songs') self.title += ' > 排行榜' self.datatype = 'songs' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: playlists = netease.top_playlists() self.datalist = netease.dig_info(playlists, 'playlists') self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.account: user_info = netease.login(self.account[0], self.account[1]) # 本地没有存储账户,或本地账户失效,则引导录入 if self.account == {} or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.account = data[1] self.username = user_info['profile']['nickname'] self.userid = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist( self.userid ) self.datalist = netease.dig_info(myplaylist, 'playlists') self.datatype = 'playlists' self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = 'songs' self.title += ' > 打碟' self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = 'songs' self.title += ' > 收藏' self.datalist = self.collection # 搜索 elif idx == 8: self.search() # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0 def search(self): ui = self.ui x = ui.build_search_menu() # if do search, push current info into stack if x in range(ord('1'), ord('5')): self.stack.append( [self.datatype, self.title, self.datalist, self.offset, self.index ]) self.index = 0 self.offset = 0 if x == ord('1'): self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif x == ord('2'): self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif x == ord('3'): self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' elif x == ord('4'): self.datatype = 'playlists' self.datalist = ui.build_search('playlists') self.title = '精选歌单搜索列表'
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.data_type = 'main' # Title of the application self.title = '网易云音乐' # Main-menu list self.data_list = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助'] # Which page of the data_list is displayed (data_list may be displayed in multiple pages self.page_index = 0 # The index of the current selected line self.current_line_index = 0 self.present_songs = [] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.page_size = 10 # The number of lines that can be displayed on one page. self.stack = [] self.dj_stack = [] self.user_id = None self.user_name = None # Read in the collection and account in flavor.json try: config_file = file(Constant.conf_dir + "/flavor.json", 'r') data = json.loads(config_file.read()) self.collection = data['collection'] self.account = data['account'] config_file.close() except: self.collection = [] self.account = {} def start(self): # draw the main menu self.ui.build_menu(self.data_type, self.title, self.data_list, self.page_index, self.current_line_index, self.page_size) # push current menu into stack self.stack.append([self.data_type, self.title, self.data_list, self.page_index, self.current_line_index]) # Main loop while True: # refresh the menu data_type = self.data_type title = self.title data_list = self.data_list page_index = self.page_index idx = current_line_index = self.current_line_index page_size = self.page_size stack = self.stack dj_stack = self.dj_stack self.ui.screen.refresh() # fetch a user's command key = self.screen.getch() # quit if key == ord('q'): break # move up elif key == ord('k') or key == curses.KEY_UP: self.current_line_index = carousel(page_index, min(len(data_list), page_index + page_size) - 1, idx - 1) # DEBUG # self.ui.screen.addstr(0, 0,'current_line_index: {}, begin: {}, end: {}'.format(self.current_line_index, page_index, min(len(data_list), page_index+page_size))) # move down elif key == ord('j') or key == curses.KEY_DOWN: self.current_line_index = carousel(page_index, min(len(data_list), page_index + page_size) - 1, idx + 1) # DEBUG # self.ui.screen.addstr(0, 0,'current_line_index: {}, begin: {}, end: {}'.format(self.current_line_index, page_index, min(len(data_list), page_index+page_size))) # number shortcut elif ord('0') <= key <= ord('9'): if self.data_type == 'songs' or self.data_type == 'djchannels' or self.data_type == 'help': continue idx = key - ord('0') self.ui.build_menu(self.data_type, self.title, self.data_list, self.page_index, idx, self.page_size) self.ui.build_loading() self.dispatch_enter(idx) self.current_line_index = 0 self.page_index = 0 # 向上翻页 elif key == ord('u') or key == curses.KEY_PPAGE: if page_index == 0: continue self.page_index -= page_size # Move to first line of the page self.current_line_index = (current_line_index - page_size) // page_size * page_size # 向下翻页 elif key == ord('d') or key == curses.KEY_NPAGE: if page_index + page_size >= len(data_list): continue self.page_index += page_size # Move to first line of the page self.current_line_index = (current_line_index + page_size) // page_size * page_size # 前进 elif key == ord('l') or key == 10 or key == curses.KEY_RIGHT: if self.data_type == 'songs' or self.data_type == 'djchannels' or self.data_type == 'help': continue self.ui.build_loading() self.dispatch_enter(idx) self.current_line_index = 0 self.page_index = 0 # 回退 elif key == ord('h') or key == curses.KEY_LEFT: # if not main menu if len(self.stack) == 1: continue last_menu = stack.pop() self.data_type = last_menu[0] self.title = last_menu[1] self.data_list = last_menu[2] self.page_index = last_menu[3] self.current_line_index = last_menu[4] # 搜索 elif key == ord('f'): self.search() # 播放下一曲 elif key == ord(']') or key == curses.KEY_NEXT: if len(self.present_songs) == 0: continue self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord('[') or key == curses.KEY_PREVIOUS: if len(self.present_songs) == 0: continue self.player.prev() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): if data_type == 'songs': self.present_songs = ['songs', title, data_list, page_index, current_line_index] elif data_type == 'djchannels': self.present_songs = ['djchannels', title, data_list, page_index, current_line_index] self.player.play(data_type, data_list, idx) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.present_songs) == 0: continue self.stack.append([data_type, title, data_list, page_index, current_line_index]) self.data_type = self.present_songs[0] self.title = self.present_songs[1] self.data_list = self.present_songs[2] self.page_index = self.present_songs[3] self.current_line_index = self.present_songs[4] # 添加到打碟歌单 elif key == ord('a'): if data_type == 'songs' and len(data_list) != 0: self.dj_stack.append(data_list[idx]) elif data_type == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([data_type, title, data_list, page_index, current_line_index]) self.data_type = 'songs' self.title = '网易云音乐 > 打碟' self.data_list = self.dj_stack self.page_index = 0 self.current_line_index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (data_type == 'songs' or data_type == 'djchannels') and len(data_list) != 0: self.collection.append(data_list[idx]) # 加载收藏歌曲 elif key == ord('c'): self.stack.append([data_type, title, data_list, page_index, current_line_index]) self.data_type = 'songs' self.title = '网易云音乐 > 收藏' self.data_list = self.collection self.page_index = 0 self.current_line_index = 0 # 从当前列表移除 elif key == ord('r'): if data_type != 'main' and len(data_list) != 0: self.data_list.pop(idx) self.current_line_index = carousel(page_index, min(len(data_list), page_index + page_size) - 1, idx) elif key == ord('m'): if data_type != 'main': self.stack.append([data_type, title, data_list, page_index, current_line_index]) self.data_type = self.stack[0][0] self.title = self.stack[0][1] self.data_list = self.stack[0][2] self.page_index = 0 self.current_line_index = 0 elif key == ord('g'): if data_type == 'help': webbrowser.open_new_tab('https://github.com/darknessomi/musicbox') elif key == ord('\\'): self.player.next_play_mode() # refresh the window self.ui.build_menu(self.data_type, self.title, self.data_list, self.page_index, self.current_line_index, self.page_size) self.player.stop() sfile = file(Constant.conf_dir + "/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection } sfile.write(json.dumps(data)) sfile.close() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.data_type title = self.title datalist = self.data_list offset = self.page_index index = self.current_line_index self.stack.append([datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.data_type = 'songs' self.data_list = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.data_type = 'songs' self.data_list = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.data_list[idx] self.data_type = data['datatype'] self.data_list = netease.dig_info(data['callback'](), self.data_type) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.data_type = 'songs' self.data_list = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.data_list[idx] self.data_type = 'playlist_class_detail' self.data_list = netease.dig_info(data, self.data_type) self.title += ' > ' + data log.debug(self.data_list) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.data_list[idx] self.data_type = 'top_playlists' self.data_list = netease.dig_info(netease.top_playlists(data), self.data_type) log.debug(self.data_list) self.title += ' > ' + data def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: songs = netease.top_songlist() self.data_list = netease.dig_info(songs, 'songs') self.title += ' > 排行榜' self.data_type = 'songs' # 艺术家 elif idx == 1: artists = netease.top_artists() self.data_list = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.data_type = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.data_list = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.data_type = 'albums' # 精选歌单 elif idx == 3: self.data_list = [ { 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes } ] self.title += ' > 精选歌单' self.data_type = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.user_id is None: # 使用本地存储了账户登录 if self.account: user_info = netease.login(self.account[0], self.account[1]) else: user_info = {} # 本地没有存储账户,或本地账户失效,则引导录入 # if self.account == {} or user_info['code'] != 200: if self.account == {} or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.account = data[1] self.user_name = user_info['profile']['nickname'] self.user_id = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist(self.user_id) self.data_type = 'top_playlists' self.data_list = netease.dig_info(myplaylist, self.data_type) self.title += ' > ' + self.user_name + ' 的歌单' # DJ节目 elif idx == 5: self.data_type = 'djchannels' self.title += ' > DJ节目' self.data_list = netease.djchannels() # 打碟 elif idx == 6: self.data_type = 'songs' self.title += ' > 打碟' self.data_list = self.dj_stack # 收藏 elif idx == 7: self.data_type = 'songs' self.title += ' > 收藏' self.data_list = self.collection # 搜索 elif idx == 8: self.search() # 帮助 elif idx == 9: self.data_type = 'help' self.title += ' > 帮助' self.data_list = shortcut self.page_index = 0 self.current_line_index = 0 def search(self): ui = self.ui x = ui.build_search_menu() # if do search, push current info into stack if x in range(ord('1'), ord('5')): self.stack.append([self.data_type, self.title, self.data_list, self.page_index, self.current_line_index]) self.current_line_index = 0 self.page_index = 0 if x == ord('1'): self.data_type = 'songs' self.data_list = ui.build_search('songs') self.title = '歌曲搜索列表' elif x == ord('2'): self.data_type = 'artists' self.data_list = ui.build_search('artists') self.title = '艺术家搜索列表' elif x == ord('3'): self.data_type = 'albums' self.data_list = ui.build_search('albums') self.title = '专辑搜索列表' elif x == ord('4'): # 搜索结果可以用top_playlists处理 self.data_type = 'top_playlists' self.data_list = ui.build_search('search_playlist') self.title = '精选歌单搜索列表'
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding("UTF-8") self.datatype = "main" self.title = "网易云音乐" self.datalist = ["排行榜", "艺术家", "新碟上架", "精选歌单", "我的歌单", "DJ节目", "打碟", "收藏", "搜索", "帮助"] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database["collections"][0] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = None self.username = None self.resume_play = True signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.storage.save() curses.endwin() sys.exit() def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database["player_info"]["playing_mode"], ) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord("q"): break # 退出并清除用户信息 if key == ord("w"): self.storage.database["user"] = {"username": "", "password": ""} break # 上移 elif key == ord("k"): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord("j"): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord("0") <= key <= ord("9"): if self.datatype == "songs" or self.datatype == "djchannels" or self.datatype == "help": continue idx = key - ord("0") self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord("u"): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord("d"): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord("l") or key == 10: if self.datatype == "songs" or self.datatype == "djchannels" or self.datatype == "help": continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord("h"): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord("f"): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord("]"): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord("["): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.prev() time.sleep(0.1) # 增加音量 elif key == ord("="): self.player.volume_up() # 减少音量 elif key == ord("-"): self.player.volume_down() # 随机播放 elif key == ord("?"): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.shuffle() time.sleep(0.1) # 播放、暂停 elif key == ord(" "): try: if self.datalist[idx] == self.storage.database["songs"][str(self.player.playing_id)]: self.player.play_and_pause(self.storage.database["player_info"]["idx"]) time.sleep(0.1) continue except: pass if datatype == "songs": self.resume_play = False self.player.new_player_list("songs", self.title, self.datalist, -1) self.player.play_and_pause(idx) elif datatype == "djchannels": self.resume_play = False self.player.new_player_list("djchannels", self.title, self.datalist, -1) self.player.play_and_pause(idx) else: self.player.play_and_pause(self.storage.database["player_info"]["idx"]) time.sleep(0.1) # 加载当前播放列表 elif key == ord("p"): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.datatype = self.storage.database["player_info"]["player_list_type"] self.title = self.storage.database["player_info"]["player_list_title"] self.datalist = [] for i in self.storage.database["player_info"]["player_list"]: self.datalist.append(self.storage.database["songs"][i]) self.index = self.storage.database["player_info"]["idx"] self.offset = self.storage.database["player_info"]["idx"] / self.step * self.step if self.resume_play: self.storage.database["player_info"]["idx"] = -1 self.player.play_and_pause(self.index) self.resume_play = False # 播放模式切换 elif key == ord("P"): self.storage.database["player_info"]["playing_mode"] = ( self.storage.database["player_info"]["playing_mode"] + 1 ) % 5 # 添加到打碟歌单 elif key == ord("a"): if datatype == "songs" and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == "artists": pass # 加载打碟歌单 elif key == ord("z"): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = "songs" self.title = "网易云音乐 > 打碟" self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord("s"): if (datatype == "songs" or datatype == "djchannels") and len(datalist) != 0: self.collection.append(datalist[idx]) # 加载收藏歌曲 elif key == ord("c"): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = "songs" self.title = "网易云音乐 > 收藏" self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord("r"): if datatype != "main" and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != "main" and len(datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != "main" and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord("m"): if datatype != "main": self.stack.append([datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord("g"): if datatype == "help": webbrowser.open_new_tab("https://github.com/darknessomi/musicbox") self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database["player_info"]["playing_mode"], ) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if datatype == "main": self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == "artists": artist_id = datalist[idx]["artist_id"] songs = netease.artists(artist_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["artists_name"] # 该专辑包含的歌曲 elif datatype == "albums": album_id = datalist[idx]["album_id"] songs = netease.album(album_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["albums_name"] # 精选歌单选项 elif datatype == "playlists": data = self.datalist[idx] self.datatype = data["datatype"] self.datalist = netease.dig_info(data["callback"](), self.datatype) self.title += " > " + data["title"] # 全站置顶歌单包含的歌曲 elif datatype == "top_playlists": log.debug(datalist) playlist_id = datalist[idx]["playlist_id"] songs = netease.playlist_detail(playlist_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["playlists_name"] # 分类精选 elif datatype == "playlist_classes": # 分类名称 data = self.datalist[idx] self.datatype = "playlist_class_detail" self.datalist = netease.dig_info(data, self.datatype) self.title += " > " + data log.debug(self.datalist) # 某一分类的详情 elif datatype == "playlist_class_detail": # 子类别 data = self.datalist[idx] self.datatype = "top_playlists" self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += " > " + data # 歌曲榜单 elif datatype == "toplists": songs = netease.top_songlist(idx) self.title += " > " + self.datalist[idx] self.datalist = netease.dig_info(songs, "songs") self.datatype = "songs" # 搜索菜单 elif datatype == "search": ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = "top_playlists" self.datalist = ui.build_search("search_playlist") self.title = "精选歌单搜索列表" elif idx == 1: self.datatype = "songs" self.datalist = ui.build_search("songs") self.title = "歌曲搜索列表" elif idx == 2: self.datatype = "artists" self.datalist = ui.build_search("artists") self.title = "艺术家搜索列表" elif idx == 3: self.datatype = "albums" self.datalist = ui.build_search("albums") self.title = "专辑搜索列表" def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += " > 排行榜" self.datatype = "toplists" # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, "artists") self.title += " > 艺术家" self.datatype = "artists" # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, "albums") self.title += " > 新碟上架" self.datatype = "albums" # 精选歌单 elif idx == 3: self.datalist = [ {"title": "全站置顶", "datatype": "top_playlists", "callback": netease.top_playlists}, {"title": "分类精选", "datatype": "playlist_classes", "callback": netease.playlist_classes}, ] self.title += " > 精选歌单" self.datatype = "playlists" # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.storage.database["user"]["username"] != "": user_info = netease.login( self.storage.database["user"]["username"], self.storage.database["user"]["password"] ) # 本地没有存储账户,或本地账户失效,则引导录入 if self.storage.database["user"]["username"] == "" or user_info["code"] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.storage.database["user"]["username"] = data[1][0] self.storage.database["user"]["password"] = data[1][1] self.username = user_info["profile"]["nickname"] self.userid = user_info["account"]["id"] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist(self.userid) self.datatype = "top_playlists" self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += " > " + self.username + " 的歌单" # DJ节目 elif idx == 5: self.datatype = "djchannels" self.title += " > DJ节目" self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = "songs" self.title += " > 打碟" self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = "songs" self.title += " > 收藏" self.datalist = self.collection # 搜索 elif idx == 8: self.datatype = "search" self.title += " > 搜索" self.datalist = ["歌曲", "艺术家", "专辑", "网易精选集"] # 帮助 elif idx == 9: self.datatype = "help" self.title += " > 帮助" self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.config = Config() self.datatype = 'main' self.title = '网易云音乐' self.datalist = [ '排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '每日推荐', '私人FM', '搜索', '帮助' ] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'][0] self.player = Player() self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] self.resume_play = True self.at_playing_list = False signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def alert(self, version): latest = Menu().check_version() if latest != version: if platform.system() == 'Darwin': os.system( '/usr/bin/osascript -e \'display notification "MusicBox Update is available"sound name "/System/Library/Sounds/Ping.aiff"\'' ) time.sleep(0.5) os.system( '/usr/bin/osascript -e \'display notification "NetEase-MusicBox installed version:' + version + '\nNetEase-MusicBox latest version:' + latest + '"\'') else: os.system( '/usr/bin/notify-send "MusicBox Update is available"') def check_version(self): # 检查更新 tree = ET.ElementTree(ET.fromstring(str(self.netease.get_version()))) root = tree.getroot() return root[0][4][0][0].text def start_fork(self, version): pid = os.fork() if pid == 0: Menu().alert(version) else: Menu().start() def play_pause(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return if self.player.pause_flag: self.player.resume() else: self.player.pause() time.sleep(0.1) def next_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.next() time.sleep(0.1) def previous_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.prev() time.sleep(0.1) def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.stack.append([ self.datatype, self.title, self.datalist, self.offset, self.index ]) if bind_global: keybinder.bind(self.config.get_item("global_play_pause"), self.play_pause) keybinder.bind(self.config.get_item("global_next"), self.next_song) keybinder.bind(self.config.get_item("global_previous"), self.previous_song) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() if bind_global: keybinder.gtk.main_iteration(False) self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): break # 退出并清除用户信息 if key == ord('w'): self.storage.database['user'] = { "username": "", "password": "", "user_id": "", "nickname": "", } try: os.remove(self.storage.cookie_path) except: break break # 上移 elif key == ord('k'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] self.at_playing_list = False # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): self.next_song() # 播放上一曲 elif key == ord('['): self.previous_song() # 增加音量 elif key == ord('='): self.player.volume_up() # 减少音量 elif key == ord('-'): self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.storage.database["player_info"] ["player_list"]) == 0: continue self.player.shuffle() time.sleep(0.1) # 喜爱 elif key == ord(','): self.request_api(self.netease.fm_like, self.player.get_playing_id()) # 删除FM elif key == ord('.'): if self.datatype == 'fmsongs': if len(self.storage.database["player_info"] ["player_list"]) == 0: continue self.player.next() self.request_api(self.netease.fm_trash, self.player.get_playing_id()) time.sleep(0.1) # 下一FM elif key == ord('/'): if self.datatype == 'fmsongs': if len(self.storage.database["player_info"] ["player_list"]) == 0: continue self.player.next() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): # If not open a new playing list, just play and pause. try: if self.datalist[idx]['song_id'] == self.player.playing_id: self.player.play_and_pause( self.storage.database['player_info']['idx']) time.sleep(0.1) continue except: pass # If change to a new playing list. Add playing list and play. if datatype == 'songs': self.resume_play = False self.player.new_player_list('songs', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'djchannels': self.resume_play = False self.player.new_player_list('djchannels', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'fmsongs': self.resume_play = False self.storage.database['player_info']['playing_mode'] = 0 self.player.new_player_list('fmsongs', self.title, self.datalist, -1) self.player.end_callback = self.fm_callback self.player.play_and_pause(idx) self.at_playing_list = True else: self.player.play_and_pause( self.storage.database['player_info']['idx']) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.storage.database['player_info'] ['player_list']) == 0: continue if not self.at_playing_list: self.stack.append([ self.datatype, self.title, self.datalist, self.offset, self.index ]) self.at_playing_list = True self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info'][ 'player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step if self.resume_play: if self.datatype == "fmsongs": self.player.end_callback = self.fm_callback else: self.player.end_callback = None self.storage.database['player_info']['idx'] = -1 self.player.play_and_pause(self.index) self.resume_play = False # 播放模式切换 elif key == ord('P'): self.storage.database['player_info']['playing_mode'] = \ (self.storage.database['player_info']['playing_mode'] + 1) % 5 # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) # 加载收藏歌曲 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel( offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != 'main' and len( datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab( 'https://github.com/darknessomi/musicbox') self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data log.debug(self.datalist) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' def fm_callback(self): log.debug("FM CallBack.") data = self.get_new_fm() self.player.append_songs(data) if self.datatype == 'fmsongs': if len(self.storage.database['player_info']['player_list']) == 0: return self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info'][ 'player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step def request_api(self, func, *args): if self.storage.database['user']['user_id'] != "": result = func(*args) if result != -1: return result log.debug("Re Login.") user_info = {} if self.storage.database['user']['username'] != "": user_info = self.netease.login( self.storage.database['user']['username'], self.storage.database['user']['password']) if self.storage.database['user'][ 'username'] == "" or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return -1 user_info = data[0] self.storage.database['user']['username'] = data[1][0] self.storage.database['user']['password'] = data[1][1] self.storage.database['user']['user_id'] = user_info['account'][ 'id'] self.storage.database['user']['nickname'] = user_info['profile'][ 'nickname'] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] return func(*args) def get_new_fm(self): myplaylist = [] for count in range(0, 1): data = self.request_api(self.netease.personal_fm) if data == -1: break myplaylist += data time.sleep(0.2) return self.netease.dig_info(myplaylist, "fmsongs") def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [{ 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes }] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: myplaylist = self.request_api(self.netease.user_playlist, self.userid) if myplaylist == -1: return self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 每日推荐 elif idx == 6: self.datatype = 'songs' self.title += ' > 每日推荐' myplaylist = self.request_api(self.netease.recommend_playlist) if myplaylist == -1: return self.datalist = self.netease.dig_info(myplaylist, self.datatype) # 私人FM elif idx == 7: self.datatype = 'fmsongs' self.title += ' > 私人FM' self.datalist = self.get_new_fm() # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > 搜索' self.datalist = ['歌曲', '艺术家', '专辑', '网易精选集'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.datatype = 'main' self.title = '网易云音乐' self.datalist = [ '排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助' ] self.offset = 0 self.index = 0 self.presentsongs = [] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = None self.username = None self.resume_play = True signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() try: sfile = file(Constant.conf_dir + "/flavor.json", 'r') data = json.loads(sfile.read()) self.collection = data['collection'] self.account = data['account'] self.presentsongs = data['presentsongs'] sfile.close() except: self.collection = [] self.account = {} self.presentsongs = [] self.resume_play = False def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() sfile = file(Constant.conf_dir + "/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection, 'presentsongs': self.presentsongs } sfile.write(json.dumps(data)) sfile.close() curses.endwin() sys.exit() def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.stack.append([ self.datatype, self.title, self.datalist, self.offset, self.index ]) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): break # 退出并清除用户信息 if key == ord('w'): self.account = {} break # 上移 elif key == ord('k'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): if len(self.presentsongs) == 0: continue self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord('['): if len(self.presentsongs) == 0: continue self.player.prev() time.sleep(0.1) # 增加音量 elif key == ord('='): if len(self.presentsongs) == 0: continue self.player.volume_up() # 减少音量 elif key == ord('-'): if len(self.presentsongs) == 0: continue self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.presentsongs) == 0: continue self.player.shuffle() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): if datatype == 'songs': self.presentsongs = [ 'songs', title, datalist, offset, index ] elif datatype == 'djchannels': self.presentsongs = [ 'djchannels', title, datalist, offset, index ] self.player.play(datatype, datalist, idx) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.presentsongs) == 0: continue self.stack.append([datatype, title, datalist, offset, index]) self.datatype = self.presentsongs[0] self.title = self.presentsongs[1] self.datalist = self.presentsongs[2] self.offset = self.presentsongs[3] self.index = self.presentsongs[4] if self.resume_play: self.player.play(self.datatype, self.datalist, self.index) self.resume_play = False # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) # 加载收藏歌曲 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if datatype != 'main' and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel( offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != 'main' and len( datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab( 'https://github.com/darknessomi/musicbox') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() sfile = file(Constant.conf_dir + "/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection, 'presentsongs': self.presentsongs } sfile.write(json.dumps(data)) sfile.close() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data log.debug(self.datalist) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [{ 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes }] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.account: user_info = netease.login(self.account[0], self.account[1]) # 本地没有存储账户,或本地账户失效,则引导录入 if self.account == {} or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.account = data[1] self.username = user_info['profile']['nickname'] self.userid = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist(self.userid) self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = 'songs' self.title += ' > 打碟' self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = 'songs' self.title += ' > 收藏' self.datalist = self.collection # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > 搜索' self.datalist = ['歌曲', '艺术家', '专辑', '网易精选集'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding("UTF-8") self.config = Config() self.datatype = "main" self.title = "网易云音乐" self.datalist = ["排行榜", "艺术家", "新碟上架", "精选歌单", "我的歌单", "DJ节目", "每日推荐", "私人FM", "搜索", "帮助"] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database["collections"][0] self.player = Player() self.player.playing_song_changed_callback = self.song_changed_callback self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] self.resume_play = True self.at_playing_list = False signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def alert(self, version): latest = Menu().check_version() if latest != version: if platform.system() == "Darwin": os.system( '/usr/bin/osascript -e \'display notification "MusicBox Update is available"sound name "/System/Library/Sounds/Ping.aiff"\'' ) time.sleep(0.5) os.system( "/usr/bin/osascript -e 'display notification \"NetEase-MusicBox installed version:" + version + "\nNetEase-MusicBox latest version:" + latest + "\"'" ) else: os.system('/usr/bin/notify-send "MusicBox Update is available"') def check_version(self): # 检查更新 tree = ET.ElementTree(ET.fromstring(str(self.netease.get_version()))) root = tree.getroot() return root[0][4][0][0].text def start_fork(self, version): # Hong, Fork a child process. # Return 0 in the child and the child’s process id in the parent. pid = os.fork() if pid == 0: Menu().alert(version) else: Menu().start() def play_pause(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return if self.player.pause_flag: self.player.resume() else: self.player.pause() time.sleep(0.1) def next_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.next() time.sleep(0.1) def previous_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.prev() time.sleep(0.1) def start(self): # Hong, Return the time in seconds since the epoch as a floating point number. self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database["player_info"]["playing_mode"], ) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) if bind_global: keybinder.bind(self.config.get_item("global_play_pause"), self.play_pause) keybinder.bind(self.config.get_item("global_next"), self.next_song) keybinder.bind(self.config.get_item("global_previous"), self.previous_song) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() if bind_global: keybinder.gtk.main_iteration(False) self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 # Hong, ord(), Given a string of length one, return an integer representing the Unicode code point of the character when the argument is a unicode object, # or the value of the byte when the argument is an 8-bit string. if key == ord("q"): break # 退出并清除用户信息 if key == ord("w"): self.storage.database["user"] = {"username": "", "password": "", "user_id": "", "nickname": ""} try: os.remove(self.storage.cookie_path) except: break break # 上移 elif key == ord("k"): # turn page if at beginning if idx == offset: if offset == 0: continue self.offset -= step # 移动光标到最后一列 self.index = offset - 1 else: self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord("j"): # turn page if at end if idx == min(len(datalist), offset + step) - 1: if offset + step >= len(datalist): continue self.offset += step # 移动光标到第一列 self.index = offset + step else: self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord("0") <= key <= ord("9"): if self.datatype == "songs" or self.datatype == "djchannels" or self.datatype == "help": continue idx = key - ord("0") self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord("u"): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord("d"): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord("l") or key == 10: if ( self.datatype == "songs" or self.datatype == "djchannels" or self.datatype == "help" or len(self.datalist) <= 0 ): continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord("h"): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] self.at_playing_list = False # 搜索 elif key == ord("f"): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord("]"): self.next_song() # 播放上一曲 elif key == ord("["): self.previous_song() # 增加音量 elif key == ord("="): self.player.volume_up() # 减少音量 elif key == ord("-"): self.player.volume_down() # 随机播放 elif key == ord("?"): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.shuffle() time.sleep(0.1) # 喜爱 elif key == ord(","): return_data = self.request_api(self.netease.fm_like, self.player.get_playing_id()) if return_data != -1: if platform.system() == "Darwin": os.system("/usr/bin/osascript -e 'display notification \"Added successfully\"'") else: os.system('/usr/bin/notify-send "Added successfully"') # 删除FM elif key == ord("."): if self.datatype == "fmsongs": if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() return_data = self.request_api(self.netease.fm_trash, self.player.get_playing_id()) if return_data != -1: if platform.system() == "Darwin": os.system("/usr/bin/osascript -e 'display notification \"Deleted successfully\"'") else: os.system('/usr/bin/notify-send "Deleted successfully"') time.sleep(0.1) # 下一FM elif key == ord("/"): if self.datatype == "fmsongs": if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() time.sleep(0.1) # 播放、暂停 elif key == ord(" "): # If not open a new playing list, just play and pause. try: if self.datalist[idx]["song_id"] == self.player.playing_id: self.player.play_and_pause(self.storage.database["player_info"]["idx"]) time.sleep(0.1) continue except: pass # If change to a new playing list. Add playing list and play. if datatype == "songs": self.resume_play = False self.player.new_player_list("songs", self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == "djchannels": self.resume_play = False self.player.new_player_list("djchannels", self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == "fmsongs": self.resume_play = False self.storage.database["player_info"]["playing_mode"] = 0 self.player.new_player_list("fmsongs", self.title, self.datalist, -1) self.player.end_callback = self.fm_callback self.player.play_and_pause(idx) self.at_playing_list = True else: self.player.play_and_pause(self.storage.database["player_info"]["idx"]) time.sleep(0.1) # 加载当前播放列表 elif key == ord("p"): self.show_playing_song() # 播放模式切换 elif key == ord("P"): self.storage.database["player_info"]["playing_mode"] = ( self.storage.database["player_info"]["playing_mode"] + 1 ) % 5 # 添加到打碟歌单 elif key == ord("a"): if datatype == "songs" and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == "artists": pass # 加载打碟歌单 elif key == ord("z"): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = "songs" self.title = "网易云音乐 > 打碟" self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord("s"): if (datatype == "songs" or datatype == "djchannels") and len(datalist) != 0: self.collection.append(datalist[idx]) if platform.system() == "Darwin": os.system("/usr/bin/osascript -e 'display notification \"Added successfully\"'") else: os.system('/usr/bin/notify-send "Added successfully"') # 加载收藏歌曲 elif key == ord("c"): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = "songs" self.title = "网易云音乐 > 收藏" self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord("r"): if (datatype == "songs" or datatype == "djchannels") and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != "main" and len(datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != "main" and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord("m"): if datatype != "main": self.stack.append([datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord("g"): if datatype == "help": webbrowser.open_new_tab("https://github.com/darknessomi/musicbox") # 开始下载 elif key == ord("C"): s = self.datalist[idx] cache_thread = threading.Thread( target=self.player.cacheSong1time, args=(s["song_id"], s["song_name"], s["artist"], s["mp3_url"]) ) cache_thread.start() elif key == ord("i"): if self.player.playing_id != -1: webbrowser.open_new_tab("http://music.163.com/#/song?id=" + str(self.player.playing_id)) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database["player_info"]["playing_mode"], ) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if datatype == "main": self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == "artists": artist_id = datalist[idx]["artist_id"] songs = netease.artists(artist_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["artists_name"] # 该专辑包含的歌曲 elif datatype == "albums": album_id = datalist[idx]["album_id"] songs = netease.album(album_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["albums_name"] # 精选歌单选项 elif datatype == "playlists": data = self.datalist[idx] self.datatype = data["datatype"] self.datalist = netease.dig_info(data["callback"](), self.datatype) self.title += " > " + data["title"] # 全站置顶歌单包含的歌曲 elif datatype == "top_playlists": log.debug(datalist) playlist_id = datalist[idx]["playlist_id"] songs = netease.playlist_detail(playlist_id) self.datatype = "songs" self.datalist = netease.dig_info(songs, "songs") self.title += " > " + datalist[idx]["playlists_name"] # 分类精选 elif datatype == "playlist_classes": # 分类名称 data = self.datalist[idx] self.datatype = "playlist_class_detail" self.datalist = netease.dig_info(data, self.datatype) self.title += " > " + data log.debug(self.datalist) # 某一分类的详情 elif datatype == "playlist_class_detail": # 子类别 data = self.datalist[idx] self.datatype = "top_playlists" self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += " > " + data # 歌曲榜单 elif datatype == "toplists": songs = netease.top_songlist(idx) self.title += " > " + self.datalist[idx] self.datalist = netease.dig_info(songs, "songs") self.datatype = "songs" # 搜索菜单 elif datatype == "search": ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = "top_playlists" self.datalist = ui.build_search("search_playlist") self.title = "精选歌单搜索列表" elif idx == 1: self.datatype = "songs" self.datalist = ui.build_search("songs") self.title = "歌曲搜索列表" elif idx == 2: self.datatype = "artists" self.datalist = ui.build_search("artists") self.title = "艺术家搜索列表" elif idx == 3: self.datatype = "albums" self.datalist = ui.build_search("albums") self.title = "专辑搜索列表" def show_playing_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return if not self.at_playing_list: self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.at_playing_list = True self.datatype = self.storage.database["player_info"]["player_list_type"] self.title = self.storage.database["player_info"]["player_list_title"] self.datalist = [] for i in self.storage.database["player_info"]["player_list"]: self.datalist.append(self.storage.database["songs"][i]) self.index = self.storage.database["player_info"]["idx"] self.offset = self.storage.database["player_info"]["idx"] / self.step * self.step if self.resume_play: if self.datatype == "fmsongs": self.player.end_callback = self.fm_callback else: self.player.end_callback = None self.storage.database["player_info"]["idx"] = -1 self.player.play_and_pause(self.index) self.resume_play = False def song_changed_callback(self): if self.at_playing_list: self.show_playing_song() def fm_callback(self): log.debug("FM CallBack.") data = self.get_new_fm() self.player.append_songs(data) if self.datatype == "fmsongs": if len(self.storage.database["player_info"]["player_list"]) == 0: return self.datatype = self.storage.database["player_info"]["player_list_type"] self.title = self.storage.database["player_info"]["player_list_title"] self.datalist = [] for i in self.storage.database["player_info"]["player_list"]: self.datalist.append(self.storage.database["songs"][i]) self.index = self.storage.database["player_info"]["idx"] self.offset = self.storage.database["player_info"]["idx"] / self.step * self.step def request_api(self, func, *args): if self.storage.database["user"]["user_id"] != "": result = func(*args) if result != -1: return result log.debug("Re Login.") user_info = {} if self.storage.database["user"]["username"] != "": user_info = self.netease.login( self.storage.database["user"]["username"], self.storage.database["user"]["password"] ) if self.storage.database["user"]["username"] == "" or user_info["code"] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return -1 user_info = data[0] self.storage.database["user"]["username"] = data[1][0] self.storage.database["user"]["password"] = data[1][1] self.storage.database["user"]["user_id"] = user_info["account"]["id"] self.storage.database["user"]["nickname"] = user_info["profile"]["nickname"] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] return func(*args) def get_new_fm(self): myplaylist = [] for count in range(0, 1): data = self.request_api(self.netease.personal_fm) if data == -1: break myplaylist += data time.sleep(0.2) return self.netease.dig_info(myplaylist, "fmsongs") def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += " > 排行榜" self.datatype = "toplists" # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, "artists") self.title += " > 艺术家" self.datatype = "artists" # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, "albums") self.title += " > 新碟上架" self.datatype = "albums" # 精选歌单 elif idx == 3: self.datalist = [ {"title": "全站置顶", "datatype": "top_playlists", "callback": netease.top_playlists}, {"title": "分类精选", "datatype": "playlist_classes", "callback": netease.playlist_classes}, ] self.title += " > 精选歌单" self.datatype = "playlists" # 我的歌单 elif idx == 4: myplaylist = self.request_api(self.netease.user_playlist, self.userid) if myplaylist == -1: return self.datatype = "top_playlists" self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += " > " + self.username + " 的歌单" # DJ节目 elif idx == 5: self.datatype = "djchannels" self.title += " > DJ节目" self.datalist = netease.djchannels() # 每日推荐 elif idx == 6: self.datatype = "songs" self.title += " > 每日推荐" myplaylist = self.request_api(self.netease.recommend_playlist) if myplaylist == -1: return self.datalist = self.netease.dig_info(myplaylist, self.datatype) # 私人FM elif idx == 7: self.datatype = "fmsongs" self.title += " > 私人FM" self.datalist = self.get_new_fm() # 搜索 elif idx == 8: self.datatype = "search" self.title += " > 搜索" self.datalist = ["歌曲", "艺术家", "专辑", "网易精选集"] # 帮助 elif idx == 9: self.datatype = "help" self.title += " > 帮助" self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.config = Config() self.datatype = 'main' self.title = '网易云音乐' self.datalist = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '每日推荐', '私人FM', '搜索', '帮助'] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'][0] self.player = Player() self.player.playing_song_changed_callback = self.song_changed_callback self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] self.resume_play = True self.at_playing_list = False signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def update_alert(self, version): latest = Menu().check_version() if latest != version and latest != 0: if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "MusicBox Update is available"sound name "/System/Library/Sounds/Ping.aiff"\'') time.sleep(0.5) os.system('/usr/bin/osascript -e \'display notification "NetEase-MusicBox installed version:' + version + '\nNetEase-MusicBox latest version:' + latest + '"\'') else: os.system('/usr/bin/notify-send "MusicBox Update is available"') def signin_alert(self, type): if type == 0: if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "Mobile signin success"sound name "/System/Library/Sounds/Ping.aiff"\'') else: os.system('/usr/bin/notify-send "Mobile signin success"') else: if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "PC signin success"sound name "/System/Library/Sounds/Ping.aiff"\'') else: os.system('/usr/bin/notify-send "PC signin success"') def check_version(self): # 检查更新 && 签到 try: mobilesignin = self.netease.daily_signin(0) if mobilesignin != -1 and mobilesignin['code'] != -2: self.signin_alert(0) time.sleep(0.5) pcsignin = self.netease.daily_signin(1) if pcsignin != -1 and pcsignin['code'] != -2: self.signin_alert(1) tree = ET.ElementTree(ET.fromstring(str(self.netease.get_version()))) root = tree.getroot() return root[0][4][0][0].text except: return 0 def start_fork(self, version): pid = os.fork() if pid == 0: Menu().update_alert(version) else: Menu().start() def play_pause(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return if self.player.pause_flag: self.player.resume() else: self.player.pause() time.sleep(0.1) def next_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.next() time.sleep(0.1) def previous_song(self): if len(self.storage.database["player_info"]["player_list"]) == 0: return self.player.prev() time.sleep(0.1) def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar(self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) if bind_global: keybinder.bind(self.config.get_item("global_play_pause"), self.play_pause) keybinder.bind(self.config.get_item("global_next"), self.next_song) keybinder.bind(self.config.get_item("global_previous"), self.previous_song) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() if bind_global: keybinder.gtk.main_iteration(False) self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): break # 退出并清除用户信息 if key == ord('w'): self.storage.database['user'] = { "username": "", "password": "", "user_id": "", "nickname": "", } try: os.remove(self.storage.cookie_path) except: break break # 上移 elif key == ord('k'): # turn page if at beginning if idx == offset: if offset == 0: continue self.offset -= step # 移动光标到最后一列 self.index = offset - 1 else: self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): # turn page if at end if idx == min( len(datalist), offset + step) - 1: if offset + step >= len( datalist ): continue self.offset += step # 移动光标到第一列 self.index = offset + step else: self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help' or len(self.datalist) <= 0: continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] self.at_playing_list = False # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): self.next_song() # 播放上一曲 elif key == ord('['): self.previous_song() # 增加音量 elif key == ord('='): self.player.volume_up() # 减少音量 elif key == ord('-'): self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.shuffle() time.sleep(0.1) # 喜爱 elif key == ord(','): return_data = self.request_api(self.netease.fm_like, self.player.get_playing_id()) if return_data != -1: if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "Added successfully"\'') else: os.system('/usr/bin/notify-send "Added successfully"') # 删除FM elif key == ord('.'): if self.datatype == 'fmsongs': if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() return_data = self.request_api(self.netease.fm_trash, self.player.get_playing_id()) if return_data != -1: if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "Deleted successfully"\'') else: os.system('/usr/bin/notify-send "Deleted successfully"') time.sleep(0.1) # 下一FM elif key == ord('/'): if self.datatype == 'fmsongs': if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): # If not open a new playing list, just play and pause. try: if self.datalist[idx]['song_id'] == self.player.playing_id: self.player.play_and_pause(self.storage.database['player_info']['idx']) time.sleep(0.1) continue except: pass # If change to a new playing list. Add playing list and play. if datatype == 'songs': self.resume_play = False self.player.new_player_list('songs', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'djchannels': self.resume_play = False self.player.new_player_list('djchannels', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'fmsongs': self.resume_play = False self.storage.database['player_info']['playing_mode'] = 0 self.player.new_player_list('fmsongs', self.title, self.datalist, -1) self.player.end_callback = self.fm_callback self.player.play_and_pause(idx) self.at_playing_list = True else: self.player.play_and_pause(self.storage.database['player_info']['idx']) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): self.show_playing_song() # 播放模式切换 elif key == ord('P'): self.storage.database['player_info']['playing_mode'] = \ (self.storage.database['player_info']['playing_mode'] + 1) % 5 # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) if platform.system() == 'Darwin': os.system('/usr/bin/osascript -e \'display notification "Added successfully"\'') else: os.system('/usr/bin/notify-send "Added successfully"') # 加载收藏歌曲 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != 'main' and len(datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append([datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab('https://github.com/darknessomi/musicbox') # 开始下载 elif key == ord("C"): s = self.datalist[idx] cache_thread = threading.Thread(target=self.player.cacheSong1time, args=( s['song_id'], s['song_name'], s['artist'], s['mp3_url'])) cache_thread.start() elif key == ord('i'): if self.player.playing_id != -1: webbrowser.open_new_tab('http://music.163.com/#/song?id=' + str(self.player.playing_id)) self.ui.build_process_bar(self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if idx > len(self.datalist): return False if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data log.debug(self.datalist) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' def show_playing_song(self): if len(self.storage.database['player_info']['player_list']) == 0: return if not self.at_playing_list: self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.at_playing_list = True self.datatype = self.storage.database['player_info']['player_list_type'] self.title = self.storage.database['player_info']['player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info']['idx'] / self.step * self.step if self.resume_play: if self.datatype == "fmsongs": self.player.end_callback = self.fm_callback else: self.player.end_callback = None self.storage.database['player_info']['idx'] = -1 self.player.play_and_pause(self.index) self.resume_play = False def song_changed_callback(self): if self.at_playing_list: self.show_playing_song() def fm_callback(self): log.debug("FM CallBack.") data = self.get_new_fm() self.player.append_songs(data) if self.datatype == 'fmsongs': if len(self.storage.database['player_info']['player_list']) == 0: return self.datatype = self.storage.database['player_info']['player_list_type'] self.title = self.storage.database['player_info']['player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info']['idx'] / self.step * self.step def request_api(self, func, *args): if self.storage.database['user']['user_id'] != "": result = func(*args) if result != -1: return result log.debug("Re Login.") user_info = {} if self.storage.database['user']['username'] != "": user_info = self.netease.login(self.storage.database['user']['username'], self.storage.database['user']['password']) if self.storage.database['user']['username'] == "" or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return -1 user_info = data[0] self.storage.database['user']['username'] = data[1][0] self.storage.database['user']['password'] = data[1][1] self.storage.database['user']['user_id'] = user_info['account']['id'] self.storage.database['user']['nickname'] = user_info['profile']['nickname'] self.userid = self.storage.database["user"]["user_id"] self.username = self.storage.database["user"]["nickname"] return func(*args) def get_new_fm(self): myplaylist = [] for count in range(0, 1): data = self.request_api(self.netease.personal_fm) if data == -1: break myplaylist += data time.sleep(0.2) return self.netease.dig_info(myplaylist, "fmsongs") def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [ { 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes } ] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: myplaylist = self.request_api(self.netease.user_playlist, self.userid) if myplaylist == -1: return self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 每日推荐 elif idx == 6: self.datatype = 'songs' self.title += ' > 每日推荐' myplaylist = self.request_api(self.netease.recommend_playlist) if myplaylist == -1: return self.datalist = self.netease.dig_info(myplaylist, self.datatype) # 私人FM elif idx == 7: self.datatype = 'fmsongs' self.title += ' > 私人FM' self.datalist = self.get_new_fm() # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > 搜索' self.datalist = ['歌曲', '艺术家', '专辑', '网易精选集'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.datatype = 'main' self.title = '网易云音乐' self.datalist = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助'] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'][0] self.player = Player() self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = None self.username = None self.resume_play = True signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar(self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack self.screen.timeout(500) key = self.screen.getch() self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): break # 退出并清除用户信息 if key == ord('w'): self.storage.database['user'] = { "username": "", "password": "", } break # 上移 elif key == ord('k'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord('['): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.prev() time.sleep(0.1) # 增加音量 elif key == ord('='): self.player.volume_up() # 减少音量 elif key == ord('-'): self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.storage.database["player_info"]["player_list"]) == 0: continue self.player.shuffle() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): try: if self.datalist[idx] == self.storage.database["songs"][str(self.player.playing_id)]: self.player.play_and_pause(self.storage.database['player_info']['idx']) time.sleep(0.1) continue except: pass if datatype == 'songs': self.resume_play = False self.player.new_player_list('songs', self.title, self.datalist, -1) self.player.play_and_pause(idx) elif datatype == 'djchannels': self.resume_play = False self.player.new_player_list('djchannels', self.title, self.datalist, -1) self.player.play_and_pause(idx) else: self.player.play_and_pause(self.storage.database['player_info']['idx']) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.storage.database['player_info']['player_list']) == 0: continue self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.datatype = self.storage.database['player_info']['player_list_type'] self.title = self.storage.database['player_info']['player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info']['idx'] / self.step * self.step if self.resume_play: self.storage.database['player_info']['idx'] = -1 self.player.play_and_pause(self.index) self.resume_play = False # 播放模式切换 elif key == ord('P'): self.storage.database['player_info']['playing_mode'] = \ (self.storage.database['player_info']['playing_mode'] + 1) % 5 # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) # 加载收藏歌曲 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if datatype != 'main' and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord("J"): if datatype != 'main' and len(datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord("K"): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append([datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab('https://github.com/darknessomi/musicbox') self.ui.build_process_bar(self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data log.debug(self.datalist) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui # no need to do stack.append, Otherwise there will be a bug when you input key 'h' to return # if idx in range(1, 5): # self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [ { 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes } ] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.storage.database['user']['username'] != "": user_info = netease.login(self.storage.database['user']['username'], self.storage.database['user']['password']) # 本地没有存储账户,或本地账户失效,则引导录入 if self.storage.database['user']['username'] == "" or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.storage.database['user']['username'] = data[1][0] self.storage.database['user']['password'] = data[1][1] self.username = user_info['profile']['nickname'] self.userid = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist(self.userid) self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = 'songs' self.title += ' > 打碟' self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = 'songs' self.title += ' > 收藏' self.datalist = self.collection # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > 搜索' self.datalist = ['歌曲', '艺术家', '专辑', '网易精选集'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.config = Config() self.datatype = 'main' self.title = '网易云音乐' self.datalist = [ '排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', '主播电台', '每日推荐', '私人FM', '搜索', '帮助' ] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'][0] self.player = Player() self.player.playing_song_changed_callback = self.song_changed_callback self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = self.storage.database['user']['user_id'] self.username = self.storage.database['user']['nickname'] self.resume_play = True self.at_playing_list = False signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def update_alert(self, version): latest = Menu().check_version() if latest != version and latest != 0: notify('MusicBox Update is available', 1) time.sleep(0.5) notify( 'NetEase-MusicBox installed version:' + version + '\nNetEase-MusicBox latest version:' + latest, 0) def check_version(self): # 检查更新 && 签到 try: mobilesignin = self.netease.daily_signin(0) if mobilesignin != -1 and mobilesignin['code'] != -2: notify('Mobile signin success', 1) time.sleep(0.5) pcsignin = self.netease.daily_signin(1) if pcsignin != -1 and pcsignin['code'] != -2: notify('PC signin success', 1) tree = ET.ElementTree( ET.fromstring(str(self.netease.get_version()))) root = tree.getroot() return root[0][4][0][0].text except TypeError as e: log.error(e) return 0 def start_fork(self, version): pid = os.fork() if pid == 0: Menu().update_alert(version) else: Menu().start() def play_pause(self): if len(self.storage.database['player_info']['player_list']) == 0: return if self.player.pause_flag: self.player.resume() else: self.player.pause() time.sleep(0.1) def next_song(self): if len(self.storage.database['player_info']['player_list']) == 0: return self.player.next() time.sleep(0.1) def previous_song(self): if len(self.storage.database['player_info']['player_list']) == 0: return self.player.prev() time.sleep(0.1) # 全局加星歌曲 def star_song(self): return_data = self.request_api(self.netease.fm_like, self.player.get_playing_id()) if return_data != -1: notify("Added successfully!", 0) else: notify("Existing song!", 0) def bind_keys(self): if bind_global: keybinder.bind(self.config.get_item('global_play_pause'), self.play_pause) keybinder.bind(self.config.get_item('global_next'), self.next_song) keybinder.bind(self.config.get_item('global_previous'), self.previous_song) keybinder.bind(self.config.get_item('global_star'), self.star_song) def unbind_keys(self): if bind_global: keybinder.unbind(self.config.get_item('global_play_pause')) keybinder.unbind(self.config.get_item('global_next')) keybinder.unbind(self.config.get_item('global_previous')) keybinder.unbind(self.config.get_item('global_star')) def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.stack.append([ self.datatype, self.title, self.datalist, self.offset, self.index ]) if bind_global: try: self.bind_keys() except KeyError as e: log.warning(e) show_lyrics_new_process() while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack self.screen.timeout(500) key = self.screen.getch() if bind_global: keybinder.gtk.main_iteration(False) self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): try: self.unbind_keys() except KeyError as e: log.warning(e) break # 退出并清除用户信息 if key == ord('w'): self.storage.database['user'] = { 'username': '', 'password': '', 'user_id': '', 'nickname': '', } try: os.remove(self.storage.cookie_path) except OSError as e: log.error(e) break break # 上移 elif key == ord('k'): # turn page if at beginning if idx == offset: if offset == 0: continue self.offset -= step # 移动光标到最后一列 self.index = offset - 1 else: self.index = carousel( offset, min(len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): # turn page if at end if idx == min(len(datalist), offset + step) - 1: if offset + step >= len(datalist): continue self.offset += step # 移动光标到第一列 self.index = offset + step else: self.index = carousel( offset, min(len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == ('songs', 'djchannels', 'help'): continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == ('songs', 'djchannels', 'help') or len(self.datalist) <= 0: continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] self.at_playing_list = False # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): self.next_song() # 播放上一曲 elif key == ord('['): self.previous_song() # 增加音量 elif key == ord('='): self.player.volume_up() # 减少音量 elif key == ord('-'): self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.storage.database['player_info'] ['player_list']) == 0: continue self.player.shuffle() time.sleep(0.1) # 喜爱 elif key == ord(','): return_data = self.request_api(self.netease.fm_like, self.player.get_playing_id()) if return_data != -1: notify('Added successfully!', 0) else: notify('Existing song!', 0) # 删除FM elif key == ord('.'): if self.datatype == 'fmsongs': if len(self.storage.database['player_info'] ['player_list']) == 0: continue self.player.next() return_data = self.request_api( self.netease.fm_trash, self.player.get_playing_id()) if return_data != -1: notify('Deleted successfully!', 0) time.sleep(0.1) # 下一FM elif key == ord('/'): if self.datatype == 'fmsongs': if len(self.storage.database['player_info'] ['player_list']) == 0: continue self.player.next() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): # If not open a new playing list, just play and pause. try: if self.datalist[idx]['song_id'] == self.player.playing_id: self.player.play_and_pause( self.storage.database['player_info']['idx']) time.sleep(0.1) continue except (TypeError, KeyError) as e: log.error(e) pass # If change to a new playing list. Add playing list and play. if datatype == 'songs': self.resume_play = False self.player.new_player_list('songs', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'djchannels': self.resume_play = False self.player.new_player_list('djchannels', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'fmsongs': self.resume_play = False self.storage.database['player_info']['playing_mode'] = 0 self.player.new_player_list('fmsongs', self.title, self.datalist, -1) self.player.end_callback = self.fm_callback self.player.play_and_pause(idx) self.at_playing_list = True else: self.player.play_and_pause( self.storage.database['player_info']['idx']) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): self.show_playing_song() # 播放模式切换 elif key == ord('P'): self.storage.database['player_info']['playing_mode'] = ( self.storage.database['player_info']['playing_mode'] + 1) % 5 # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到本地收藏 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) notify('Added successfully', 0) # 加载本地收藏 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 本地收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel( offset, min(len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord('J'): if datatype != 'main' and len( datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord('K'): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab( 'https://github.com/darknessomi/musicbox') # 开始下载 elif key == ord('C'): s = self.datalist[idx] cache_thread = threading.Thread( target=self.player.cacheSong1time, args=(s['song_id'], s['song_name'], s['artist'], s['mp3_url'])) cache_thread.start() elif key == ord('i'): if self.player.playing_id != -1: webbrowser.open_new_tab('http://music.163.com/#/song?id=' + str(self.player.playing_id)) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if idx > len(self.datalist): return False if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' def show_playing_song(self): if len(self.storage.database['player_info']['player_list']) == 0: return if not self.at_playing_list: self.stack.append([ self.datatype, self.title, self.datalist, self.offset, self.index ]) self.at_playing_list = True self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info']['player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step if self.resume_play: if self.datatype == 'fmsongs': self.player.end_callback = self.fm_callback else: self.player.end_callback = None self.storage.database['player_info']['idx'] = -1 self.player.play_and_pause(self.index) self.resume_play = False def song_changed_callback(self): if self.at_playing_list: self.show_playing_song() def fm_callback(self): log.debug('FM CallBack.') data = self.get_new_fm() self.player.append_songs(data) if self.datatype == 'fmsongs': if len(self.storage.database['player_info']['player_list']) == 0: return self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info'][ 'player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step def request_api(self, func, *args): if self.storage.database['user']['user_id'] != '': result = func(*args) if result != -1: return result log.debug('Re Login.') user_info = {} if self.storage.database['user']['username'] != '': user_info = self.netease.login( self.storage.database['user']['username'], self.storage.database['user']['password']) if self.storage.database['user'][ 'username'] == '' or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return -1 user_info = data[0] self.storage.database['user']['username'] = data[1][0] self.storage.database['user']['password'] = data[1][1] self.storage.database['user']['user_id'] = user_info['account'][ 'id'] self.storage.database['user']['nickname'] = user_info['profile'][ 'nickname'] self.userid = self.storage.database['user']['user_id'] self.username = self.storage.database['user']['nickname'] return func(*args) def get_new_fm(self): myplaylist = [] for count in range(0, 1): data = self.request_api(self.netease.personal_fm) if data == -1: break myplaylist += data time.sleep(0.2) return self.netease.dig_info(myplaylist, 'fmsongs') def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [{ 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes }] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: myplaylist = self.request_api(self.netease.user_playlist, self.userid) if myplaylist == -1: return self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # 主播电台 elif idx == 5: self.datatype = 'djchannels' self.title += ' > 主播电台' self.datalist = netease.djchannels() # 每日推荐 elif idx == 6: self.datatype = 'songs' self.title += ' > 每日推荐' myplaylist = self.request_api(self.netease.recommend_playlist) if myplaylist == -1: return self.datalist = self.netease.dig_info(myplaylist, self.datatype) # 私人FM elif idx == 7: self.datatype = 'fmsongs' self.title += ' > 私人FM' self.datalist = self.get_new_fm() # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > 搜索' self.datalist = ['歌曲', '艺术家', '专辑', '网易精选集'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu(object): def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.config = Config() self.datatype = 'main' self.title = 'NetEase Music' self.datalist = ['Charts', 'Artists', 'New Songs', 'Songs', 'My Songs', 'Radio Stations', 'Recommended', 'Personal Radio', 'Search', 'Help'] self.offset = 0 self.index = 0 self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'][0] self.player = Player() self.player.playing_song_changed_callback = self.song_changed_callback self.cache = Cache() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = self.storage.database['user']['user_id'] self.username = self.storage.database['user']['nickname'] self.resume_play = True self.at_playing_list = False signal.signal(signal.SIGWINCH, self.change_term) signal.signal(signal.SIGINT, self.send_kill) self.START = time.time() def change_term(self, signum, frame): self.ui.screen.clear() self.ui.screen.refresh() def send_kill(self, signum, fram): self.player.stop() self.cache.quit() self.storage.save() curses.endwin() sys.exit() def update_alert(self, version): latest = Menu().check_version() if latest != version and latest != 0: notify('MusicBox Update is available', 1) time.sleep(0.5) notify('NetEase-MusicBox installed version:' + version + '\nNetEase-MusicBox latest version:' + latest, 0) def check_version(self): # 检查更新 && 签到 try: mobilesignin = self.netease.daily_signin(0) if mobilesignin != -1 and mobilesignin['code'] != -2: notify('Mobile signin success', 1) time.sleep(0.5) pcsignin = self.netease.daily_signin(1) if pcsignin != -1 and pcsignin['code'] != -2: notify('PC signin success', 1) tree = ET.ElementTree(ET.fromstring(str(self.netease.get_version( )))) root = tree.getroot() return root[0][4][0][0].text except TypeError as e: log.error(e) return 0 def start_fork(self, version): pid = os.fork() if pid == 0: Menu().update_alert(version) else: Menu().start() def _is_playlist_empty(self): return len(self.storage.database['player_info']['player_list']) == 0 def play_pause(self): if self._is_playlist_empty(): return if self.player.pause_flag: self.player.resume() else: self.player.pause() time.sleep(0.1) def next_song(self): if self._is_playlist_empty(): return self.player.next() time.sleep(0.5) def previous_song(self): if self._is_playlist_empty(): return self.player.prev() time.sleep(0.5) def bind_keys(self): if BINDABLE: keybinder.bind( self.config.get_item('global_play_pause'), self.play_pause) keybinder.bind(self.config.get_item('global_next'), self.next_song) keybinder.bind( self.config.get_item('global_previous'), self.previous_song) def unbind_keys(self): if BINDABLE: keybinder.unbind(self.config.get_item('global_play_pause')) keybinder.unbind(self.config.get_item('global_next')) keybinder.unbind(self.config.get_item('global_previous')) def start(self): self.START = time.time() // 1 self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) try: self.bind_keys() except KeyError as e: log.warning(e) show_lyrics_new_process() while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack self.screen.timeout(500) key = self.screen.getch() if BINDABLE: keybinder.gtk.main_iteration(False) self.ui.screen.refresh() # term resize if key == -1: self.ui.update_size() self.player.update_size() # 退出 if key == ord('q'): try: self.unbind_keys() except KeyError as e: log.warning(e) break # 退出并清除用户信息 if key == ord('w'): self.storage.database['user'] = { 'username': '', 'password': '', 'user_id': '', 'nickname': '', } try: os.remove(self.storage.cookie_path) except OSError as e: log.error(e) break break # 上移 elif key == ord('k'): # turn page if at beginning if idx == offset: if offset == 0: continue self.offset -= step # 移动光标到最后一列 self.index = offset - 1 else: self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx - 1) self.START = time.time() # 下移 elif key == ord('j'): # turn page if at end if idx == min(len(datalist), offset + step) - 1: if offset + step >= len(datalist): continue self.offset += step # 移动光标到第一列 self.index = offset + step else: self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx + 1) self.START = time.time() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == ('songs', 'djchannels', 'help'): continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step, self.START) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.START = time.time() self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index - step) // step * step # 向下翻页 elif key == ord('d'): if offset + step >= len(datalist): continue self.START = time.time() self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index + step) // step * step # 前进 elif key == ord('l') or key == 10: if self.datatype == ('songs', 'djchannels', 'help') or len(self.datalist) <= 0: continue self.START = time.time() self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue self.START = time.time() up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] self.at_playing_list = False # 搜索 elif key == ord('f'): # 8 is the 'search' menu self.dispatch_enter(8) # 播放下一曲 elif key == ord(']'): self.next_song() # 播放上一曲 elif key == ord('['): self.previous_song() # 增加音量 elif key == ord('='): self.player.volume_up() # 减少音量 elif key == ord('-'): self.player.volume_down() # 随机播放 elif key == ord('?'): if len(self.storage.database['player_info'][ 'player_list']) == 0: continue self.player.shuffle() time.sleep(0.1) # 喜爱 elif key == ord(','): return_data = self.request_api(self.netease.fm_like, self.player.get_playing_id()) if return_data != -1: notify('Added successfully!', 0) else: notify('Existing song!', 0) # 删除FM elif key == ord('.'): if self.datatype == 'fmsongs': if len(self.storage.database['player_info'][ 'player_list']) == 0: continue self.player.next() return_data = self.request_api( self.netease.fm_trash, self.player.get_playing_id()) if return_data != -1: notify('Deleted successfully!', 0) time.sleep(0.1) # 下一FM elif key == ord('/'): if self.datatype == 'fmsongs': if len(self.storage.database['player_info'][ 'player_list']) == 0: continue if self.player.end_callback: self.player.end_callback() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): # If not open a new playing list, just play and pause. try: if self.datalist[idx]['song_id'] == self.player.playing_id: self.player.play_and_pause(self.storage.database[ 'player_info']['idx']) time.sleep(0.1) continue except (TypeError, KeyError) as e: log.error(e) pass # If change to a new playing list. Add playing list and play. if datatype == 'songs': self.resume_play = False self.player.new_player_list('songs', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'djchannels': self.resume_play = False self.player.new_player_list('djchannels', self.title, self.datalist, -1) self.player.end_callback = None self.player.play_and_pause(idx) self.at_playing_list = True elif datatype == 'fmsongs': self.resume_play = False self.storage.database['player_info']['playing_mode'] = 0 self.player.new_player_list('fmsongs', self.title, self.datalist, -1) self.player.end_callback = self.fm_callback self.player.play_and_pause(idx) self.at_playing_list = True else: self.player.play_and_pause(self.storage.database[ 'player_info']['idx']) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): self.show_playing_song() # 播放模式切换 elif key == ord('P'): self.storage.database['player_info']['playing_mode'] = ( self.storage.database['player_info']['playing_mode'] + 1) % 5 # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append(datalist[idx]) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到本地收藏 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append(datalist[idx]) notify('Added successfully', 0) # 加载本地收藏 elif key == ord('c'): self.stack.append([datatype, title, datalist, offset, index]) self.datatype = 'songs' self.title = 'NetEase Music > Local Music' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx) # 当前项目下移 elif key == ord('J'): if datatype != 'main' and len( datalist) != 0 and idx + 1 != len(self.datalist): self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx + 1, song) self.index = idx + 1 # 翻页 if self.index >= offset + step: self.offset = offset + step # 当前项目上移 elif key == ord('K'): if datatype != 'main' and len(datalist) != 0 and idx != 0: self.START = time.time() song = self.datalist.pop(idx) self.datalist.insert(idx - 1, song) self.index = idx - 1 # 翻页 if self.index < offset: self.offset = offset - step elif key == ord('m'): if datatype != 'main': self.stack.append([datatype, title, datalist, offset, index ]) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab( 'https://github.com/darknessomi/musicbox') # 开始下载 elif key == ord('C'): s = self.datalist[idx] cache_thread = threading.Thread( target=self.player.cacheSong1time, args=(s['song_id'], s['song_name'], s['artist'], s[ 'mp3_url'])) cache_thread.start() elif key == ord('i'): if self.player.playing_id != -1: webbrowser.open_new_tab('http://music.163.com/#/song?id=' + str(self.player.playing_id)) self.ui.build_process_bar( self.player.process_location, self.player.process_length, self.player.playing_flag, self.player.pause_flag, self.storage.database['player_info']['playing_mode']) self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step, self.START) self.player.stop() self.cache.quit() self.storage.save() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append([datatype, title, datalist, offset, index]) if idx > len(self.datalist): return False if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info( netease.top_playlists(data), self.datatype) self.title += ' > ' + data # 歌曲榜单 elif datatype == 'toplists': songs = netease.top_songlist(idx) self.title += ' > ' + self.datalist[idx] self.datalist = netease.dig_info(songs, 'songs') self.datatype = 'songs' # 搜索菜单 elif datatype == 'search': ui = self.ui self.index = 0 self.offset = 0 if idx == 0: # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = 'Playlist Search' elif idx == 1: self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = 'Song Search' elif idx == 2: self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = 'Artist Search' elif idx == 3: self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = 'Album Search' def show_playing_song(self): if self._is_playlist_empty(): return if not self.at_playing_list: self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.at_playing_list = True self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info']['player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step if self.resume_play: if self.datatype == 'fmsongs': self.player.end_callback = self.fm_callback else: self.player.end_callback = None self.storage.database['player_info']['idx'] = -1 self.player.play_and_pause(self.index) self.resume_play = False def song_changed_callback(self): if self.at_playing_list: self.show_playing_song() def fm_callback(self): log.debug('FM CallBack.') data = self.get_new_fm() self.player.append_songs(data) if self.datatype == 'fmsongs': if self._is_playlist_empty(): return self.datatype = self.storage.database['player_info'][ 'player_list_type'] self.title = self.storage.database['player_info'][ 'player_list_title'] self.datalist = [] for i in self.storage.database['player_info']['player_list']: self.datalist.append(self.storage.database['songs'][i]) self.index = self.storage.database['player_info']['idx'] self.offset = self.storage.database['player_info'][ 'idx'] / self.step * self.step def request_api(self, func, *args): if self.storage.database['user']['user_id'] != '': result = func(*args) if result != -1: return result log.debug('Re Login.') user_info = {} if self.storage.database['user']['username'] != '': user_info = self.netease.login( self.storage.database['user']['username'], self.storage.database['user']['password']) if self.storage.database['user']['username'] == '' or user_info[ 'code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return -1 user_info = data[0] self.storage.database['user']['username'] = data[1][0] self.storage.database['user']['password'] = data[1][1] self.storage.database['user']['user_id'] = user_info['account'][ 'id'] self.storage.database['user']['nickname'] = user_info['profile'][ 'nickname'] self.userid = self.storage.database['user']['user_id'] self.username = self.storage.database['user']['nickname'] return func(*args) def get_new_fm(self): myplaylist = [] for count in range(0, 1): data = self.request_api(self.netease.personal_fm) if data == -1: break myplaylist += data time.sleep(0.2) return self.netease.dig_info(myplaylist, 'fmsongs') def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: self.datalist = netease.return_toplists() self.title += ' > Charts' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > Artists' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > Albums' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [ { 'title': 'Top Playlists', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': 'Playlists (By Category)', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes } ] self.title += ' > Playlists' self.datatype = 'playlists' # 我的歌单 elif idx == 4: myplaylist = self.request_api(self.netease.user_playlist, self.userid) if myplaylist == -1: return self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # 主播电台 elif idx == 5: self.datatype = 'djchannels' self.title += ' > Radio Stations' self.datalist = netease.djchannels() # 每日推荐 elif idx == 6: self.datatype = 'songs' self.title += ' > Songs' myplaylist = self.request_api(self.netease.recommend_playlist) if myplaylist == -1: return self.datalist = self.netease.dig_info(myplaylist, self.datatype) # 私人FM elif idx == 7: self.datatype = 'fmsongs' self.title += ' > Personal Radio' self.datalist = self.get_new_fm() # 搜索 elif idx == 8: self.datatype = 'search' self.title += ' > Search' self.datalist = ['Songs', 'Artists', 'Albums', 'Playlists'] # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > Help' self.datalist = shortcut self.offset = 0 self.index = 0
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.datatype = 'main' self.title = '网易云音乐' self.datalist = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助'] self.offset = 0 self.index = 0 self.presentsongs = [] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = None self.username = None try: sfile = file(home + "/netease-musicbox/flavor.json",'r') data = json.loads(sfile.read()) self.collection = data['collection'] self.account = data['account'] sfile.close() except: self.collection = [] self.account = {} def start(self): self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset idx = index = self.index step = self.step stack = self.stack djstack = self.djstack key = self.screen.getch() self.ui.screen.refresh() # 退出 if key == ord('q'): break # 上移 elif key == ord('k'): self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx-1 ) # 下移 elif key == ord('j'): self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx+1 ) # 向上翻页 elif key == ord('u'): if offset == 0: continue self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index-step)//step*step # 向下翻页 elif key == ord('d'): if offset + step >= len( datalist ): continue self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index+step)//step*step # 前进 elif key == ord('l') or key == 10: if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 回退 elif key == ord('h'): # if not main menu if len(self.stack) == 1: continue up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord('f'): self.search() # 播放下一曲 elif key == ord(']'): self.player.next() time.sleep(0.1) # 播放上一曲 elif key == ord('['): self.player.prev() time.sleep(0.1) # 播放、暂停 elif key == ord(' '): if datatype == 'songs': self.presentsongs = ['songs', title, datalist, offset, index] elif datatype == 'djchannels': self.presentsongs = ['djchannels', title, datalist, offset, index] self.player.play(datatype, datalist, idx) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.presentsongs) == 0: continue self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.presentsongs[0] self.title = self.presentsongs[1] self.datalist = self.presentsongs[2] self.offset = self.presentsongs[3] self.index = self.presentsongs[4] # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append( datalist[idx] ) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append( datalist[idx] ) # 加载收藏歌曲 elif key == ord('c'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if datatype != 'main' and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx ) elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': webbrowser.open_new_tab('https://github.com/vellow/NetEase-MusicBox') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.player.stop() sfile = file(home + "/netease-musicbox/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection } sfile.write(json.dumps(data)) sfile.close() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append( [datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 该歌单包含的歌曲 elif datatype == 'playlists': playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: songs = netease.top_songlist() self.datalist = netease.dig_info(songs, 'songs') self.title += ' > 排行榜' self.datatype = 'songs' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: playlists = netease.top_playlists() self.datalist = netease.dig_info(playlists, 'playlists') self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.account: user_info = netease.login(self.account[0], self.account[1]) # 本地没有存储账户,或本地账户失效,则引导录入 if self.account == {} or user_info['code'] != 200: data = self.ui.build_login() # 取消登录 if data == -1: return user_info = data[0] self.account = data[1] self.username = user_info['profile']['nickname'] self.userid = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist( self.userid ) self.datalist = netease.dig_info(myplaylist, 'playlists') self.datatype = 'playlists' self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = 'songs' self.title += ' > 打碟' self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = 'songs' self.title += ' > 收藏' self.datalist = self.collection # 搜索 elif idx == 8: self.search() # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0 def search(self): ui = self.ui x = ui.build_search_menu() # if do search, push current info into stack if x in range(ord('1'), ord('5')): self.stack.append( [self.datatype, self.title, self.datalist, self.offset, self.index ]) self.index = 0 self.offset = 0 if x == ord('1'): self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif x == ord('2'): self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif x == ord('3'): self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' elif x == ord('4'): self.datatype = 'playlists' self.datalist = ui.build_search('playlists') self.title = '精选歌单搜索列表'
class Menu: def __init__(self): reload(sys) sys.setdefaultencoding('UTF-8') self.datatype = 'main' self.title = '网易云音乐' self.datalist = ['排行榜', '艺术家', '新碟上架', '精选歌单', '我的歌单', 'DJ节目', '打碟', '收藏', '搜索', '帮助'] self.offset = 0 self.index = 0 self.presentsongs = [] self.player = Player() self.ui = Ui() self.netease = NetEase() self.screen = curses.initscr() self.screen.keypad(1) self.step = 10 self.stack = [] self.djstack = [] self.userid = None self.username = None self.play_show_flag=False #定时器用,跳到播放歌曲 self.interrupt_handler=None self.delay=10 self.play_p=False #歌曲播放标记 self.kill_p=0 #kill线程标记 self.run_p=False #定时运行标记 self.index_c=False #定时完成标志 self.key=[None,None] #存储按键值及按键时的时间 self.next=False #下一曲切换标记 self.play_time_str='0' self.play_time_str_p=True #获取播放时间进程标记 self.play_length_str='0' #歌曲总长度 self.idx_idx=-1 #get_play_*函数用,保存上一个歌曲序列 self.mplayer_start_finished=False #mplayer获取歌曲完成标志 self.bar_p=False try: sfile = file(Constant.conf_dir + "/flavor.json",'r') data = json.loads(sfile.read()) self.collection = data['collection'] self.account = data['account'] sfile.close() except: self.collection = [] self.account = {} def interrupt_delay(self,delay=30): #定时中断`` self.play_p=self.player.return_idx()[1] self.delay=delay if (self.datatype=='songs' or self.datatype=='djchannels') and self.play_p: #if self.kill_p==False : # self.interrupt_stop() while self.run_p : self.kill_p=1 time.sleep(0.02) self.play_show_flag=True self.popen_interrupt() def popen_interrupt(self): #创建定时进程 def runThread(): #d_num='sleep '+str(self.delay) #self.interrupt_handler=subprocess.Popen(['sleep',10]) self.play_show_flag=False self.run_p=True number=int(self.delay/0.05) for i in range(number): time.sleep(0.05) if self.kill_p==1: self.kill_p=0 self.play_show_flag=True break if i==number-1: self.index_c=True self.index=self.player.return_idx()[0] self.offset=self.index//self.step*self.step time.sleep(0.2) # self.index_c=False self.return_play_list() self.ui.build_menu(self.datatype,self.title,self.datalist,self.offset,self.index,self.step) self.ui.progress_bar(self.play_time_str,self.play_length_str) #self.interrupt_handler.wait() #self.index=self.player.return_idx()[0] self.kill_p=0 self.run_p=False if self.play_show_flag: self.thread=threading.Thread(target=runThread) self.thread.setDaemon(True) self.thread.start() def key_m(self): def run_key(): self.key[0]=self.screen.getch() self.key[1]=time.time() th=threading.Thread(target=run_key,name='keyboard_1') th.setDaemon(True) th.start() def return_play_list(self): #返回播放当前播放列表 self.datatype=self.presentsongs[0] self.title=self.presentsongs[1] self.datalist=self.presentsongs[2] self.index=self.player.return_idx()[0] self.offset=self.index//self.step*self.step def get_play_time(self): #获取以播放时间 def run_time(): try: if self.idx_idx==self.player.return_idx()[0]: self.play_time_str=self.player.get_time_pos() time.sleep(0.1) else: self.idx_idx=self.player.return_idx()[0] self.play_time_str_p=True except: self.play_time_str_p=True t=threading.Thread(target=run_time) t.setDaemon(True) t.start() def get_play_length(self): #获取歌曲总长度 def run_length(): try: self.play_length_str=self.player.get_time_length() time.sleep(0.1) except: pass tl=threading.Thread(target=run_length) tl.setDaemon(True) tl.start() def progress_line(self): try: self.play_length_str=self.player.get_time_length() time.sleep(0.1) #time.sleep(0.1) if float(self.play_length_str)>=1: #self.get_play_time() try: if self.idx_idx==self.player.return_idx()[0]: self.play_time_str=self.player.get_time_pos() #time.sleep(0.1) else: self.idx_idx=self.player.return_idx()[0] self.play_time_str_p=True except: self.play_time_str_p=True self.ui.progress_bar(self.play_time_str,self.play_length_str) except: pass def s_n(self): #更新音乐播放进度及下一曲光标更随 def run_s(): index=0 #保存上一个歌曲序列 while True: try: if index!=self.player.return_idx()[0] and self.datatype in ['songs','djchannels'] and self.player.return_idx()[1]: self.index=self.player.return_idx()[0] index=self.index#播放歌曲序列 self.offset=self.index//self.step*self.step self.ui.build_menu(self.datatype,self.title,self.datalist,self.offset,self.index,self.step) self.ui.progress_bar(self.play_time_str,self.play_length_str) self.ui.screen.refresh() elif self.player.return_idx()[1] and self.bar_p==False: self.progress_line() time.sleep(0.89) except: pass progress=threading.Thread(target=run_s) progress.setDaemon(True) progress.start() def start(self): self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.stack.append([self.datatype, self.title, self.datalist, self.offset, self.index]) self.s_n() while True: datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset #idx = index = self.index step = self.step stack = self.stack djstack = self.djstack curses.flushinp() key = self.screen.getch() idx = index = self.index #self.key_m() #self.next=self.player.return_idx()[2] if not datatype in ['songs','djchannels']: self.kill_p=1 #不在播放列表songs or djchannels,不跳转 else: self.kill_p=0 self.ui.screen.refresh() # 退出 if key == ord('q'): #self.kill_p=1 #结束循环 break # 上移 elif key == ord('k') or key== curses.KEY_UP: #↑ self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx-1 ) self.interrupt_delay() # 下移 elif key == ord('j') or key==curses.KEY_DOWN: #↓ self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx+1 ) self.interrupt_delay() # 数字快捷键 elif ord('0') <= key <= ord('9'): if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue idx = key - ord('0') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, idx, self.step) self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 # 向上翻页 elif key == ord('u'): if offset == 0: continue self.offset -= step # e.g. 23 - 10 = 13 --> 10 self.index = (index-step)//step*step self.interrupt_delay() # 向下翻页 elif key == ord('d'): if offset + step >= len( datalist ): continue self.offset += step # e.g. 23 + 10 = 33 --> 30 self.index = (index+step)//step*step self.interrupt_delay() # 前进 elif key == ord('l') or key == 10 or key == curses.KEY_RIGHT: #→ if self.datatype == 'songs' or self.datatype == 'djchannels' or self.datatype == 'help': continue self.ui.build_loading() self.dispatch_enter(idx) self.index = 0 self.offset = 0 self.interrupt_delay() # 回退 elif key == ord('h') or key== curses.KEY_LEFT: #← # if not main menu if len(self.stack) == 1: continue up = stack.pop() self.datatype = up[0] self.title = up[1] self.datalist = up[2] self.offset = up[3] self.index = up[4] # 搜索 elif key == ord('f'): self.search() # 播放下一曲 elif key == ord(']'): if len(self.presentsongs) == 0: continue self.index=self.player.return_idx()[0]+1 self.return_play_list() self.player.next() for i in range(9): self.ui.build_loading(2) time.sleep(0.2) # 播放上一曲 elif key == ord('['): if len(self.presentsongs) == 0: continue self.return_play_list() self.player.prev() for i in range(9): self.ui.build_loading(2) time.sleep(0.2) # 播放、暂停 elif key == ord(' '): if datatype == 'songs': self.presentsongs = ['songs', title, datalist, offset, index] elif datatype == 'djchannels': self.presentsongs = ['djchannels', title, datalist, offset, index] self.player.play(datatype, datalist, idx) time.sleep(0.1) # 加载当前播放列表 elif key == ord('p'): if len(self.presentsongs) == 0: continue self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.presentsongs[0] self.title = self.presentsongs[1] self.datalist = self.presentsongs[2] self.offset = self.presentsongs[3] self.index = self.presentsongs[4] self.return_play_list() # 添加到打碟歌单 elif key == ord('a'): if datatype == 'songs' and len(datalist) != 0: self.djstack.append( datalist[idx] ) elif datatype == 'artists': pass # 加载打碟歌单 elif key == ord('z'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 打碟' self.datalist = self.djstack self.offset = 0 self.index = 0 # 添加到收藏歌曲 elif key == ord('s'): if (datatype == 'songs' or datatype == 'djchannels') and len(datalist) != 0: self.collection.append( datalist[idx] ) # 加载收藏歌曲 elif key == ord('c'): self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = 'songs' self.title = '网易云音乐 > 收藏' self.datalist = self.collection self.offset = 0 self.index = 0 # 从当前列表移除 elif key == ord('r'): if datatype != 'main' and len(datalist) != 0: self.datalist.pop(idx) self.index = carousel(offset, min( len(datalist), offset + step) - 1, idx ) elif key == ord('m'): if datatype != 'main': self.stack.append( [datatype, title, datalist, offset, index] ) self.datatype = self.stack[0][0] self.title = self.stack[0][1] self.datalist = self.stack[0][2] self.offset = 0 self.index = 0 elif key == ord('g'): if datatype == 'help': #webbrowser.open_new_tab('https://github.com/darknessomi/musicbox') webbrowser.open('https://github.com/pi-dan/musicbox') self.ui.build_menu(self.datatype, self.title, self.datalist, self.offset, self.index, self.step) self.ui.progress_bar(self.play_time_str,self.play_length_str) self.ui.screen.refresh() self.player.stop() sfile = file(Constant.conf_dir + "/flavor.json", 'w') data = { 'account': self.account, 'collection': self.collection } sfile.write(json.dumps(data)) sfile.close() curses.endwin() def dispatch_enter(self, idx): # The end of stack netease = self.netease datatype = self.datatype title = self.title datalist = self.datalist offset = self.offset index = self.index self.stack.append( [datatype, title, datalist, offset, index]) if datatype == 'main': self.choice_channel(idx) # 该艺术家的热门歌曲 elif datatype == 'artists': artist_id = datalist[idx]['artist_id'] songs = netease.artists(artist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['artists_name'] # 该专辑包含的歌曲 elif datatype == 'albums': album_id = datalist[idx]['album_id'] songs = netease.album(album_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['albums_name'] # 精选歌单选项 elif datatype == 'playlists': data = self.datalist[idx] self.datatype = data['datatype'] self.datalist = netease.dig_info(data['callback'](), self.datatype) self.title += ' > ' + data['title'] # 全站置顶歌单包含的歌曲 elif datatype == 'top_playlists': log.debug(datalist) playlist_id = datalist[idx]['playlist_id'] songs = netease.playlist_detail(playlist_id) self.datatype = 'songs' self.datalist = netease.dig_info(songs, 'songs') self.title += ' > ' + datalist[idx]['playlists_name'] # 分类精选 elif datatype == 'playlist_classes': # 分类名称 data = self.datalist[idx] self.datatype = 'playlist_class_detail' self.datalist = netease.dig_info(data, self.datatype) self.title += ' > ' + data log.debug(self.datalist) # 某一分类的详情 elif datatype == 'playlist_class_detail': # 子类别 data = self.datalist[idx] self.datatype = 'top_playlists' self.datalist = netease.dig_info(netease.top_playlists(data), self.datatype) log.debug(self.datalist) self.title += ' > ' + data #榜单 elif datatype == 'toplists': songs=netease.top_songlist(idx) self.title+=' > ' + self.datalist[idx] self.datalist=netease.dig_info(songs,'songs') self.datatype='songs' def choice_channel(self, idx): # 排行榜 netease = self.netease if idx == 0: #songs = netease.top_songlist() #self.datalist = netease.dig_info(songs, 'songs') self.datalist=netease.return_toplists() self.title += ' > 排行榜' self.datatype = 'toplists' # 艺术家 elif idx == 1: artists = netease.top_artists() self.datalist = netease.dig_info(artists, 'artists') self.title += ' > 艺术家' self.datatype = 'artists' # 新碟上架 elif idx == 2: albums = netease.new_albums() self.datalist = netease.dig_info(albums, 'albums') self.title += ' > 新碟上架' self.datatype = 'albums' # 精选歌单 elif idx == 3: self.datalist = [ { 'title': '全站置顶', 'datatype': 'top_playlists', 'callback': netease.top_playlists }, { 'title': '分类精选', 'datatype': 'playlist_classes', 'callback': netease.playlist_classes } ] self.title += ' > 精选歌单' self.datatype = 'playlists' # 我的歌单 elif idx == 4: # 未登录 if self.userid is None: # 使用本地存储了账户登录 if self.account: user_info = netease.login(self.account[0], self.account[1]) # 本地没有存储账户,或本地账户失效,则引导录入 if self.account == {} or user_info['code'] != 200: self.bar_p=True #进度条不显示 time.sleep(0.1) data = self.ui.build_login() self.bar_p=False #显示进度条 # 取消登录 if data ==-1: self.lonin=False return user_info = data[0] self.account = data[1] self.username = user_info['profile']['nickname'] self.userid = user_info['account']['id'] # 读取登录之后的用户歌单 myplaylist = netease.user_playlist( self.userid ) self.datatype = 'top_playlists' self.datalist = netease.dig_info(myplaylist, self.datatype) self.title += ' > ' + self.username + ' 的歌单' # DJ节目 elif idx == 5: self.datatype = 'djchannels' self.title += ' > DJ节目' self.datalist = netease.djchannels() # 打碟 elif idx == 6: self.datatype = 'songs' self.title += ' > 打碟' self.datalist = self.djstack # 收藏 elif idx == 7: self.datatype = 'songs' self.title += ' > 收藏' self.datalist = self.collection # 搜索 elif idx == 8: self.search() # 帮助 elif idx == 9: self.datatype = 'help' self.title += ' > 帮助' self.datalist = shortcut self.offset = 0 self.index = 0 def search(self): ui = self.ui x = ui.build_search_menu() # if do search, push current info into stack if x in range(ord('1'), ord('5')): self.stack.append( [self.datatype, self.title, self.datalist, self.offset, self.index ]) self.index = 0 self.offset = 0 self.bar_p=True #不显示进度条 time.sleep(0.1) if x == ord('1'): self.datatype = 'songs' self.datalist = ui.build_search('songs') self.title = '歌曲搜索列表' elif x == ord('2'): self.datatype = 'artists' self.datalist = ui.build_search('artists') self.title = '艺术家搜索列表' elif x == ord('3'): self.datatype = 'albums' self.datalist = ui.build_search('albums') self.title = '专辑搜索列表' elif x == ord('4'): # 搜索结果可以用top_playlists处理 self.datatype = 'top_playlists' self.datalist = ui.build_search('search_playlist') self.title = '精选歌单搜索列表' self.bar_p=False #显示进度条