예제 #1
0
class PlaylistButton(QPushButton):
    # parent = navigation
    __solts__ = ('parent', 'grandparent', 'ids', 'coverImgUrl', 'catch',
                 'detailFrame', 'result', 'singsIds', 'singsUrls')

    hasClicked = pyqtSignal(int, str)

    def __init__(self, parent, ids, coverImgUrl, *args):
        super(PlaylistButton, self).__init__(*args)
        self.parent = parent
        self.grandparent = self.parent.parent

        self.setCheckable(True)
        self.setAutoExclusive(True)

        self.ids = ids
        self.coverImgUrl = coverImgUrl

        self.catch = None
        self.result = None
        self.singsIds = None
        self.singsUrls = None

        self.clicked.connect(self.clickedEvent)

    def clickedEvent(self):
        self.hasClicked.emit(self.ids, self.coverImgUrl)
예제 #2
0
class OneSing(QFrame):
    # 大量创建,这样可以省内存。
    __solts__ = ('parent', 'ggparent', 'detailFrame', 'row', 'column', 'ids',
                 'picName', 'picLabel', 'nameLabel', 'mainLayout', 'mousePos',
                 'result', 'catch', 'singsIds', 'singsUrls')

    clicked = pyqtSignal(int, str)

    def __init__(self, row, column, ids=None, parent=None, picName=None):
        super(OneSing, self).__init__()

        self.setObjectName('oneSing')
        # 自己的位置信息。
        self.row = row
        self.column = column
        # 歌单号。
        self.ids = ids
        # 大图的缓存名。
        self.picName = picName

        self.setMinimumSize(180, 235)

        self.picLabel = QLabel()
        self.picLabel.setObjectName('picLabel')
        self.picLabel.setMinimumSize(180, 180)
        self.picLabel.setMaximumSize(180, 180)

        self.nameLabel = QLabel()
        self.nameLabel.setMaximumWidth(180)
        self.nameLabel.setWordWrap(True)

        self.mainLayout = QVBoxLayout(self)

        self.mainLayout.addWidget(self.picLabel)
        self.mainLayout.addWidget(self.nameLabel)

    # 功能。
    def setStyleSheets(self, styleSheet=None):
        if styleSheet:
            self.setStyleSheet(styleSheet)

    # 事件。
    def mousePressEvent(self, event):
        # 记录下当前鼠标的位置。
        self.mousePos = QCursor.pos()

    def mouseReleaseEvent(self, event):
        # 先进行判断,防止误点将鼠标移开后还是会判断为已经点击的尴尬。
        if QCursor.pos() != self.mousePos:
            return
        else:
            self.clicked.emit(self.ids, self.picName)
예제 #3
0
class PlaylistButton(QPushButton):
    """
        提供一个简单点击的歌单自动切换点击状态,点击时会发出hasClicked信号。
        Args:
        parent 父类。
        ids 歌单的ids。
        coverImgUrl 这个歌单应该包含的图片地址 -> None, url.
        *args其他作用于原生Button的参数。
        singsIds 与 singsUrls暂时无用,不提供接受接口。

    """
    __solts__ = ('parent', 'grandparent', 'ids', 'coverImgUrl', 'catch',
                 'detailFrame', 'result', 'singsIds', 'singsUrls')

    hasClicked = pyqtSignal(int, str)

    def __init__(self, parent, ids, coverImgUrl, *args):
        super(PlaylistButton, self).__init__(*args)
        self.parent = parent
        self.grandparent = self.parent.parent

        self.setCheckable(True)
        self.setAutoExclusive(True)

        self.ids = ids
        self.coverImgUrl = coverImgUrl

        self.catch = None
        self.result = None
        self.singsIds = None
        self.singsUrls = None

        self.clicked.connect(self.clickedEvent)

    def clickedEvent(self):
        self.hasClicked.emit(self.ids, self.coverImgUrl)
