用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - python代码库

音乐播放器python源码 - pyqt实现

2022-04-25 作者: Python自学举报

[python]代码库

# coding:utf-8
from copy import deepcopy
from pathlib import Path
from random import shuffle
from typing import List

from common import resource
from common.crawler import CrawlerBase
from common.database import DBInitializer
from common.database.entity import AlbumInfo, Playlist, SongInfo
from common.library import Library
from common.os_utils import moveToTrash
from common.signal_bus import signalBus
from common.thread.get_online_song_url_thread import GetOnlineSongUrlThread
from common.thread.library_thread import LibraryThread
from components.dialog_box.create_playlist_dialog import CreatePlaylistDialog
from components.dialog_box.message_dialog import MessageDialog
from components.frameless_window import FramelessWindow
from components.label_navigation_interface import LabelNavigationInterface
from components.media_player import MediaPlaylist, PlaylistType
from components.system_tray_icon import SystemTrayIcon
from components.thumbnail_tool_bar import ThumbnailToolBar
from components.title_bar import TitleBar
from components.video_window import VideoWindow
from components.widgets.stacked_widget import (OpacityAniStackedWidget,
                                               PopUpAniStackedWidget)
from components.widgets.state_tooltip import StateTooltip
from PyQt5.QtCore import QEasingCurve, QEvent, QEventLoop, QFile, Qt, QTimer
from PyQt5.QtGui import QColor, QIcon, QPixmap
from PyQt5.QtMultimedia import QMediaPlayer, QMediaPlaylist
from PyQt5.QtWidgets import (QAction, QApplication, QHBoxLayout, QLabel,
                             QWidget, qApp)
from PyQt5.QtWinExtras import QtWin
from View.album_interface import AlbumInterface
from View.more_search_result_interface import MoreSearchResultInterface
from View.my_music_interface import MyMusicInterface
from View.navigation_interface import NavigationInterface
from View.play_bar import PlayBar
from View.playing_interface import PlayingInterface
from View.playlist_card_interface import PlaylistCardInterface
from View.playlist_interface import PlaylistInterface
from View.search_result_interface import SearchResultInterface
from View.setting_interface import SettingInterface
from View.singer_interface import SingerInterface
from View.smallest_play_interface import SmallestPlayInterface


