Пример #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 = 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  #显示进度条