예제 #4
0
class Player(QMediaPlayer):
    """播放器组件。"""

    timeChanged = pyqtSignal(str)

    def __init__(self, parent=None):
        super(Player, self).__init__()
        self.setObjectName('player')

        self.parent = parent
        self.playWidgets = self.parent
        self.transTime = addition.itv2time
        self.musicTime = 0
        self.playList = _MediaPlaylist(self)
        # 默认列表循环。
        self.playList.setPlaybackMode(self.playList.Loop)

        self.setConnects()

    # 功能。
    def setConnects(self):
        """用于设置连接的信号槽。"""
        self.durationChanged.connect(self.countTimeEvent)
        self.positionChanged.connect(self.positionChangedEvent)
        self.stateChanged.connect(self.stateChangedEvent)
        self.error.connect(self.dealError)
        self.playList.setInitConnection()
        # self.currentMediaChanged.connect(self.currentMediaChangedEvent)
        # self.mediaStatusChanged.connect(self.mediaStatusChangedEvent)

    def setDisconnects(self):
        self.durationChanged.disconnect()
        self.positionChanged.disconnect()
        self.stateChanged.disconnect()
        self.error.disconnect()
        self.mediaStatusChanged.disconnect()
        # self.playList.setInitConnection()

    def setMusic(self, url, data):
        """设置当前的音乐,可用直接用网络链接。"""
        if url:
            if 'http' in url or 'file' in url:
                self.playList.addMedias(QMediaContent(QUrl(url)), data)
            else:
                self.playList.addMedias(QMediaContent(QUrl.fromLocalFile(url)),
                                        data)
            return True
        else:
            return False
            # self.playMusic()

    def setAllMusics(self, datas):
        pass
        self.playList.addAllMedias(datas)

    def setIndex(self, index):
        self.playList.setCurrentIndex(index)
        # self.playMusic()

    def allTime(self):
        """返回当前音乐的总时间。(秒)"""
        return self.duration() / 1000

    def getCurrentMusicInfo(self):

        return self.playList.mediaList.get(
            self.currentMedia().canonicalUrl().toString())

    def playMusic(self, url=None, data=None):
        """播放音乐。"""
        if url:
            self.setMusic(url, data)
            # 播放事件。
            self.playWidgets.playEvent(self)
        else:
            self.playWidgets.playEvent(self)

    def dealError(self, error):
        # 具体内容看文档:
        # http://doc.qt.io/qt-5/qmediaplayer.html

        if error:
            musicInfo = self.playList.mediaList.pop(
                self.currentMedia().canonicalUrl().toString())
            self.loadRealMusicUrl(musicInfo)

    @toTask
    def loadRealMusicUrl(self, musicInfo):
        # 如果有个Url出错,比如音乐地址403重新获取下地址。
        musicId = musicInfo.get('music_id')
        # invalidUrl = musicInfo.get('url')

        if not musicId:
            self.playWidgets.nextSing()
            return

        future = aAsync(api.singsUrl, [musicId])
        data = yield from future

        if not data:
            self.playWidgets.nextSing()
            return

        url = data[0]['url']
        musicInfo['url'] = url
        self.playList.mediaList[url] = musicInfo
        # replaceIndex = self.playList.musics.index(invalidUrl)

        self.playList.musics[self.playList.currentIndex] = url
        self.playList.play()

    def saveCookies(self):
        self.playList.saveCookies()

    def loadCookies(self):
        self.playList.loadCookies()

    # 事件。
    def countTimeEvent(self, duration):
        """总时间改变的事件。相当于加载完成歌曲的事件。"""
        self.musicTime = duration / 1000
        # print('COUNT{0}'.format(duration))
        self.playWidgets.countTime.setText(self.transTime(self.musicTime))
        self.playList.duration = duration

    def positionChangedEvent(self):
        """音乐在Media里以毫秒的形式保存,这里是播放时的进度条。"""
        currentTime = self.position() / 1000
        transedTime = self.transTime(currentTime)
        self.playWidgets.currentTime.setText(transedTime)
        self.timeChanged.emit(transedTime)
        # print(self.transTime(currentTime))

        # position先于duration变化,会出现/0的情况。
        if self.musicTime == 0:
            return
        # *1000是为了与进度条的范围相匹配。
        self.playWidgets.slider.setValue(currentTime / self.musicTime * 1000)

    def stateChangedEvent(self):
        """"""
        if self.state() == 0 and self.playList.mediaCount(
        ) == 0 and self.playWidgets.pauseButton.isVisible():
            self.playWidgets.stopEvent(self)

    # def mediaStatusChangedEvent(self, status):
        """"""
