Beispiel #1
0
    def _load_more(self):
        ''' load more when scroll bar is scrolled to the bottom
        only when searching music and in qq music
        '''
        if self.display_mode == 'local' or self.parent.header.music_source != 'qq':
            return

        # scroll bar at end
        if self.music_list.verticalScrollBar().value(
        ) == self.load_more_threshold:
            keywords = self.parent.header.search_line.text()

            api = QQMusicApi()
            search_result = api.search(self.load_page, keywords)
            for item in search_result:
                qt_item = QTreeWidgetItem()

                qt_item.setText(0, item['song_name'])

                singers = ''
                for singer in item['singer_list']:
                    singers += singer
                    singers += '/'
                singers = singers.strip('/')
                qt_item.setText(1, singers)

                qt_item.setText(2, item['album_name'])
                qt_item.setText(3, convert_interval(item['interval']))
                qt_item.setText(4, str(item['song_mid']))
                qt_item.setText(5, item['image_url'])

                self.parent.main_list.music_list.addTopLevelItem(qt_item)

            self.load_page += 1
            self.load_more_threshold += 10
Beispiel #2
0
 def _show_search(self):
     ''' show first 10 search result from `list` self.search_result '''
     print('{}{}{}{}{}'.format(
         self._rpad('', 4),
         self._rpad('歌曲', 30), 
         self._rpad('歌手', 20), 
         self._rpad('专辑', 30), 
         self._rpad('时长', 10)))
     print('-'*100)
     index = 1
     for result in self.search_result['content']:
         if self.search_result['source'] != 'migu':
             singers = convert_singerlist(result['singer_list'])
         else:
             singers = result['singer_list']
         print('{}{}{}{}{}'.format(
             self._rpad(str(index)+'.', 4),
             self._rpad(result['song_name'], 30), 
             self._rpad(singers, 20),
             self._rpad(result['album_name'], 30), 
             self._rpad(convert_interval(result['interval']), 10)))
         index += 1
         if index == 11: # show only ten results
             break
     print('-'*100)
