예제 #1
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 = 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 = '精选歌单搜索列表'
예제 #2
0
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 = '精选歌单搜索列表'
예제 #3
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.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
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
0
파일: menu.py 프로젝트: dssljt/musicbox
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
예제 #8
0
파일: menu.py 프로젝트: pastorgod/musicbox
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
예제 #9
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
예제 #10
0
파일: menu.py 프로젝트: Zorgodon/musicbox
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
예제 #11
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 = '精选歌单搜索列表'
예제 #12
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.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  #显示进度条