예제 #5
0
class ConfigDetailSings(QObject):
    download = pyqtSignal(dict)

    def __init__(self, parent=None):
        super(ConfigDetailSings, self).__init__()
        self.detailSings = parent
        self.musicList = []

        self.currentIndex = 0

        self.grandparent = self.detailSings.parent
        self.player = self.grandparent.playWidgets.player
        self.playList = self.grandparent.playWidgets
        self.currentMusic = self.grandparent.playWidgets.currentMusic
        self.transTime = transTime

        self.detailSings.singsTable.contextMenuEvent = self.singsFrameContextMenuEvent

        self.bindConnect()
        self.setContextMenu()

    def bindConnect(self):
        self.detailSings.playAllButton.clicked.connect(
            self.addAllMusicToPlayer)
        self.detailSings.singsTable.itemDoubleClicked.connect(
            self.itemDoubleClickedEvent)

    def setContextMenu(self):
        self.actionNextPlay = QAction('下一首播放', self)
        self.actionNextPlay.triggered.connect(self.addToNextPlay)

        self.actionDownloadSong = QAction('下载', self)
        self.actionDownloadSong.triggered.connect(self.downloadSong)

    def addToNextPlay(self):
        data = self.musicList[self.currentIndex]
        self.player.setAllMusics([data])
        self.playList.playList.addMusic(data)
        self.playList.playList.addPlayList(data['name'], data['author'],
                                           data['time'])

    @toTask
    def downloadSong(self, x):
        musicInfo = self.musicList[self.currentIndex]
        url = musicInfo.get('url')
        if 'http:' not in url and 'https:' not in url:
            songId = musicInfo.get('music_id')
            future = aAsync(netease.singsUrl, [songId])
            url = yield from future
            url = url[0].get('url')
            musicInfo['url'] = url

        self.download.emit(musicInfo)

    def addAllMusicToPlayer(self):
        self.playList.setPlayerAndPlaylists(self.musicList)

    def setupDetailFrames(self, datas, singsUrls, singsIds):
        result = datas
        self.musicList = []

        self.detailSings.singsTable.clearContents()

        self.detailSings.titleLabel.setText(result['name'])
        self.detailSings.authorName.setText(result['creator']['nickname'])
        description = result['description']
        # 有些没有简介会报错的。
        if not description:
            description = ''

        self.detailSings.descriptionText.setText(description)
        # 这边添加歌曲的信息到table。
        self.detailSings.singsTable.setRowCount(result['trackCount'])

        for i, j, t, x in zip(result['tracks'], range(result['trackCount']),
                              singsUrls, singsIds):
            names = i['name']
            musicName = QTableWidgetItem(names)
            self.detailSings.singsTable.setItem(j, 0, musicName)

            author = i['artists'][0]['name']
            musicAuthor = QTableWidgetItem(author)
            self.detailSings.singsTable.setItem(j, 1, musicAuthor)

            times = self.transTime(i['duration'] / 1000)
            musicTime = QTableWidgetItem(times)
            self.detailSings.singsTable.setItem(j, 2, musicTime)

            music_img = i['album']['blurPicUrl']

            lyric = i.get('lyric')

            self.musicList.append({
                'url': t,
                'name': names,
                'time': times,
                'author': author,
                'music_img': music_img,
                'music_id': x,
                'lyric': lyric
            })

    # 事件。
    def itemDoubleClickedEvent(self):
        currentRow = self.detailSings.singsTable.currentRow()
        data = self.musicList[currentRow]

        self.playList.setPlayerAndPlayList(data)

    def singsFrameContextMenuEvent(self, event):
        item = self.detailSings.singsTable.itemAt(
            self.detailSings.singsTable.mapFromGlobal(QCursor.pos()))
        self.menu = QMenu(self.detailSings.singsTable)

        self.menu.addAction(self.actionNextPlay)
        self.menu.addAction(self.actionDownloadSong)

        try:
            self.currentIndex = item.row() - 1
        # 在索引是最后一行时会获取不到。
        except:
            self.currentIndex = -1

        self.menu.exec_(QCursor.pos())