Beispiel #3
0
    def __slider_moved(self):
        ''' moving slider '''
        ratio = self.slider.value() / 1000
        music_time = (self.player.duration() // 1000) * ratio  # ms -> s
        music_time_str = convert_interval(int(music_time))

        total_time = self.time.text().split('/')[-1]
        self.time.setText(music_time_str + '/' + total_time)
Beispiel #4
0
    def _player_pos_change(self):
        ''' when player position is changing, change slider and time info '''
        # current music total time (ms)
        if self.player.duration() == 0:
            return

        current_time = self.player.position() // 1000  # ms -> s
        api = QQMusicApi()
        total_time = self.time.text().split('/')[-1]

        # set time_info and slider
        self.time.setText(convert_interval(current_time) + '/' + total_time)
        self.slider.setValue(current_time / (self.player.duration() // 1000) *
                             1000)

        if self.player.duration() == self.player.position():
            self.music_end_signal.emit()
Beispiel #5
0
    def do_i(self, arg):
        ''' print current playing song's info '''
        if self.current_song == None:
            print('No song is playing.')
            return
        # print(self.current_song)
        try:
            # print(self.player._get_property('time-pos'))
            if self.current_song['source'] == 'migu':
                total_time = ''
            else:
                total_time = '/' + self.current_song['interval']

            print('Playing {} - {}  {}{}'.format(
                self.current_song['song_name'], self.current_song['singers'],
                convert_interval(int(self.player._get_property('time-pos'))),
                total_time))
        except:
            print('No song is playing.')
Beispiel #6
0
    def local_music(self):
        ''' display local music in main_list '''
        self.navigation_list.setCurrentItem(None)
        self.play_list.setCurrentItem(None)
        self.parent.main_list.music_list.clear()
        self.parent.main_list.display_mode = 'local'

        for file_path in os.listdir('userdata/music'):
            if '.m4a' not in file_path and '.mp3' not in file_path and '.flac' not in file_path:
                continue
            path = os.path.join('userdata/music', file_path)
            media_info = json.loads(
                MediaInfo.parse(path).to_json())['tracks'][0]

            # song_name = media_info['title'] if 'title' in media_info else file_path.split('_')[0]
            song_name = file_path.split('_')[0]
            singers = media_info[
                'performer'] if 'performer' in media_info else ''
            album_name = media_info['album'] if 'album' in media_info else ''

            api = QQMusicApi()

            duration = convert_interval(
                math.floor(media_info['duration'] /
                           1000)) if 'duration' in media_info else ''

            song_mid = file_path.split('.')[0].split('_')[1]

            qt_item = QTreeWidgetItem()
            qt_item.setText(0, song_name)
            qt_item.setText(1, singers)
            qt_item.setText(2, album_name)
            qt_item.setText(3, duration)
            qt_item.setText(4, song_mid)

            self.parent.main_list.music_list.addTopLevelItem(qt_item)
Beispiel #7
0
    def next_song(self, direction=None):
        ''' when current music play end, continue to next song '''

        if self.current_music == None:
            return

        index = self.play_list.index(self.current_music)
        # next song mid
        if direction == 'next' or direction is None:
            if index == len(self.play_list) - 1:
                next_song_dict = self.play_list[0]
            else:
                next_song_dict = self.play_list[index + 1]
        elif direction == 'prev':
            if index == 0:
                next_song_dict = self.play_list[len(self.play_list) - 1]
            else:
                next_song_dict = self.play_list[index - 1]
        else:
            raise valueError('direction error.')

        self.pause()
        self.slider.setValue(0)

        # if local exists
        for music_file in os.listdir('userdata/music'):
            if next_song_dict['song_mid'] in music_file:
                next_path = os.path.join('userdata/music', music_file)
                self.player.setMedia(
                    QMediaContent(QUrl.fromLocalFile(next_path)))
                self.play()

                # get true interval
                media_info = json.loads(
                    MediaInfo.parse(next_path).to_json())['tracks'][0]
                interval = convert_interval(
                    math.floor(media_info['duration'] / 1000))

                # set song name, singer, interval display
                if next_song_dict['singers'] != '':
                    self.song_info.setText(next_song_dict['song_name'] + '-' +
                                           next_song_dict['singers'])
                else:
                    self.song_info.setText(next_song_dict['song_name'])
                self.time.setText(self.time.text().split('/')[0] + '/' +
                                  interval)
                self.current_music = next_song_dict

                iterator = QTreeWidgetItemIterator(
                    self.parent.main_list.music_list)
                while iterator.value():
                    item = iterator.value()
                    if item.text(4) == next_song_dict['song_mid']:
                        self.parent.main_list.music_list.setCurrentItem(item)
                        break
                    iterator.__iadd__(1)
                return

        # local not exists, download according to song mid
        if next_song_dict['source'] == 'migu':
            url = next_song_dict['url']
        elif next_song_dict['source'] == 'qq':
            url = QQMusicApi().get_url(next_song_dict['song_mid'])
        elif next_song_didct['source'] == 'netease':
            url = NeteaseCloudMusicAPI().get_url(next_song_dict['song_mid'])

        next_path = 'userdata/music/{}_{}.m4a'.format(
            next_song_dict['song_name'], next_song_dict['song_mid'])
        urllib.request.urlretrieve(url, next_path)
        self.player.setMedia(QMediaContent(QUrl.fromLocalFile(next_path)))
        self.play()

        # get true interval
        media_info = json.loads(
            MediaInfo.parse(next_path).to_json())['tracks'][0]
        interval = convert_interval(math.floor(media_info['duration'] / 1000))

        # set song name, singer, interval display
        if next_song_dict['singers'] != '':
            self.song_info.setText(next_song_dict['song_name'] + '-' +
                                   next_song_dict['singers'])
        else:
            self.song_info.setText(next_song_dict['song_name'])
        self.time.setText(self.time.text().split('/')[0] + '/' + interval)
        self.current_music = next_song_dict

        iterator = QTreeWidgetItemIterator(self.parent.main_list.music_list)
        while iterator.value():
            item = iterator.value()
            if item.text(4) == next_song_dict['song_mid']:
                self.parent.main_list.music_list.setCurrentItem(item)
                break
            iterator.__iadd__(1)
Beispiel #8
0
    def play_from_main_list(self, qtree_item, music_path, mode):
        ''' Get signal from main list and play music
        qtree_item - `QTreeWidgetItem`
        music_path - local path
        mode - 'global', 'local', 'list'
        '''
        self.play_mode = mode
        # button
        self.slider.setValue(0)
        self.play_button.hide()
        self.pause_button.show()
        # play list clear
        self.play_list.clear()

        # set media for QMediaPlayer
        q_path = QUrl.fromLocalFile(music_path)
        self.player.setMedia(QMediaContent(q_path))

        media_info = json.loads(MediaInfo.parse(
            music_path).to_json())['tracks'][0]  # to get song interval
        item_dict = {
            'song_name': qtree_item.text(0),
            'singers': qtree_item.text(1),
            'album_name': qtree_item.text(2),
            'interval': '',
            'song_mid': qtree_item.text(4),
            'url': qtree_item.text(5),
            'source': qtree_item.text(6)
        }
        self.current_music = item_dict  # qtreewidgetiem

        # set play_list according to the mode
        if mode == 'global':
            self.play_list.append(self.current_music)
        elif mode == 'list' or mode == 'local':
            iterator = QTreeWidgetItemIterator(
                self.parent.main_list.music_list)
            while iterator.value():
                item = iterator.value()
                item_dict = {
                    'song_name': item.text(0),
                    'singers': item.text(1),
                    'album_name': item.text(2),
                    'interval': '',
                    'song_mid': item.text(4),
                    'url': item.text(5),
                    'source': item.text(6)
                }

                self.play_list.append(item_dict)
                iterator.__iadd__(1)

        self.order_play_list = self.play_list[:]
        # play
        self.play()
        # set song_info
        if self.current_music['singers'] != '':
            self.song_info.setText(self.current_music['song_name'] + '-' +
                                   self.current_music['singers'])
        else:
            self.song_info.setText(self.current_music['song_name'])
        # set total time
        media_info = json.loads(
            MediaInfo.parse(music_path).to_json())['tracks'][0]
        interval = convert_interval(math.floor(media_info['duration'] / 1000))
        self.time.setText(self.time.text().split('/')[0] + '/' + interval)
Beispiel #9
0
    def search(self):
        self.parent.main_list.music_list.clear()
        self.parent.navigation.local_list.setCurrentItem(None)
        self.parent.navigation.play_list.setCurrentItem(None)

        self.parent.main_list.display_mode = 'global'

        keywords = self.search_line.text()
        if keywords == '':
            return

        if self.music_source == 'qq':
            self.parent.navigation.navigation_list.setCurrentRow(0)
            api = QQMusicApi()
        elif self.music_source == 'netease':
            self.parent.navigation.navigation_list.setCurrentRow(1)
            api = NeteaseCloudMusicAPI()
        elif self.music_source == 'migu':
            self.parent.navigation.navigation_list.setCurrentRow(2)
            api = MiguMusicAPI()
        else:
            raise ValueError(
                'music sources only contain qq, netease and migu.')

        search_result = []
        if api.name == 'qq':
            for page in [1, 2]:
                search_result += api.search(page, keywords)
        elif api.name == 'netease':
            search_result += api.search(keywords, 1)
        elif api.name == 'migu':
            search_result += api.search(keywords)
        else:
            raise ValueError('api.name not in qq, netease and migu')

        for item in search_result:
            qt_item = QTreeWidgetItem()
            qt_item.setText(0, item['song_name'])

            if api.name == 'migu':
                singers = item['singer_list']
            else:
                singers = ''
                for singer in item['singer_list']:
                    singers += singer
                    singers += '/'
                singers = singers.strip('/')

            qt_item.setText(1, singers)
            qt_item.setText(2, item['album_name'])

            if api.name == 'migu':
                qt_item.setText(3, '')
            else:
                qt_item.setText(3, convert_interval(item['interval']))

            qt_item.setText(4, str(item['song_mid']))

            if api.name == 'migu':
                qt_item.setText(5, item['url'])
            else:
                qt_item.setText(5, '')
            qt_item.setText(6, api.name)

            self.parent.main_list.music_list.addTopLevelItem(qt_item)
Beispiel #10
0
    def do_play(self, arg):
        ''' play songs 
        > play        # default play from playlist 1
        > play -pl 2  # play from playlist 2
        > play -s 2   # play the 2nd song in the last search result
        '''
        # update playlist
        self._get_playlist_info()

        # play from playlist 1 by default
        if arg == '':
            if len(self.playlist) == 0:
                print('No playlist found, use `cpl` to create one.')
                return
            pl_name = self.playlist[0]
            pl_path = os.path.join(self.LIST_DIR, pl_name + '.json')
            with open(pl_path, 'r') as f:
                song_list = json.load(f)
            if len(song_list) == 0:
                print('No song found in playlist {}.'.format(pl_name))
                return

            play_pl_thread = threading.Thread(target=self._play_from_playlist,
                                              args=(song_list, ))
            play_pl_thread.start()

        # play from playlist or search
        else:
            # args number
            args = arg.split()
            if len(args) < 2:
                print(
                    'Not enough arguments, use `help play` for more information.'
                )
                return
            if len(args) > 2:
                print(
                    'Too much arguments, use `help play` for more information.'
                )
                return

            # check mode
            mode = args[0]
            if mode not in ['-pl', '-s']:
                print('Arguments error, use `help play` for more information.')
                return

            # play from playlist
            if mode == '-pl':
                if len(self.playlist) == 0:
                    print('No playlist found, use `cpl` to create one.')
                    return
                try:
                    pl_index = int(args[1])
                    assert pl_index >= 1 and pl_index <= len(self.playlist)
                except:
                    print('playlist index should be in [1, {}].'.format(
                        len(self.playlist)))
                    return
                pl_name = self.playlist[pl_index - 1]
                pl_path = os.path.join(self.LIST_DIR, pl_name + '.json')
                with open(pl_path, 'r') as f:
                    song_list = json.load(f)
                if len(song_list) == 0:
                    print('No song found in playlist {}.'.format(pl_name))
                    return

                play_pl_thread = threading.Thread(
                    target=self._play_from_playlist, args=(song_list, ))

                play_pl_thread.start()

            # play from search result
            elif mode == '-s':
                if len(self.search_result['content']) == 0:
                    print('No search result, do search first.')
                    return

                s_index_upper_limit = len(
                    self.search_result['content']) if len(
                        self.search_result['content']) <= 10 else 10
                try:
                    s_index = int(args[1])
                    assert s_index >= 1 and s_index <= s_index_upper_limit
                except:
                    print('The index in search result must be in [1, {}].'.
                          format(s_index_upper_limit))

                # song info
                play_song = copy.deepcopy(
                    self.search_result['content'][s_index - 1])
                play_song['source'] = self.search_result['source']
                play_song['singers'] = play_song['singer_list'] if play_song[
                    'source'] == 'migu' else convert_singerlist(
                        play_song['singer_list'])
                play_song['interval'] = '' if play_song[
                    'source'] == 'migu' else convert_interval(
                        play_song['interval'])

                play_s_thread = threading.Thread(target=self._play_from_search,
                                                 args=(play_song, ))
                play_s_thread.start()
Beispiel #11
0
    def do_add(self, arg):
        ''' add songs in last search result to playlist 
        > add 10 1 # 10 is index in search result, 1 is index of playlist
        '''
        # check search result
        if len(self.search_result['content']) == 0:
            print('No search result, do search first.')
            return

        # check playlist exists
        if len(self.playlist) == 0:
            print('No playlist found, use `cpl` to create one.')
            return

        # check arguments format
        arg_list = arg.split()  # check number of arguments
        if len(arg_list) < 2:
            print('Not enough arguments, the number of arguments should be 2.')
            return
        elif len(arg_list) > 2:
            print('Too much arguments, the number of arguments should be 2.')
            return
        try:  # check if arguments are number
            s_index = int(arg_list[0])  # index in search result
            pl_index = int(arg_list[1])  # index in playlist
        except:
            print(
                'Arguments should be [the index in search result] [the index of playlist].'
            )
            return

        # check if index is out of range
        s_index_upper_limit = len(self.search_result['content']) if len(
            self.search_result['content']) <= 10 else 10
        if s_index < 1 or s_index > s_index_upper_limit:
            print('The index in search result must be in [1, {}].'.format(
                s_index_upper_limit))
            return
        if pl_index < 1 or pl_index > len(self.playlist):
            print('The index of playlist must be in [1, {}].'.format(
                len(self.playlist)))
            return

        # add song to playlist
        add_song = self.search_result['content'][s_index - 1]
        source = self.search_result['source']
        pl_name = self.playlist[pl_index - 1]

        # if playlist name exists locally
        if os.path.exists('{}/{}.json'.format(self.LIST_DIR, pl_name)):
            full_path = '{}/{}.json'.format(self.LIST_DIR, pl_name)
        else:
            print('playlist {} dosen\'t exist.'.format(pl_name))
            return

        # generate stored info
        music_info = dict()
        music_info['source'] = source
        music_info['song_name'] = add_song['song_name']
        music_info['singers'] = add_song[
            'singer_list'] if source == 'migu' else convert_singerlist(
                add_song['singer_list'])
        music_info['album_name'] = add_song['album_name']
        music_info['interval'] = '' if source == 'migu' else convert_interval(
            add_song['interval'])
        music_info['song_mid'] = add_song['song_mid']
        music_info['url'] = add_song['url'] if source == 'migu' else ''

        # add to playlist
        with open(full_path, 'r') as f:
            song_list = json.load(f)
        song_list.append(music_info)
        with open(full_path, 'w') as f:
            json.dump(song_list, f, indent=1)

        print('Add {} to playlist {} successfully.'.format(
            add_song['song_name'], pl_name))