class MainWindow(FramelessWindow):
    """ Main window """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.isInSelectionMode = False
        self.navigationHistories = [("myMusicInterfaceStackWidget", 0)]
        self.setObjectName("mainWindow")
        self.initDatabase()
        self.createWidgets()
        self.initWidget()

    def initDatabase(self):
        """ initialize database """
        initializer = DBInitializer()
        initializer.init()
        self.db = initializer.db

    def createWidgets(self):
        """ create widgets """
        # main window contains totalStackWidget, playBar and titleBar
        # totalStackWidget contanins subMainWindow, playingInterface and videoWindow
        self.totalStackWidget = OpacityAniStackedWidget(self)

        # subMainWindow is used to put navigation interface and subStackWidget
        self.subMainWindow = QWidget(self)

        # create splash screen
        self.splashScreen = SplashScreen(self)

        # create title bar
        self.titleBar = TitleBar(self)

        # display the window on the desktop first
        self.initWindow()

        # subStackWidget contains myMusicInterface, albumInterface and other interface
        # that need to be displayed on the right side of navigationInterface
        self.subStackWidget = PopUpAniStackedWidget(self.subMainWindow)

        # get online music url thread
        self.getOnlineSongUrlThread = GetOnlineSongUrlThread(self)

        # create setting interface
        self.settingInterface = SettingInterface(self.subMainWindow)

        # create song library
        self.initLibrary()

        # create player and playlist
        self.player = QMediaPlayer(self)
        self.mediaPlaylist = MediaPlaylist(self.library, self)

        # create my music interface
        self.myMusicInterface = MyMusicInterface(
            self.library, self.subMainWindow)

        # create timer to update the position of lyrics
        self.updateLyricPosTimer = QTimer(self)

        # crete thumbnail bar
        self.thumbnailToolBar = ThumbnailToolBar(self)
        self.thumbnailToolBar.setWindow(self.windowHandle())

        # create play bar
        color = self.settingInterface.config['playBar-color']
        self.playBar = PlayBar(
            self.mediaPlaylist.lastSongInfo, QColor(*color), self)

        # create playing interface
        self.playingInterface = PlayingInterface(
            self.mediaPlaylist.playlist, self)

        # create video interface
        self.videoWindow = VideoWindow(self)

        # create album interface
        self.albumInterface = AlbumInterface(
            self.library, parent=self.subMainWindow)

        # create singer interface
        self.singerInterface = SingerInterface(
            self.library, parent=self.subMainWindow)

        # create playlist card interface and playlist interface
        self.playlistCardInterface = PlaylistCardInterface(
            self.library, self.subMainWindow)
        self.playlistInterface = PlaylistInterface(self.library, parent=self)

        # create navigation interface
        self.navigationInterface = NavigationInterface(self.subMainWindow)

        # create label navigation interface
        self.labelNavigationInterface = LabelNavigationInterface(
            self.subMainWindow)

        # create smallest play interface
        self.smallestPlayInterface = SmallestPlayInterface(
            self.mediaPlaylist.playlist, parent=self)

        # create system tray icon
        self.systemTrayIcon = SystemTrayIcon(self)

        # create search result interface
        pageSize = self.settingInterface.config['online-music-page-size']
        quality = self.settingInterface.config['online-play-quality']
        folder = self.settingInterface.config['download-folder']
        self.searchResultInterface = SearchResultInterface(
            self.library, pageSize, quality, folder, self.subMainWindow)

        # create more search result interface
        self.moreSearchResultInterface = MoreSearchResultInterface(
            self.library, self.subMainWindow)

        # create state tooltip
        self.scanInfoTooltip = None

        # create hot keys
        self.togglePlayPauseAct_1 = QAction(
            parent=self, shortcut=Qt.Key_Space, triggered=self.togglePlayState)
        self.showNormalAct = QAction(
            parent=self, shortcut=Qt.Key_Escape, triggered=self.exitFullScreen)
        self.lastSongAct = QAction(
            parent=self, shortcut=Qt.Key_MediaPrevious, triggered=self.mediaPlaylist.previous)
        self.nextSongAct = QAction(
            parent=self, shortcut=Qt.Key_MediaNext, triggered=self.mediaPlaylist.next)
        self.togglePlayPauseAct_2 = QAction(
            parent=self, shortcut=Qt.Key_MediaPlay, triggered=self.togglePlayState)
        self.addActions([
            self.togglePlayPauseAct_1,
            self.showNormalAct,
            self.nextSongAct,
            self.lastSongAct,
            self.togglePlayPauseAct_2,
        ])

        self.songTabSongListWidget = self.myMusicInterface.songListWidget

    def initLibrary(self):
        """ initialize song library """
        self.library = Library(
            self.settingInterface.config["selected-folders"], self.db)
        self.libraryThread = LibraryThread(
            self.settingInterface.config["selected-folders"], self)

        eventLoop = QEventLoop(self)
        self.libraryThread.finished.connect(eventLoop.quit)
        self.libraryThread.start()
        eventLoop.exec()

        self.library.songInfos = self.libraryThread.library.songInfos
        self.library.albumInfos = self.libraryThread.library.albumInfos
        self.library.singerInfos = self.libraryThread.library.singerInfos
        self.library.playlists = self.libraryThread.library.playlists

    def initWindow(self):
        """ initialize window """
        self.resize(1240, 970)
        self.setWindowTitle(self.tr("Groove Music"))
        self.setWindowIcon(QIcon(":/images/logo/logo_small.png"))

        QtWin.enableBlurBehindWindow(self)
        self.setWindowFlags(Qt.FramelessWindowHint |
                            Qt.WindowMinMaxButtonsHint)
        self.windowEffect.addWindowAnimation(self.winId())
        desktop = QApplication.desktop().availableGeometry()
        self.move(desktop.width()//2 - self.width()//2,
                  desktop.height()//2 - self.height()//2)
        self.show()
        QApplication.processEvents()

    def initWidget(self):
        """ initialize widgets """
        self.resize(1240, 970)
        self.setMinimumSize(1030, 800)
        self.videoWindow.hide()

        QApplication.setQuitOnLastWindowClosed(
            not self.settingInterface.config['minimize-to-tray'])

        desktop = QApplication.desktop().availableGeometry()
        self.smallestPlayInterface.move(desktop.width() - 390, 40)

        self.titleBar.raise_()

        # add sub interface to stacked Widget
        self.subStackWidget.addWidget(self.myMusicInterface, 0, 70)
        self.subStackWidget.addWidget(self.playlistCardInterface, 0, 120)
        self.subStackWidget.addWidget(self.settingInterface, 0, 120)
        self.subStackWidget.addWidget(self.albumInterface, 0, 70)
        self.subStackWidget.addWidget(self.singerInterface, 0, 70)
        self.subStackWidget.addWidget(self.playlistInterface, 0, 70)
        self.subStackWidget.addWidget(self.labelNavigationInterface, 0, 100)
        self.subStackWidget.addWidget(self.searchResultInterface, 0, 120)
        self.subStackWidget.addWidget(self.moreSearchResultInterface, 0, 120)
        self.totalStackWidget.addWidget(self.subMainWindow)
        self.totalStackWidget.addWidget(self.playingInterface)
        self.totalStackWidget.addWidget(self.videoWindow)
        self.subMainWindow.setGraphicsEffect(None)

        self.adjustWidgetGeometry()
        self.setQss()

        # Set the interval that the player sends update position signal
        self.player.setNotifyInterval(1000)

        self.updateLyricPosTimer.setInterval(200)

        # set MV quality
        self.playingInterface.getMvUrlThread.setVideoQuality(
            self.settingInterface.config['mv-quality'])

        self.initPlaylist()
        self.connectSignalToSlot()
        self.initPlayBar()

        self.setPlayButtonEnabled(self.songTabSongListWidget.songCardNum() > 0)

        self.navigationInterface.navigationMenu.installEventFilter(self)
        self.updateLyricPosTimer.start()
        self.onInitFinished()

    def onInitFinished(self):
        """ initialize finished slot """
        self.splashScreen.hide()
        self.subStackWidget.show()
        self.navigationInterface.show()
        self.playBar.show()
        self.systemTrayIcon.show()
        self.setWindowEffect(
            self.settingInterface.config["enable-acrylic-background"])

    def setWindowEffect(self, isEnableAcrylic: bool):
        """ set window effect """
        if isEnableAcrylic:
            self.windowEffect.setAcrylicEffect(self.winId(), "F2F2F299", True)
            self.setStyleSheet("#mainWindow{background:transparent}")
        else:
            self.setStyleSheet("#mainWindow{background:#F2F2F2}")
            self.windowEffect.addShadowEffect(self.winId())
            self.windowEffect.removeBackgroundEffect(self.winId())

    def adjustWidgetGeometry(self):
        """ adjust the geometry of widgets """
        self.titleBar.resize(self.width(), 40)
        self.splashScreen.resize(self.size())

        if not hasattr(self, 'playBar'):
            return

        self.subMainWindow.resize(self.size())
        self.totalStackWidget.resize(self.size())
        self.playBar.resize(self.width(), self.playBar.height())
        self.playBar.move(0, self.height()-self.playBar.height())

        if not hasattr(self, "navigationInterface"):
            return

        self.navigationInterface.setOverlay(self.width() < 1280)
        self.subStackWidget.move(self.navigationInterface.width(), 0)
        self.subStackWidget.resize(
            self.width() - self.navigationInterface.width(), self.height())
        self.navigationInterface.resize(
            self.navigationInterface.width(), self.height())

    def setQss(self):
        """ set style sheet """
        self.setObjectName("mainWindow")
        self.subMainWindow.setObjectName("subMainWindow")
        self.subStackWidget.setObjectName("subStackWidget")
        self.playingInterface.setObjectName("playingInterface")

        f = QFile(":/qss/main_window.qss")
        f.open(QFile.ReadOnly)
        self.setStyleSheet(str(f.readAll(), encoding='utf-8'))
        f.close()

    def eventFilter(self, obj, e: QEvent):
        if obj == self.navigationInterface.navigationMenu:
            # 显示导航菜单是更改标题栏返回按钮和标题的父级为导航菜单
            isVisible = self.titleBar.returnButton.isVisible()

            if e.type() == QEvent.Show:
                self.titleBar.returnButton.setParent(obj)

                # show title
                self.titleBar.title.setParent(obj)
                self.titleBar.title.move(15, 10)
                self.titleBar.title.show()

                # shorten the navigation menu if the play bar is visible
                isScaled = self.playBar.isVisible()
                height = self.height() - isScaled * self.playBar.height()
                self.navigationInterface.navigationMenu.setBottomSpacingVisible(
                    not isScaled)
                self.navigationInterface.navigationMenu.resize(
                    self.navigationInterface.navigationMenu.width(), height)
            elif e.type() == QEvent.Hide:
                # hide title
                self.titleBar.title.setParent(self.titleBar)
                self.titleBar.returnButton.setParent(self.titleBar)
                self.titleBar.title.hide()

            self.titleBar.returnButton.setVisible(isVisible)

        return super().eventFilter(obj, e)

    def resizeEvent(self, e):
        super().resizeEvent(e)
        self.adjustWidgetGeometry()
        self.titleBar.maxButton.setMaxState(
            self._isWindowMaximized(int(self.winId())))

    def showEvent(self, e):
        if hasattr(self, 'smallestPlayInterface'):
            self.smallestPlayInterface.hide()

        super().showEvent(e)

    def initPlaylist(self):
        """ initialize playlist """
        self.player.setPlaylist(self.mediaPlaylist)

        if not self.mediaPlaylist.playlist:
            songInfos = self.songTabSongListWidget.songInfos
            self.setPlaylist(songInfos)
            self.mediaPlaylist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
            self.songTabSongListWidget.setPlay(0)
            if songInfos:
                self.systemTrayIcon.updateWindow(songInfos[0])

        if self.mediaPlaylist.lastSongInfo in self.mediaPlaylist.playlist:
            index = self.mediaPlaylist.playlist.index(
                self.mediaPlaylist.lastSongInfo)
            self.mediaPlaylist.setCurrentIndex(index)
            self.playingInterface.setCurrentIndex(index)
            self.smallestPlayInterface.setCurrentIndex(index)
            self.systemTrayIcon.updateWindow(self.mediaPlaylist.lastSongInfo)

            index = self.songTabSongListWidget.index(
                self.mediaPlaylist.lastSongInfo)
            if index is not None:
                self.songTabSongListWidget.setPlay(index)

    def initPlayBar(self):
        """ initialize play bar """
        volume = self.settingInterface.config["volume"]
        self.playBar.setVolume(volume)

        if self.mediaPlaylist.playlist:
            self.playBar.updateWindow(self.mediaPlaylist.getCurrentSong())
            self.playBar.songInfoCard.albumCoverLabel.setOpacity(1)

    def setFullScreen(self, isFullScreen: bool):
        """ set full screen """
        if isFullScreen == self.isFullScreen():
            return

        if not isFullScreen:
            self.exitFullScreen()
            return

        # update title bar
        self.playBar.hide()
        self.titleBar.title.hide()
        self.titleBar.setWhiteIcon(True)
        self.titleBar.hide()

        # switch to playing interface
        self.totalStackWidget.setCurrentIndex(1)
        self.navigationHistories.append(("totalStackWidget", 1))

        self.showFullScreen()
        self.videoWindow.playBar.fullScreenButton.setFullScreen(True)
        self.videoWindow.playBar.fullScreenButton.setToolTip(
            self.tr('Exit fullscreen'))
        self.playingInterface.setFullScreen(True)
        if self.playingInterface.isPlaylistVisible:
            self.playingInterface.songInfoCardChute.move(
                0, 258 - self.height())

    def setVideoFullScreen(self, isFullScreen: bool):
        """ set video interface full screen """
        self.titleBar.setVisible(not isFullScreen)
        self.titleBar.maxButton.setMaxState(isFullScreen)
        self.titleBar.returnButton.show()
        if isFullScreen:
            self.showFullScreen()
        else:
            self.showNormal()

    def setMute(self, isMute: bool):
        """ set whether to mute """
        self.player.setMuted(isMute)
        self.playBar.setMute(isMute)
        self.playingInterface.setMute(isMute)

    def onVolumeChanged(self, volume: int):
        """ volume changed slot """
        self.player.setVolume(volume)
        self.playBar.setVolume(volume)
        self.playingInterface.setVolume(volume)

    def setRandomPlay(self, isRandomPlay: bool):
        """ set whether to play randomly """
        self.mediaPlaylist.setRandomPlay(isRandomPlay)
        self.playingInterface.setRandomPlay(isRandomPlay)
        self.playBar.randomPlayButton.setRandomPlay(isRandomPlay)

    def play(self):
        """ play songs """
        if not self.mediaPlaylist.playlist:
            self.playBar.songInfoCard.hide()
            self.setPlayButtonState(False)
            self.setPlayButtonEnabled(False)
            self.playBar.setTotalTime(0)
            self.playBar.progressSlider.setRange(0, 0)
        else:
            self.player.play()
            self.setPlayButtonState(True)
            self.playBar.songInfoCard.show()

    def setPlaylist(self, playlist: list, index=0):
        """ set playing playlist """
        self.playingInterface.setPlaylist(playlist, index=index)
        self.smallestPlayInterface.setPlaylist(playlist)
        self.mediaPlaylist.setPlaylist(playlist, index)
        self.play()

    def setPlayButtonEnabled(self, isEnabled: bool):
        """ set the enabled state of play buttons """
        self.playBar.playButton.setEnabled(isEnabled)
        self.playBar.nextSongButton.setEnabled(isEnabled)
        self.playBar.lastSongButton.setEnabled(isEnabled)
        self.playingInterface.playBar.playButton.setEnabled(isEnabled)
        self.playingInterface.playBar.nextSongButton.setEnabled(isEnabled)
        self.playingInterface.playBar.lastSongButton.setEnabled(isEnabled)
        self.thumbnailToolBar.playButton.setEnabled(isEnabled)
        self.thumbnailToolBar.nextSongButton.setEnabled(isEnabled)
        self.thumbnailToolBar.lastSongButton.setEnabled(isEnabled)
        self.smallestPlayInterface.playButton.setEnabled(isEnabled)
        self.smallestPlayInterface.lastSongButton.setEnabled(isEnabled)
        self.smallestPlayInterface.nextSongButton.setEnabled(isEnabled)
        self.systemTrayIcon.menu.songAct.setEnabled(isEnabled)
        self.systemTrayIcon.menu.playAct.setEnabled(isEnabled)
        self.systemTrayIcon.menu.lastSongAct.setEnabled(isEnabled)
        self.systemTrayIcon.menu.nextSongAct.setEnabled(isEnabled)

    def setPlayButtonState(self, isPlay: bool):
        """ set the play state of play buttons """
        self.playBar.setPlay(isPlay)
        self.systemTrayIcon.setPlay(isPlay)
        self.playingInterface.setPlay(isPlay)
        self.thumbnailToolBar.setPlay(isPlay)
        self.smallestPlayInterface.setPlay(isPlay)

    def togglePlayState(self):
        """ toggle play state """
        if self.totalStackWidget.currentWidget() is self.videoWindow:
            self.videoWindow.togglePlayState()
            return

        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
            self.setPlayButtonState(False)
            self.thumbnailToolBar.setButtonsEnabled(True)
        else:
            self.play()

    def onPlayerPositionChanged(self, position):
        """ player position changed slot """
        self.playBar.setCurrentTime(position)
        self.playBar.progressSlider.setValue(position)
        self.playingInterface.setCurrentTime(position)
        self.playingInterface.playBar.progressSlider.setValue(position)
        self.smallestPlayInterface.progressBar.setValue(position)

    def onPlayerDurationChanged(self):
        """ player duration changed slot """
        # the duration is 0 when just switching songs
        duration = self.player.duration()
        if duration < 1:
            return

        self.playBar.setTotalTime(duration)
        self.playBar.progressSlider.setRange(0, duration)
        self.playingInterface.playBar.setTotalTime(duration)
        self.playingInterface.playBar.progressSlider.setRange(0, duration)
        self.smallestPlayInterface.progressBar.setRange(0, duration)

    def onMediaStatusChanged(self, status: QMediaPlayer.MediaStatus):
        """ media status changed slot """
        if status != QMediaPlayer.NoMedia:
            return

        self.setPlayButtonState(False)

    def onProgressSliderMoved(self, position):
        """ progress slider moved slot """
        self.player.setPosition(position)
        self.playBar.setCurrentTime(position)
        self.playingInterface.setCurrentTime(position)
        self.smallestPlayInterface.progressBar.setValue(position)

    def switchLoopMode(self, loopMode):
        """ switch loop mode of player """
        self.mediaPlaylist.prePlayMode = loopMode

        self.playBar.setLoopMode(loopMode)
        self.playingInterface.setLoopMode(loopMode)

        if not self.mediaPlaylist.randPlayBtPressed:
            self.mediaPlaylist.setPlaybackMode(loopMode)
        else:
            if self.playBar.loopModeButton.loopMode == QMediaPlaylist.CurrentItemInLoop:
                self.mediaPlaylist.setPlaybackMode(
                    QMediaPlaylist.CurrentItemInLoop)
            else:
                self.mediaPlaylist.setPlaybackMode(QMediaPlaylist.Random)

    def getOnlineSongUrl(self, index: int):
        """ get the play url of online music """
        if index < 0 or not self.mediaPlaylist.playlist:
            return

        songInfo = self.mediaPlaylist.playlist[index]
        if songInfo.file != CrawlerBase.song_url_mark:
            return

        i = self.searchResultInterface.onlineSongInfos.index(songInfo)
        songCard = self.searchResultInterface.onlineSongListWidget.songCards[i]

        # get play url and cover
        eventLoop = QEventLoop(self)
        self.getOnlineSongUrlThread.finished.connect(eventLoop.quit)
        self.getOnlineSongUrlThread.setSongInfo(
            songInfo, self.settingInterface.config['online-play-quality'])
        self.getOnlineSongUrlThread.start()
        eventLoop.exec()

        # TODO:更优雅地更新在线媒体
        songInfo.file = self.getOnlineSongUrlThread.playUrl
        songInfo['coverPath'] = self.getOnlineSongUrlThread.coverPath
        songCard.setSongInfo(songInfo)
        self.mediaPlaylist.insertSong(index, songInfo)
        self.playingInterface.playlist[index] = songInfo
        self.smallestPlayInterface.playlist[index] = songInfo
        self.searchResultInterface.onlineSongInfos[i] = songInfo
        self.mediaPlaylist.removeOnlineSong(index+1)
        self.mediaPlaylist.setCurrentIndex(index)

    def updateWindow(self, index: int):
        """ update main window after switching songs """
        if not self.mediaPlaylist.playlist:
            self.playBar.songInfoCard.hide()
            self.setPlayButtonState(False)
            self.setPlayButtonEnabled(False)
            return

        self.setPlayButtonEnabled(True)

        # handling the situation that song does not exist
        if index < 0:
            return

        songInfo = self.mediaPlaylist.playlist[index]

        # update sub interfaces
        self.playBar.updateWindow(songInfo)
        self.playingInterface.setCurrentIndex(index)
        self.systemTrayIcon.updateWindow(songInfo)

        if self.smallestPlayInterface.isVisible():
            self.smallestPlayInterface.setCurrentIndex(index)

        signalBus.playBySongInfoSig.emit(songInfo)

        self.checkMediaAvailable()

    def checkMediaAvailable(self):
        """ check the availability of media """
        if not self.mediaPlaylist.playlist:
            return

        # determin the availability
        songPath = self.mediaPlaylist.getCurrentSong().file
        if songPath.startswith('http') or Path(songPath).exists():
            return

        # pause player when the media is not available
        self.player.pause()
        self.setPlayButtonState(False)

        # pop up message dialog
        w = MessageDialog(self.tr("Can't play this song"), self.tr(
            "It's not on this device or somewhere we can stream from."), self)
        w.cancelButton.setText(self.tr('Close'))
        w.yesButton.hide()
        w.exec()

    def onMinimizeToTrayChanged(self, isMinimize: bool):
        """ minimize to tray slot """
        QApplication.setQuitOnLastWindowClosed(not isMinimize)

    def onReturnButtonClicked(self):
        """ return button clicked slot """
        if self.isInSelectionMode:
            return

        self.playingInterface.playBar.volumeSliderWidget.hide()

        history = self.navigationHistories.pop()
        if history == ("totalStackWidget", 2):
            self.videoWindow.pause()
            self.totalStackWidget.setCurrentIndex(1)
            return

        # should not return to the playingInterface
        if self.navigationHistories[-1] == ("totalStackWidget", 1):
            self.navigationHistories.pop()

        stackWidget, index = self.navigationHistories[-1]
        if stackWidget == "myMusicInterfaceStackWidget":
            self.myMusicInterface.stackedWidget.setCurrentIndex(index)
            self.subStackWidget.setCurrentIndex(
                0, True, False, 200, QEasingCurve.InCubic)
            self.navigationInterface.setCurrentIndex(0)
            self.myMusicInterface.setSelectedButton(index)
            self.titleBar.setWhiteIcon(False)
        elif stackWidget == "subStackWidget":
            isShowNextWidgetDirectly = self.subStackWidget.currentWidget() is not self.settingInterface
            self.subStackWidget.setCurrentIndex(
                index, True, isShowNextWidgetDirectly, 200, QEasingCurve.InCubic)
            self.navigationInterface.setCurrentIndex(index)

            # update icon color of title bar
            whiteIndexes = [self.subStackWidget.indexOf(
                i) for i in [self.albumInterface, self.playlistInterface, self.singerInterface]]
            self.titleBar.setWhiteIcon(index in whiteIndexes)
            self.titleBar.returnButton.setWhiteIcon(False)

        self.hidePlayingInterface()

        if len(self.navigationHistories) == 1:
            self.titleBar.returnButton.hide()

    def showLabelNavigationInterface(self, labels: list, layout: str):
        """ show label navigation interface """
        self.labelNavigationInterface.setLabels(labels, layout)
        self.switchToSubInterface(self.labelNavigationInterface)

    def showSmallestPlayInterface(self):
        """ show smallest play interface """
        self.smallestPlayInterface.setCurrentIndex(
            self.mediaPlaylist.currentIndex())
        self.hide()
        self.smallestPlayInterface.show()

    def showVideoWindow(self, url: str):
        """ show video window """
        self.player.pause()
        self.setPlayButtonState(False)

        songInfo = self.mediaPlaylist.getCurrentSong()
        self.videoWindow.setVideo(url, songInfo.singer+' - '+songInfo.title)
        self.totalStackWidget.setCurrentIndex(2)

        self.navigationHistories.append(("totalStackWidget", 2))
        self.titleBar.returnButton.show()

    def exitSmallestPlayInterface(self):
        """ exit smallest play interface """
        self.smallestPlayInterface.hide()
        self.show()

    def hidePlayingInterface(self):
        """ hide playing interface """
        if not self.playingInterface.isVisible():
            return

        self.playBar.show()
        self.totalStackWidget.setCurrentIndex(0)

        # set the icon color of title bar
        whiteInterface = [self.albumInterface,
                          self.playlistInterface, self.singerInterface]
        if self.subStackWidget.currentWidget() in whiteInterface:
            self.titleBar.returnButton.setWhiteIcon(False)
        else:
            self.titleBar.setWhiteIcon(False)

        # hide return button
        cond = self.subStackWidget.currentWidget() not in [
            self.labelNavigationInterface, self.albumInterface]
        if len(self.navigationHistories) == 1 and cond:
            self.titleBar.returnButton.hide()

        self.titleBar.title.setVisible(self.navigationInterface.isExpanded)

    def showPlayingInterface(self):
        """ show playing interface """
        self.show()

        if self.playingInterface.isVisible():
            return

        self.exitSelectionMode()
        self.playBar.hide()
        self.titleBar.title.hide()
        self.titleBar.returnButton.show()

        if not self.playingInterface.isPlaylistVisible and len(self.playingInterface.playlist) > 0:
            self.playingInterface.songInfoCardChute.move(
                0, -self.playingInterface.playBar.height() + 68)
            self.playingInterface.playBar.show()

        self.totalStackWidget.setCurrentIndex(1)
        self.titleBar.setWhiteIcon(True)

        self.navigationHistories.append(("totalStackWidget", 1))

    def showPlayingPlaylist(self):
        """ show playing playlist """
        self.playingInterface.showPlaylist()
        self.playingInterface.playBar.pullUpArrowButton.setArrowDirection(
            "down")
        if self.playingInterface.isPlaylistVisible:
            self.showPlayingInterface()

    def clearPlaylist(self):
        """ clear playlist """
        self.mediaPlaylist.playlistType = PlaylistType.NO_PLAYLIST
        self.mediaPlaylist.clear()
        self.playingInterface.clearPlaylist()
        self.smallestPlayInterface.clearPlaylist()
        self.playBar.songInfoCard.hide()
        self.setPlayButtonState(False)
        self.setPlayButtonEnabled(False)

        self.songTabSongListWidget.cancelPlayState()
        self.albumInterface.songListWidget.cancelPlayState()
        self.playlistInterface.songListWidget.cancelPlayState()
        self.searchResultInterface.localSongListWidget.cancelPlayState()
        self.searchResultInterface.onlineSongListWidget.cancelPlayState()

        self.playBar.setTotalTime(0)
        self.playBar.progressSlider.setRange(0, 0)

    def onNavigationDisplayModeChanged(self, disPlayMode: int):
        """ navigation interface display mode changed slot """
        self.titleBar.title.setVisible(self.navigationInterface.isExpanded)
        self.adjustWidgetGeometry()
        self.navigationInterface.navigationMenu.stackUnder(self.playBar)
        # 如果现在显示的是字母导航界面就将其隐藏
        if self.subStackWidget.currentWidget() is self.labelNavigationInterface:
            self.subStackWidget.setCurrentIndex(0)

    def onSelectionModeStateChanged(self, isOpen: bool):
        """ selection mode state changed slot """
        self.isInSelectionMode = isOpen
        if not self.playingInterface.isVisible():
            self.playBar.setHidden(isOpen)

    def exitSelectionMode(self):
        """ exit selection mode """
        if not self.isInSelectionMode:
            return

        self.myMusicInterface.exitSelectionMode()
        self.albumInterface.exitSelectionMode()
        self.playlistCardInterface.exitSelectionMode()
        self.playlistInterface.exitSelectionMode()
        self.playingInterface.exitSelectionMode()
        self.singerInterface.exitSelectionMode()

    def exitFullScreen(self):
        """ exit full screen """
        if not self.isFullScreen():
            return

        self.showNormal()

        # 更新最大化按钮图标
        self.titleBar.maxButton.setMaxState(False)
        self.titleBar.returnButton.show()
        self.titleBar.show()

        self.videoWindow.playBar.fullScreenButton.setFullScreen(False)
        self.playingInterface.setFullScreen(False)
        if self.playingInterface.isPlaylistVisible:
            self.playingInterface.songInfoCardChute.move(
                0, 258 - self.height())

    def appendSubStackWidgetHistory(self, widget: QWidget):
        """ push the switching history of sub interface """
        index = self.subStackWidget.indexOf(widget)
        if self.navigationHistories[-1] == ("subStackWidget", index):
            return

        self.navigationHistories.append(('subStackWidget', index))

    def switchToSubInterface(self, widget: QWidget, whiteIcon=False, whiteReturn=False):
        """ switch to sub interface in `subStackWidget`

        Parameters
        ----------
        widget: QWidget
            the interface to be displayed

        whiteIcon: bool
            whether to set the icon color of title bar to white

        whiteReturn: bool
            Whether to set the return button to a white button
        """
        self.titleBar.returnButton.show()
        self.titleBar.setWhiteIcon(whiteIcon)
        self.titleBar.returnButton.setWhiteIcon(whiteReturn)

        # switch interface
        self.exitSelectionMode()
        self.playBar.show()
        self.totalStackWidget.setCurrentIndex(0)
        self.subStackWidget.setCurrentWidget(widget)
        self.appendSubStackWidgetHistory(widget)

    def switchToSettingInterface(self):
        """ switch to setting interface """
        self.show()

        # TODO: 从视频界面直接切换回设置界面
        if self.videoWindow.isVisible():
            return

        if self.playingInterface.isVisible():
            self.titleBar.returnButton.click()

        self.switchToSubInterface(self.settingInterface)

    def switchToMyMusicInterface(self):
        """ switch to my music interface """
        self.exitSelectionMode()
        self.subStackWidget.setCurrentWidget(self.myMusicInterface)
        self.appendSubStackWidgetHistory(self.myMusicInterface)

    def switchToPlaylistInterface(self, name: str):
        """ switch to playlist interface """
        if self.isInSelectionMode:
            return

        playlist = self.library.playlistController.getPlaylist(name)
        if not playlist:
            return

        self.playlistInterface.updateWindow(playlist)
        self.switchToSubInterface(self.playlistInterface, True)
        self.playlistInterface.songListWidget.setPlayBySongInfo(
            self.mediaPlaylist.getCurrentSong())

    def switchToPlaylistCardInterface(self):
        """ switch to playlist card interface """
        self.switchToSubInterface(self.playlistCardInterface)

    def switchToSearchResultInterface(self, keyWord: str):
        """ switch to search result interface """
        self.searchResultInterface.search(keyWord)
        self.switchToSubInterface(self.searchResultInterface)
        self.searchResultInterface.localSongListWidget.setPlayBySongInfo(
            self.mediaPlaylist.getCurrentSong())

    def switchToMoreSearchResultInterface(self, keyWord: str, viewType, data: list):
        """ switch to more search result interface """
        self.moreSearchResultInterface.updateWindow(keyWord, viewType, data)
        self.switchToSubInterface(self.moreSearchResultInterface)
        self.moreSearchResultInterface.localSongListWidget.setPlayBySongInfo(
            self.mediaPlaylist.getCurrentSong())

    def switchToSingerInterface(self, singer: str):
        """ switch to singer interface """
        if self.isInSelectionMode:
            return

        singerInfo = self.library.singerInfoController.getSingerInfoByName(
            singer)
        if not singerInfo:
            return

        self.exitFullScreen()
        self.singerInterface.updateWindow(singerInfo)
        self.switchToSubInterface(self.singerInterface, True)
        self.singerInterface.albumBlurBackground.hide()

    def switchToAlbumInterface(self, singer: str, album: str):
        """ switch to album interface """
        if self.isInSelectionMode:
            return

        albumInfo = self.library.albumInfoController.getAlbumInfo(
            singer, album)
        if not albumInfo:
            return

        self.exitFullScreen()
        self.albumInterface.updateWindow(albumInfo)
        self.switchToSubInterface(self.albumInterface, True)
        self.albumInterface.songListWidget.setPlayBySongInfo(
            self.mediaPlaylist.getCurrentSong())

    def switchToAlbumCardInterface(self):
        """ switch to album card interface """
        self.subStackWidget.setCurrentWidget(self.myMusicInterface)
        self.titleBar.setWhiteIcon(False)
        self.titleBar.returnButton.show()
        self.myMusicInterface.setCurrentTab(1)
        self.navigationInterface.setCurrentIndex(0)

        # add navigation history
        index = self.myMusicInterface.stackedWidget.indexOf(
            self.myMusicInterface.albumTabInterface)
        self.navigationHistories.append(('myMusicInterfaceStackWidget', index))

    def onMyMusicInterfaceStackWidgetIndexChanged(self, index):
        """ my music interface tab index changed slot """
        self.navigationHistories.append(("myMusicInterfaceStackWidget", index))
        self.titleBar.returnButton.show()

    def onSongTabSongCardPlay(self, songInfo: SongInfo):
        """ song tab interface play song card slot """
        songInfos = self.songTabSongListWidget.songInfos

        if self.mediaPlaylist.playlistType != PlaylistType.ALL_SONG_PLAYLIST \
                or songInfos != self.mediaPlaylist.playlist:
            self.mediaPlaylist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
            songInfos = self.songTabSongListWidget.songInfos
            index = songInfos.index(songInfo)
            playlist = songInfos[index:] + songInfos[:index]
            self.setPlaylist(playlist)

        self.mediaPlaylist.setCurrentSong(songInfo)

    def onPlaylistInterfaceSongCardPlay(self, index):
        """ playlist interface song card play slot """
        songInfos = self.playlistInterface.songInfos
        self.playCustomPlaylistSong(songInfos, index)

    def playOneSongCard(self, songInfo: SongInfo):
        """ reset the playing playlist to one song """
        self.mediaPlaylist.playlistType = PlaylistType.SONG_CARD_PLAYLIST
        self.setPlaylist([songInfo])

    def updatePlaylist(self, reset=False):
        """ update playing playlist """
        playlist = self.mediaPlaylist.playlist
        self.playingInterface.setPlaylist(playlist, reset)
        self.smallestPlayInterface.setPlaylist(playlist, reset)
        self.play()

    def onSongsNextToPlay(self, songInfos: List[SongInfo]):
        """ songs next to play slot """
        reset = not self.mediaPlaylist.playlist
        index = self.mediaPlaylist.currentIndex()
        self.mediaPlaylist.insertSongs(index + 1, songInfos)
        self.updatePlaylist(reset)

    def addSongsToPlayingPlaylist(self, songInfos: list):
        """ add songs to playing playlist """
        reset = not self.mediaPlaylist.playlist
        self.mediaPlaylist.addSongs(songInfos)
        self.updatePlaylist(reset)

    def addSongsToCustomPlaylist(self, name: str, songInfos: List[SongInfo]):
        """ add songs to custom playlist """

        def resetSongInfo(songInfos: list, diffSongInfos):
            songInfos.clear()
            songInfos.extend(diffSongInfos)

        songInfos = deepcopy(songInfos)

        # find new songs
        oldPlaylist = self.library.playlistController.getPlaylist(name)
        oldFiles = [i.file for i in oldPlaylist.songInfos]
        diffSongInfos = [i for i in songInfos if i.file not in oldFiles]

        planToAddNum = len(songInfos)
        repeatNum = planToAddNum-len(diffSongInfos)

        # show dialog box if there are duplicate songs
        if repeatNum > 0:
            if planToAddNum == 1:
                content = self.tr(
                    "This song is already in your playlist. Do you want to add?")
            elif repeatNum < planToAddNum:
                content = self.tr(
                    "Some songs are already in your playlist. Do you want to add?")
            else:
                content = self.tr(
                    "All these songs are already in your playlist. Do you want to add?")

            w = MessageDialog(self.tr("Song duplication"), content, self)
            w.cancelSignal.connect(
                lambda: resetSongInfo(songInfos, diffSongInfos))
            w.exec_()

        success = self.library.playlistController.addSongs(name, songInfos)
        if not success:
            return

        self.playlistCardInterface.addSongsToPlaylist(name, songInfos)
        self.searchResultInterface.playlistGroupBox.playlistCardView.addSongsToPlaylistCard(
            name, songInfos)
        self.moreSearchResultInterface.playlistInterface.playlistCardView.addSongsToPlaylistCard(
            name, songInfos)

    def removeSongsFromCustomPlaylist(self, name: str, songInfos: List[SongInfo]):
        """ remove songs from custom playlist """
        success = self.library.playlistController.removeSongs(name, songInfos)
        if not success:
            return

        self.playlistCardInterface.removeSongsFromPlaylist(name, songInfos)
        self.searchResultInterface.playlistGroupBox.playlistCardView.removeSongsFromPlaylistCard(
            name, songInfos)
        self.moreSearchResultInterface.playlistInterface.playlistCardView.removeSongsFromPlaylistCard(
            name, songInfos)

    def playAlbum(self, singer: str, album: str, index=0):
        """ play songs in an album """
        albumInfo = self.library.albumInfoController.getAlbumInfo(
            singer, album)
        if not albumInfo:
            return

        playlist = albumInfo.songInfos
        self.playingInterface.setPlaylist(playlist, index=index)
        self.smallestPlayInterface.setPlaylist(playlist)
        self.mediaPlaylist.playAlbum(playlist, index)
        self.play()

    def playAbumSong(self, index: int):
        """ play the song in an album """
        if self.mediaPlaylist.playlistType != PlaylistType.ALBUM_CARD_PLAYLIST or \
                self.mediaPlaylist.playlist != self.albumInterface.songInfos:
            self.playAlbum(self.albumInterface.singer,
                           self.albumInterface.album, index)

        self.mediaPlaylist.setCurrentIndex(index)

    def playCustomPlaylist(self, songInfos: list, index=0):
        """ play songs in custom playlist """
        self.mediaPlaylist.playlistType = PlaylistType.CUSTOM_PLAYLIST
        self.setPlaylist(songInfos, index)

    def playCustomPlaylistSong(self, songInfos: List[SongInfo], index: int):
        """ play the song in a custom playlist  """
        if self.mediaPlaylist.playlistType != PlaylistType.CUSTOM_PLAYLIST or \
                self.mediaPlaylist.playlist != songInfos:
            self.playCustomPlaylist(songInfos, index)

        self.mediaPlaylist.setCurrentIndex(index)

    def playLocalSearchedSong(self, index: int):
        """ play selected local searched song """
        songInfos = self.searchResultInterface.localSongListWidget.songInfos
        self.playCustomPlaylistSong(songInfos, index)

    def playOnlineSearchedSong(self, index: int):
        """ play selected online searched song """
        songInfos = self.searchResultInterface.onlineSongListWidget.songInfos
        self.playCustomPlaylistSong(songInfos, index)

    def playLocalMoreSearchedSong(self, songInfo: SongInfo):
        """ play selected local more searched song """
        songInfos = self.moreSearchResultInterface.localSongListWidget.songInfos
        index = songInfos.index(songInfo)
        self.playCustomPlaylistSong(songInfos, index)

    def randomPlayAll(self):
        """ play all songs randomly """
        self.mediaPlaylist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
        playlist = self.songTabSongListWidget.songInfos.copy()
        shuffle(playlist)
        self.setPlaylist(playlist)

    def onEditSongInfo(self, oldSongInfo: SongInfo, newSongInfo: SongInfo):
        """ edit song information slot """
        self.library.updateSongInfo(newSongInfo)
        self.mediaPlaylist.updateSongInfo(newSongInfo)
        self.playingInterface.updateSongInfo(newSongInfo)
        self.myMusicInterface.updateSongInfo(newSongInfo)
        self.playlistInterface.updateSongInfo(newSongInfo)
        self.albumInterface.updateSongInfo(newSongInfo)
        self.searchResultInterface.localSongListWidget.updateOneSongCard(
            newSongInfo)

    def onEditAlbumInfo(self, oldAlbumInfo: AlbumInfo, newAlbumInfo: AlbumInfo, coverPath: str):
        """ edit album information slot """
        songInfos = newAlbumInfo.songInfos
        self.library.updateMultiSongInfos(songInfos)
        self.mediaPlaylist.updateMultiSongInfos(songInfos)
        self.myMusicInterface.updateMultiSongInfos(songInfos)
        self.playingInterface.updateMultiSongInfos(songInfos)
        self.playlistInterface.updateMultiSongInfos(songInfos)
        self.albumInterface.updateMultiSongInfos(songInfos)
        self.searchResultInterface.localSongListWidget.updateMultiSongCards(
            songInfos)

    def deleteSongs(self, songPaths: List[str]):
        """ delete songs from local """
        for songPath in songPaths:
            moveToTrash(songPath)

    def onUpdateLyricPosTimeOut(self):
        """ update lyric postion timer time out """
        if self.player.state() != QMediaPlayer.PlayingState:
            return

        t = self.player.position()
        self.playingInterface.lyricWidget.setCurrentTime(t)

    def onPlayingInterfaceCurrentIndexChanged(self, index):
        """ playing interface current index changed slot """
        self.mediaPlaylist.setCurrentIndex(index)
        self.play()

    def onExit(self):
        """ exit main window """
        config = {
            "volume": self.playBar.volumeSlider.value(),
            "playBar-color": list(self.playBar.getColor().getRgb()[:3])
        }
        self.settingInterface.config.update(config)
        self.mediaPlaylist.save()
        self.systemTrayIcon.hide()

    def onNavigationLabelClicked(self, label: str):
        """ navigation label clicked slot """
        self.myMusicInterface.scrollToLabel(label)
        self.subStackWidget.setCurrentWidget(
            self.subStackWidget.previousWidget)
        self.navigationHistories.pop()

    def onSelectedFolderChanged(self, directories: List[str]):
        """ selected music folders changed slot """
        title = self.tr("Scanning song information")
        content = self.tr("Please wait patiently")
        self.scanInfoTooltip = StateTooltip(title, content, self.window())
        self.scanInfoTooltip.move(self.scanInfoTooltip.getSuitablePos())
        self.scanInfoTooltip.show()

        self.libraryThread.setTask(
            self.libraryThread.library.setDirectories, directories=directories)
        self.libraryThread.start()

    def onReloadFinished(self):
        """ reload library finished slot """
        self.libraryThread.library.copyTo(self.library)
        self.myMusicInterface.updateWindow()

        if self.scanInfoTooltip:
            self.scanInfoTooltip.setState(True)

        self.scanInfoTooltip = None

    def showCreatePlaylistDialog(self, songInfos: List[SongInfo] = None):
        """ show create playlist dialog box """
        w = CreatePlaylistDialog(self.library, songInfos, self)
        w.createPlaylistSig.connect(self.onCreatePlaylist)
        w.exec_()

    def onCreatePlaylist(self, name: str, playlist: Playlist):
        """ create a playlist """
        self.playlistCardInterface.addPlaylistCard(name, playlist)
        self.navigationInterface.updateWindow()

    def onRenamePlaylist(self, old: str, new: str):
        """ rename a playlist """
        success = self.library.playlistController.rename(old, new)
        if not success:
            return

        self.navigationInterface.updateWindow()
        self.playlistCardInterface.renamePlaylist(old, new)
        self.searchResultInterface.playlistGroupBox.playlistCardView.renamePlaylistCard(
            old, new)
        self.moreSearchResultInterface.playlistInterface.playlistCardView.renamePlaylistCard(
            old, new)

    def onDeleteCustomPlaylist(self, name: str):
        """ delete a playlist """
        success = self.library.playlistController.delete(name)
        if not success:
            return

        self.navigationInterface.updateWindow()
        self.playlistCardInterface.deletePlaylistCard(name)
        self.searchResultInterface.deletePlaylistCard(name)
        self.moreSearchResultInterface.playlistInterface.playlistCardView.deletePlaylistCard(
            name)

        if self.playlistInterface.isVisible():
            self.titleBar.returnButton.click()

        N = len(self.moreSearchResultInterface.playlistInterface.playlistCards)
        if self.moreSearchResultInterface.playlistInterface.isVisible() and N == 0:
            self.titleBar.returnButton.click()

    def onFileRemoved(self, files: List[str]):
        """ files removed slot """
        self.myMusicInterface.deleteSongs(files)
        self.albumInterface.songListWidget.removeSongCards(files)
        self.searchResultInterface.localSongListWidget.removeSongCards(files)
        self.moreSearchResultInterface.localSongListWidget.removeSongCards(
            files)

    def onFileAdded(self, songInfos: List[SongInfo]):
        """ files add slot """
        self.myMusicInterface.updateWindow()

    def onCrawMetaDataFinished(self):
        """ craw meta data finished slot """
        self.library.load()
        self.myMusicInterface.updateWindow()

    def connectSignalToSlot(self):
        """ connect signal to slot """

        # player signal
        self.player.positionChanged.connect(self.onPlayerPositionChanged)
        self.player.durationChanged.connect(self.onPlayerDurationChanged)
        self.player.mediaStatusChanged.connect(self.onMediaStatusChanged)

        # media playlist signal
        self.mediaPlaylist.currentIndexChanged.connect(self.getOnlineSongUrl)
        self.mediaPlaylist.currentIndexChanged.connect(self.updateWindow)

        # setting interface signal
        self.settingInterface.acrylicEnableChanged.connect(
            self.setWindowEffect)
        self.settingInterface.selectedMusicFoldersChanged.connect(
            self.onSelectedFolderChanged)
        self.settingInterface.downloadFolderChanged.connect(
            self.searchResultInterface.setDownloadFolder)
        self.settingInterface.onlinePlayQualityChanged.connect(
            self.searchResultInterface.setOnlinePlayQuality)
        self.settingInterface.pageSizeChanged.connect(
            self.searchResultInterface.setOnlineMusicPageSize)
        self.settingInterface.mvQualityChanged.connect(
            self.playingInterface.getMvUrlThread.setVideoQuality)
        self.settingInterface.minimizeToTrayChanged.connect(
            self.onMinimizeToTrayChanged)
        self.settingInterface.crawlFinished.connect(
            self.onCrawMetaDataFinished)

        # title signal
        self.titleBar.returnButton.clicked.connect(self.onReturnButtonClicked)

        # navigation interface signal
        self.navigationInterface.displayModeChanged.connect(
            self.onNavigationDisplayModeChanged)
        self.navigationInterface.showCreatePlaylistDialogSig.connect(
            self.showCreatePlaylistDialog)
        self.navigationInterface.searchSig.connect(
            self.switchToSearchResultInterface)

        # play bar signal
        self.playBar.savePlaylistSig.connect(
            lambda: self.showCreatePlaylistDialog(self.mediaPlaylist.playlist))

        # signal bus signal
        signalBus.nextSongSig.connect(self.mediaPlaylist.next)
        signalBus.lastSongSig.connect(self.mediaPlaylist.previous)
        signalBus.togglePlayStateSig.connect(self.togglePlayState)
        signalBus.progressSliderMoved.connect(self.onProgressSliderMoved)

        signalBus.muteStateChanged.connect(self.setMute)
        signalBus.volumeChanged.connect(self.onVolumeChanged)

        signalBus.loopModeChanged.connect(self.switchLoopMode)
        signalBus.randomPlayChanged.connect(self.setRandomPlay)

        signalBus.fullScreenChanged.connect(self.setFullScreen)

        signalBus.playAlbumSig.connect(self.playAlbum)
        signalBus.randomPlayAllSig.connect(self.randomPlayAll)
        signalBus.playCheckedSig.connect(self.playCustomPlaylist)
        signalBus.playOneSongCardSig.connect(self.playOneSongCard)
        signalBus.nextToPlaySig.connect(self.onSongsNextToPlay)

        signalBus.editSongInfoSig.connect(self.onEditSongInfo)
        signalBus.editAlbumInfoSig.connect(self.onEditAlbumInfo)

        signalBus.addSongsToPlayingPlaylistSig.connect(
            self.addSongsToPlayingPlaylist)
        signalBus.addSongsToCustomPlaylistSig.connect(
            self.addSongsToCustomPlaylist)
        signalBus.addSongsToNewCustomPlaylistSig.connect(
            self.showCreatePlaylistDialog)
        signalBus.selectionModeStateChanged.connect(
            self.onSelectionModeStateChanged)

        signalBus.removeSongSig.connect(self.deleteSongs)
        signalBus.clearPlayingPlaylistSig.connect(self.clearPlaylist)
        signalBus.deletePlaylistSig.connect(self.onDeleteCustomPlaylist)
        signalBus.renamePlaylistSig.connect(self.onRenamePlaylist)

        signalBus.showPlayingPlaylistSig.connect(self.showPlayingPlaylist)
        signalBus.showPlayingInterfaceSig.connect(self.showPlayingInterface)
        signalBus.switchToSingerInterfaceSig.connect(
            self.switchToSingerInterface)
        signalBus.switchToAlbumInterfaceSig.connect(
            self.switchToAlbumInterface)
        signalBus.switchToMyMusicInterfaceSig.connect(
            self.switchToMyMusicInterface)
        signalBus.switchToPlaylistInterfaceSig.connect(
            self.switchToPlaylistInterface)
        signalBus.switchToPlaylistCardInterfaceSig.connect(
            self.switchToPlaylistCardInterface)
        signalBus.switchToSettingInterfaceSig.connect(
            self.switchToSettingInterface)
        signalBus.switchToMoreSearchResultInterfaceSig.connect(
            self.switchToMoreSearchResultInterface)
        signalBus.showSmallestPlayInterfaceSig.connect(
            self.showSmallestPlayInterface)
        signalBus.showLabelNavigationInterfaceSig.connect(
            self.showLabelNavigationInterface)

        # playing interface signal
        self.playingInterface.currentIndexChanged.connect(
            self.onPlayingInterfaceCurrentIndexChanged)
        self.playingInterface.removeSongSignal.connect(
            self.mediaPlaylist.removeSong)
        self.playingInterface.selectionModeStateChanged.connect(
            self.onSelectionModeStateChanged)
        self.playingInterface.switchToVideoInterfaceSig.connect(
            self.showVideoWindow)

        # song tab interface song list widget signal
        self.songTabSongListWidget.playSignal.connect(
            self.onSongTabSongCardPlay)

        # my music interface signal
        self.myMusicInterface.currentIndexChanged.connect(
            self.onMyMusicInterfaceStackWidgetIndexChanged)

        # update lyrics position timer signal
        self.updateLyricPosTimer.timeout.connect(self.onUpdateLyricPosTimeOut)

        # album interface signal
        self.albumInterface.songCardPlaySig.connect(
            self.playAbumSong)

        # playlist interface signal
        self.playlistInterface.songCardPlaySig.connect(
            self.onPlaylistInterfaceSongCardPlay)
        self.playlistInterface.removeSongSig.connect(
            self.removeSongsFromCustomPlaylist)
        self.playlistInterface.switchToAlbumCardInterfaceSig.connect(
            self.switchToAlbumCardInterface)

        # playlist card interface signal
        self.playlistCardInterface.createPlaylistSig.connect(
            self.showCreatePlaylistDialog)

        # smallest play interface signal
        self.smallestPlayInterface.exitSmallestPlayInterfaceSig.connect(
            self.exitSmallestPlayInterface)

        # label navigation interface signal
        self.labelNavigationInterface.labelClicked.connect(
            self.onNavigationLabelClicked)

        # search result interface signal
        self.searchResultInterface.playLocalSongSig.connect(
            self.playLocalSearchedSong)
        self.searchResultInterface.playOnlineSongSig.connect(
            self.playOnlineSearchedSong)

        # more search result interface signal
        self.moreSearchResultInterface.playLocalSongSig.connect(
            self.playLocalMoreSearchedSong)

        # system tray icon signal
        qApp.aboutToQuit.connect(self.onExit)
        self.systemTrayIcon.exitSignal.connect(qApp.quit)
        self.systemTrayIcon.showMainWindowSig.connect(self.show)

        # video window signal
        self.videoWindow.fullScreenChanged.connect(self.setVideoFullScreen)

        # library thread signal
        self.libraryThread.reloadFinished.connect(self.onReloadFinished)

        # library signal
        self.library.fileAdded.connect(self.onFileAdded)
        self.library.fileRemoved.connect(self.onFileRemoved)


class SplashScreen(QWidget):
    """ Splash screen """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.hBoxLayout = QHBoxLayout(self)
        self.logo = QLabel(self)
        self.logo.setPixmap(QPixmap(":/images/logo/splash_screen_logo.png"))
        self.hBoxLayout.addWidget(self.logo, 0, Qt.AlignCenter)
        self.setAttribute(Qt.WA_StyledBackground)
        self.setStyleSheet('background:white')

via:https://github.com/zhiyiYo/Groove

[代码运行效果截图]


音乐播放器python源码 - pyqt实现

[源代码打包下载]




网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...