예제 #6
0
class ConfigSearchArea(QObject):

    download = pyqtSignal(dict)

    def __init__(self, searchArea):
        super(ConfigSearchArea, self).__init__()

        # current show-table's index.
        self.currentIndex = 0
        # current widgets name。
        self.currentName = '网易云'

        # parent.
        self.searchArea = searchArea

        # get storage folder
        self.downloadFolder = self.searchArea.parent.config.getDownloadFolder()

        self.transTime = addition.itv2time

        self.searchEngineers = {'网易云': netease, '虾米': xiami, 'QQ': qqApi}
        # TODO
        # to config singsFrameBase instead of configing them respective.
        self.searchResultTableIndexs = {
            '网易云': self.searchArea.neteaseSearchFrame.singsResultTable,
            '虾米': self.searchArea.xiamiSearchFrame.singsResultTable,
            'QQ': self.searchArea.qqSearchFrame.singsResultTable
        }

        self.musicList = []
        self.noContents = "很抱歉 未能找到关于<font style='text-align: center;' color='#23518F'>“{0}”</font>的{1}。"

        self.bindConnect()
        self.setContextMenu()

    def bindConnect(self):
        self.searchArea.contentsTab.tabBarClicked.connect(self.searchBy)
        self.searchArea.neteaseSearchFrame.singsResultTable.itemDoubleClicked.connect(
            self.itemDoubleClickedEvent)
        self.searchArea.xiamiSearchFrame.singsResultTable.itemDoubleClicked.connect(
            self.itemDoubleClickedEvent)
        self.searchArea.qqSearchFrame.singsResultTable.itemDoubleClicked.connect(
            self.itemDoubleClickedEvent)

        self.searchArea.neteaseSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent
        self.searchArea.xiamiSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent
        self.searchArea.qqSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent

    def setContextMenu(self):
        self.actionDownloadSong = QAction('下载', self)
        self.actionDownloadSong.triggered.connect(self.downloadSong)

    @toTask
    def downloadSong(self, x):
        # x is useless, but must be.
        #
        musicInfo = self.musicList[self.currentIndex]
        url = musicInfo.get('url')
        if 'http:' not in url and 'https:' not in url:
            songId = musicInfo.get('music_id')
            future = aAsync(netease.singsUrl, [songId])
            url = yield from future
            url = url[0].get('url')
            musicInfo['url'] = url

        self.download.emit(musicInfo)

    def searchBy(self, index):
        currentWidgetName = self.searchArea.contentsTab.tabText(index)
        self.currentName = currentWidgetName
        self.search(currentWidgetName)

    @toTask
    def search(self, name):
        """接受name信息,由这个引擎进行搜索。"""
        searchEngineer = self.searchEngineers[name]
        data = yield from aAsync(searchEngineer.search, self.searchArea.text)
        if not data['songCount']:
            songsIds = []
            data['songs'] = []
        else:
            songsIds = [i['id'] for i in data['songs']]

            if name == '网易云':
                songsDetail = {i: 'http' for i in songsIds}
            elif name == '虾米' or name == 'QQ':
                songsDetail = {i['id']: i['mp3Url'] for i in data['songs']}

            # 进行重新编辑方便索引。
            songs = data['songs']
            data['songs'] = [{
                'name': i['name'],
                'artists': i['ar'],
                'picUrl': i['al']['picUrl'],
                'mp3Url': songsDetail[i['id']],
                'duration': i['dt'],
                'music_id': i['id'],
                'lyric': i.get('lyric')
            } for i in songs]

        songsCount = data['songCount']

        # 总数是0即没有找到。
        if not songsCount:
            songs = []
        else:
            songs = data['songs']

        self.setSingsData(songs)

    def setSingsData(self, data):
        # 单曲搜索结果。
        searchArea = self.searchArea.contentsTab.currentWidget()
        if not len(data):
            # self.contentsTab.addTab()
            searchArea.noSingsContentsLabel.setText(
                self.noContents.format(self.searchArea.text, '单曲'))
            searchArea.singsResultTable.hide()
            searchArea.noSingsContentsLabel.show()
        else:
            searchArea.singsResultTable.setRowCount(len(data))

            musicList = []
            for count, datas in enumerate(data):
                picUrl = datas['picUrl']
                url = datas['mp3Url']
                name = datas['name']
                authors = ','.join([t['name'] for t in datas['artists']])
                duration = self.transTime(datas['duration'] / 1000)
                musicId = datas['music_id']

                searchArea.singsResultTable.setItem(count, 0,
                                                    QTableWidgetItem(name))
                searchArea.singsResultTable.setItem(count, 1,
                                                    QTableWidgetItem(authors))
                searchArea.singsResultTable.setItem(count, 2,
                                                    QTableWidgetItem(duration))
                musicList.append({
                    'url': url,
                    'name': name,
                    'time': duration,
                    'author': authors,
                    'music_img': picUrl,
                    'music_id': musicId
                })

            searchArea.noSingsContentsLabel.hide()
            searchArea.singsResultTable.show()

            self.musicList = musicList

    def itemDoubleClickedEvent(self):
        currentRow = self.searchArea.contentsTab.currentWidget(
        ).singsResultTable.currentRow()
        data = self.musicList[currentRow]
        self.searchArea.parent.playWidgets.setPlayerAndPlayList(data)

    def contextEvent(self, event):
        currentWidget = self.searchResultTableIndexs.get(self.currentName)
        if not currentWidget:
            return

        item = currentWidget.itemAt(currentWidget.mapFromGlobal(QCursor.pos()))
        self.menu = QMenu(currentWidget)

        self.menu.addAction(self.actionDownloadSong)

        try:
            self.currentIndex = item.row() - 1
        # 在索引是最后一行时会获取不到。
        except:
            self.currentIndex = -1

        self.menu.exec_(QCursor.pos())