Beispiel #1
0
 def do_cs(self, arg):
     ''' change search source
     arg must be in 'qq', 'netease', 'migu'
     '''
     if arg == '':
         # stay current api
         return
     if arg == 'qq':
         self.api = QQMusicApi()
         print('Source is changed to qq music.')
     elif arg == 'netease':
         self.api = NeteaseCloudMusicAPI()
         print('Source is changed to netease cloud music.')
     elif arg == 'migu':
         self.api = MiguMusicAPI()
         print('Source is changed to migu music.')
     else:
         print('Music source must be in qq, netease or migu.')
Beispiel #2
0
    def __init__(self):
        Cmd.__init__(self)

        self.search_result = {'source': '', 'content': []}
        self.api = QQMusicApi()  # default qq
        self.current_song = None  # dict()
        self.playlist = list()
        # self.player = mpv.MPV(ytdl=True)

        # playing signal
        self.playing_s = False
        self.playing_pl = False
        self.interrupt = False
        self.playing = False

        # initialize playlist info
        self._get_playlist_info()
Beispiel #3
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 #4
0
class MusicShell(Cmd):
    ''' Main command shell '''

    prompt = 'BowenMusic> '
    with open('src/intro.txt', 'r') as f:
        intro = f.read()  # welcome

    def __init__(self):
        Cmd.__init__(self)

        self.search_result = {'source': '', 'content': []}
        self.api = QQMusicApi()  # default qq
        self.current_song = None  # dict()
        self.playlist = list()
        # self.player = mpv.MPV(ytdl=True)

        # playing signal
        self.playing_s = False
        self.playing_pl = False
        self.interrupt = False
        self.playing = False

        # initialize playlist info
        self._get_playlist_info()

    # command #
    def do_pl(self, arg):
        ''' show playlist 
        > pl          # all playlists overview
        > pl 2    # show songs in 2nd playlist
        '''
        # check playlist exists
        self._get_playlist_info()
        if len(self.playlist) == 0:
            print('No playlist found, use `cpl` to create one.')
            return

        # no arg, show all playlists' names
        if arg == '':
            index = 1
            for index in range(len(self.playlist)):
                print('{}. {}'.format(index + 1, self.playlist[index]))
            return

        try:  # if arg is `int` and in range
            pl_index = int(arg)
            assert (pl_index >= 1 and pl_index <= len(self.playlist))
        except:
            print('Arguments should be in [1, {}].'.format(len(self.playlist)))
            return

        print('\n歌单: {}'.format(self.playlist[pl_index - 1]))
        print('-' * 15)
        print('{}{}{}{}'.format(self._rpad('', 4), self._rpad('歌曲', 30),
                                self._rpad('歌手', 20), self._rpad('专辑', 30)))
        print('-' * 80)
        with open(
                os.path.join(self.LIST_DIR,
                             '{}.json'.format(self.playlist[pl_index - 1])),
                'r') as f:
            song_list = json.load(f)

        for index in range(len(song_list)):
            print('{}{}{}{}'.format(
                self._rpad(str(index + 1) + '.', 4),
                self._rpad(song_list[index]['song_name'], 30),
                self._rpad(song_list[index]['singers'], 20),
                self._rpad(song_list[index]['album_name'], 30)))
        print('-' * 80)

    def do_cpl(self, arg):
        ''' create playlist '''
        print('Please input the name of new playlist: ', end='')
        pl_name = input()
        for file_path in os.listdir(self.LIST_DIR):
            if pl_name == file_path.split('.')[0]:
                print('Playlist {} already exists.'.format(pl_name))
                return
        # create playlist json file
        with open('{}/{}.json'.format(self.LIST_DIR, pl_name), 'w') as f:
            f.write('[]')
        print('Playlist {} created.'.format(pl_name))
        self._get_playlist_info()

    def do_rpl(self, arg):
        ''' rename playlist '''
        # check playlist exists
        if len(self.playlist) == 0:
            print('No playlist found, use `cpl` to create one.')
            return
        # arg format
        if arg == '':
            print(
                'Not enough arguments, the index of playlist should be offered.'
            )
            return
        try:  # if arg is `int` and in range
            pl_index = int(arg)
            assert (pl_index >= 1 and pl_index <= len(self.playlist))
        except:
            print('Arguments should be in [1, {}].'.format(len(self.playlist)))
            return

        # check if the playlist exists
        if os.path.exists('{}/{}.json'.format(self.LIST_DIR,
                                              self.playlist[pl_index - 1])):
            old_path = os.path.join(self.LIST_DIR,
                                    self.playlist[pl_index - 1] + '.json')
        else:
            print('Playlist {} doesn\'t exist.'.format(self.playlist[pl_index -
                                                                     1]))
            return

        # get new name from user
        print('Please input a new name: ', end='')
        pl_name = input()

        # check if new name is the same as the old name
        if pl_name == self.playlist[pl_index - 1]:
            print('Name not changed.')
            return

        new_path = os.path.join(self.LIST_DIR, pl_name + '.json')
        os.rename(old_path, new_path)
        print('Playlist {} is renamed to {}.'.format(
            self.playlist[pl_index - 1], pl_name))
        self._get_playlist_info()

    def do_dpl(self, arg):
        ''' delete playlist '''
        # check playlist exists
        if len(self.playlist) == 0:
            print('No playlist found, user `cpl` to create one.')
            return
        # arg format
        if arg == '':
            print(
                'Not enough arguments, the index of playlist should be offered.'
            )
            return
        try:  # if arg is `int` and in range
            pl_index = int(arg)
            assert (pl_index >= 1 and pl_index <= len(self.playlist))
        except:
            print('Arguments should be in [1, {}].'.format(len(self.playlist)))
            return
        # check if the playlist exists
        if os.path.exists('{}/{}.json'.format(self.LIST_DIR,
                                              self.playlist[pl_index - 1])):
            delete_path = os.path.join(self.LIST_DIR,
                                       self.playlist[pl_index - 1] + '.json')
        else:
            print('Playlist {} doesn\'t exist.'.format(self.playlist[pl_index -
                                                                     1]))
            return

        os.remove(delete_path)
        print('Playlist {} is deleted.'.format(self.playlist[pl_index - 1]))
        self._get_playlist_info()

    def do_search(self, keyword):
        ''' search according to keyword
            results are stored in `list` self.search_result
        '''
        # check arg
        if keyword == '':
            print('Not enough arguments, keywords should be offered.')
            return
        if self.api.name == 'qq':
            self.search_result['source'] = 'qq'
            self.search_result['content'] = self.api.search(1, keyword)
            if len(self.search_result['content']) != 0:  # result exists
                self._show_search()
            else:
                print('No result found.')
        elif self.api.name == 'netease':
            self.search_result['source'] = 'netease'
            self.search_result['content'] = self.api.search(keyword, 1)
            if len(self.search_result['content']) != 0:
                self._show_search()
            else:
                print('No result found.')
        elif self.api.name == 'migu':
            self.search_result['source'] = 'migu'
            self.search_result['content'] = self.api.search(keyword)
            if len(self.search_result['content']) != 0:
                self._show_search()
            else:
                print('No result found.')
        else:
            print('api name not found.')
            return

    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))

    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()

    def do_m(self, arg):
        ''' pause or continue the player '''
        try:
            if self.player._get_property('pause') == False:
                self.player._set_property('pause', True)
                print('pause.')
            else:
                self.player._set_property('pause', False)
                print('continue')
        except:
            print('No song is being played, use `play` first.')

    def _play_from_search(self, song):
        # song url
        if song['source'] == 'migu':
            url = song['url']
        elif song['source'] == 'qq':
            url = QQMusicApi().get_url(song['song_mid'])
        elif song['source'] == 'netease':
            url = NeteaseCloudMusicAPI().get_url(song['song_mid'])

        # check url
        if url == '':
            print('You need {} vip to listen {}.'.format(
                self.search_result['source'], play_song['song_name']))
            return

        # player is occupied by playing pl
        if self.playing == True:
            self.interrupt = True
            self.player.terminate()
        self.playing = True

        self.player = mpv.MPV(ytdl=True)
        self.event_s = threading.Event()
        play_thread = threading.Thread(target=self.__play_search_base,
                                       args=(url, ))
        play_thread.start()
        self.current_song = song
        self.event_s.wait()

        if self.interrupt == True:
            self.interrupt = False
            return

        self.playing = False
        self.player.terminate()

    def __play_search_base(self, url):
        self.player.play(url)
        self.player.wait_for_playback()
        self.current_song = None
        self.event_s.set()

    def _play_from_playlist(self, song_list):
        if self.playing == True:
            self.interrupt = True
            self.player.terminate()

        self.playing = True
        self.player = mpv.MPV(ytdl=True)

        for song in song_list:
            if song['source'] == 'migu':
                url = song['url']
            elif song['source'] == 'qq':
                url = QQMusicApi().get_url(song['song_mid'])
            elif song['source'] == 'netease':
                url = NeteaseCloudMusicAPI().get_url(song['song_mid'])
            if url == '':
                print('You need {} vip to listen {}.'.format(
                    song['source'], song['song_name']))
                continue

            self.event_pl = threading.Event()
            play_thread = threading.Thread(target=self.__play_pl_base,
                                           args=(url, ))
            play_thread.start()
            self.current_song = song
            self.event_pl.wait()

            # interrupt by playing search
            if self.interrupt == True:
                self.interrupt = False
                return

        self.playing = False
        self.player.terminate()

    def __play_pl_base(self, url):
        self.player.play(url)
        # self.player.wait_for_playback()
        self.player.wait_for_shutdown()
        self.current_song = None
        self.event_pl.set()

    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.')

    def do_cs(self, arg):
        ''' change search source
        arg must be in 'qq', 'netease', 'migu'
        '''
        if arg == '':
            # stay current api
            return
        if arg == 'qq':
            self.api = QQMusicApi()
            print('Source is changed to qq music.')
        elif arg == 'netease':
            self.api = NeteaseCloudMusicAPI()
            print('Source is changed to netease cloud music.')
        elif arg == 'migu':
            self.api = MiguMusicAPI()
            print('Source is changed to migu music.')
        else:
            print('Music source must be in qq, netease or migu.')

    def do_s(self, arg):
        ''' print current music source '''
        print('Current source is \'{}\''.format(self.api.name))

    def do_quit(self, arg):
        print('Wish you good luck.')
        return True

    def do_bye(self, arg):
        return self.do_quit(arg)

    def do_exit(self, arg):
        return self.do_quit(arg)

    def default(self, arg):
        print('Command not defined, use help for more information.')

    def _get_playlist_info(self):
        self.LIST_DIR = 'userdata/playlist'
        self.playlist.clear()
        for file_path in os.listdir(self.LIST_DIR):
            playlist_name = file_path.split('.')[0]
            self.playlist.append(playlist_name)

    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)

    def _lpad(self, text, length, padding=' '):
        ''' left pad for printing, not used '''
        return padding * max(0, (length - wcswidth(text))) + text

    def _rpad(self, text, length, padding=' '):
        ''' right pad for printing 
        if len(text) is larger than length, shorten the text
        '''
        while length - wcswidth(text) <= 0:
            text = text[0:len(text) - 1]
        return text + padding * max(0, (length - wcswidth(text)))
from flask import Flask, redirect, url_for, request
from api import MiguMusicAPI, NeteaseCloudMusicAPI, QQMusicApi

API_DICT = {
    'qq': QQMusicApi(),
    'netease': NeteaseCloudMusicAPI(),
    'migu': MiguMusicAPI()
}

app = Flask(__name__)


@app.route('/')
def main():
    return redirect(url_for('music'))


@app.route('/music')
def music():
    return 'Welcome to BowenMusic'


@app.route('/music/search', methods=['GET', 'POST'])
def search():
    if request.method == 'GET':
        api = request.args.get('api')
        keywords = request.args.get('keywords')
    elif request.method == 'POST':
        api = request.form.get('api')
        keywords = request.form.get('keywords')