Beispiel #1
0
class MusicList(QListWidget):
    def __init__(self):
        super(MusicList, self).__init__()
        self.__musicList = []
        self.setFixedWidth(250)
        self.setFont(QFont('宋体', 10,))
        self.setObjectName('musicList')
        self.setStyleSheet('#musicList{background-color: rgba(0, 0, 0, 120); color: "green";} #musicList:item{height: 25;}')
        self.itemDoubleClicked.connect(self.music_double_clicked)

        # 初始化多媒体播放器和播放列表
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist(self.player)
        self.player.setPlaylist(self.playlist)

    def add_music_item(self, file_names):
        for file in file_names:
            self.addItem(file.split('/')[-1])
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(file)))

    def music_double_clicked(self):
        music_list_index = self.currentRow()
        self.music_play(music_list_index)

    def music_play(self, music_list_index):
        self.playlist.setCurrentIndex(music_list_index)
        self.player.play()

    def add_network_music(self, music_name, music_url):
        print(music_name)
        self.addItem(music_name)
        self.playlist.addMedia(QMediaContent(QUrl(music_url)))
Beispiel #2
0
class LolitaPlayer(QMediaPlayer):
    """控制萝莉声音"""

    def __init__(self, playList = [], ddir = "data", parent = None):
        """
        @param dfile: 萝莉的音乐配置文件
        """
        QMediaPlayer.__init__(self, parent)
        # super(LolitaMusic, self).__init__(parent)
        try:
            # 播放列表
            self.playList = QMediaPlaylist(parent)
            # 设置只播放一次
            self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemOnce)
            # 读取配置文件中的音乐路径
            self._playList = playList
            # 添加到列表里
            self.playList.addMedia([QMediaContent(QUrl(item[1].format(DATA_DIR = ddir))) for item in self._playList])
            self.playList.setCurrentIndex(0)

            # 设置播放列表
            self.setPlaylist(self.playList)
            # 设置音量
            self.setVolume(100)
        except Exception as e:
            traceback.print_exc(e)

    def __del__(self):
        if hasattr(self, "playList"):
            del self.playList

    def currentIndex(self):
        if hasattr(self, "playList"):
            return self.playList.currentIndex()
        return 0

    def mediaCount(self):
        if hasattr(self, "_playList"):
            return len(self._playList)
        return 0

    def setCurrentIndex(self, i):
        if hasattr(self, "playList"):
            self.playList.setCurrentIndex(i)

    def getText(self, i):
        """获取当前歌曲对应的文字"""
        if hasattr(self, "_playList"):
            try: return self._playList[i][0]
            except Exception as e: traceback.print_exc(e)
        return ""

    def play(self, i):
        """播放指定的歌曲"""
        if hasattr(self, "playList"):
            self.playList.setCurrentIndex(i)    # 切换到第几首
            QMediaPlayer.play(self)    # 播放一次

    def stop(self):
        QMediaPlayer.stop(self)
Beispiel #3
0
class MusicList(QListWidget):
    def __init__(self):
        super(MusicList, self).__init__()
        self.__musicList = []
        self.setFixedWidth(250)
        self.setFont(QFont(
            '宋体',
            10,
        ))
        self.setObjectName('musicList')
        self.setStyleSheet(
            '#musicList{background-color: rgba(0, 0, 0, 120); color: "green";} #musicList:item{height: 25;}'
        )
        self.itemDoubleClicked.connect(self.music_double_clicked)

        # 初始化多媒体播放器和播放列表
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist(self.player)
        self.player.setPlaylist(self.playlist)

    def add_music_item(self, file_names):
        for file in file_names:
            self.addItem(file.split('/')[-1])
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(file)))

    def music_double_clicked(self):
        music_list_index = self.currentRow()
        self.music_play(music_list_index)

    def music_play(self, music_list_index):
        self.playlist.setCurrentIndex(music_list_index)
        self.player.play()

    def add_network_music(self, music_name, music_url):
        print(music_name)
        self.addItem(music_name)
        self.playlist.addMedia(QMediaContent(QUrl(music_url)))
Beispiel #4
0
class SoundPlayer:
    def __init__(self, parent):
        self.parent = parent

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()

    def play(self, playlists, startRow=0, option=QMediaPlaylist.Sequential):
        if self.player.state() == QMediaPlayer.PausedState:
            self.player.play()
        else:
            self.createPlaylist(playlists, startRow, option)
            self.player.setPlaylist(self.playlist)
            self.playlist.setCurrentIndex(startRow)
            self.player.play()

    def pause(self):
        self.player.pause()

    def stop(self):
        self.player.stop()

    def createPlaylist(self,
                       playlists,
                       startRow=0,
                       option=QMediaPlaylist.Sequential):
        self.playlist.clear()

        for path in playlists:
            url = QUrl.fromLocalFile(path)
            self.playlist.addMedia(QMediaContent(url))

        self.playlist.setPlaybackMode(option)

    def upateVolume(self, vol):
        self.player.setVolume(vol)
class VideoPlayer(QWidget):
    def __init__(self, parent=None):
        # Super (whatever that means)
        super(VideoPlayer, self).__init__()
        # Initialize
        self.setGeometry(400, 100, 1280, 960)
        self.setWindowTitle('ProjecTosh by Trent Baker (c) 2019')

        # Set window background color
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), QColor(53, 64, 38))
        self.setPalette(p)

        # UI and widgets and such
        # Video widget
        self.video = QVideoWidget()
        #self.video.resize(300, 300)
        #self.video.move(0, 0)

        # Media Playlist
        self.playlist = QMediaPlaylist()
        self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile("video/video.avi"))) # https://www.nps.gov/grca/learn/photosmultimedia/b-roll_hd07.htm (default is public domain b-roll video)
        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
        self.playlist.setCurrentIndex(0)

        # Video player widget
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.setVideoOutput(self.video)
        #self.player.setMedia()
        self.player.play()

        # Label widgets
        fnt = QtGui.QFont('Impact', 20)
        h = announcements.announcements[1][0]
        b = announcements.announcements[1][1]
        # Announcements body
        self.lbAnnounce = QLabel()
        self.lbAnnounce.setText(h+'\n\n'+b)
        self.lbAnnounce.setFont(fnt)
        self.lbAnnounce.setAlignment(Qt.AlignTop)
        self.lbAnnounce.setWordWrap(True)
        self.lbAnnounce.setMaximumSize(600, 400)
        self.lbAnnounce.setStyleSheet("color: rgb(250, 241, 205);")
        # Current day
        self.lbDay = QLabel()
        self.lbDay.setText("it's day 1 lol")
        self.lbDay.setAlignment(Qt.AlignCenter)
        # Grad events
        self.lbGrad = QLabel()
        self.lbGrad.setText('upcoming grad event:\nsled')
        self.lbGrad.setAlignment(Qt.AlignCenter)

        # Timer for cycling announcement
        i = 1
        j = 1
        # Called when timer hits limit
        def handler():
            nonlocal h, b, i, j # Here i is the 'x' index of the 2D announcements.announcements array, and j is the 'y'
            j += 1
            # Print attempt begin
            print("Trying announcement at index "+str(i))
            # Cycle fake for loop
            if j >= len(announcements.announcements[i]):
                j = 1
                i += 1
            if i >= len(announcements.announcements):
                i = 1
            # Try until get announcement
            error = True
            while error:
                try:
                    h = announcements.announcements[i][0]
                    b = announcements.announcements[i][j] # At present this is only listing the first non-title item in the annoucement lists
                    ann = h + '\n\n' + b
                    print("Successfully updated announcement from index "+str(i))
                    error = False
                except:
                    print("Error when converting announcement at index "+str(i)+", skipping")
                    i += 1
            # Update announcement text
            self.lbAnnounce.setText(ann)
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(handler)
        self.timer.start(2000)

        # Do the layout move to do the layout move
        self.grid = QGridLayout()
        w = 4
        h = 3
        wl = 2
        wr = w-wl
        ht = 1
        hb = h-ht
        self.grid.addWidget(self.lbDay, 0, 0, ht, wl)
        self.grid.addWidget(self.lbGrad, ht, 0, hb, wl)
        self.grid.addWidget(self.video, 0, wl, ht, wr)
        self.grid.addWidget(self.lbAnnounce, ht, wl, hb, wr)

        self.setLayout(self.grid)
class DirectoryPlaylist(Playlist):

    def __init__(self, parent=None):
        super(DirectoryPlaylist, self).__init__(parent)

        self._directories_urls = set()
        self._added_song_urls = set()
        self._tracks = []

        self._qPlaylist = QMediaPlaylist(parent)
        self._qPlaylist.mediaAboutToBeInserted.connect(
            lambda s, e: self.mediaAboutToBeInserted.emit(s, e))
        self._qPlaylist.mediaInserted.connect(
            lambda s, e: self.mediaInserted.emit(s, e))
        self._qPlaylist.mediaAboutToBeRemoved.connect(
            lambda s, e: self.mediaAboutToBeRemoved.emit(s, e))
        self._qPlaylist.mediaRemoved.connect(
            lambda s, e: self.mediaRemoved.emit(s, e))
        self._qPlaylist.mediaChanged.connect(
            lambda s, e: self.mediaChanged.emit(s, e))

    def songs(self):
        return self._tracks

    def albums_data(self):
        return self._albumsData

    def artists_data(self):
        return self._artistsData

    def __traverse_directory(self, url, func):
        songs = []
        for root, dirs, files in os.walk(url):
                for file in files:
                    abs_path = os.path.join(root, file)
                    song = func(abs_path)
                    if song:
                        songs.append(song)
        return songs

    def is_empty(self):
        return not self._tracks

    def add_song(self, abs_path):
        if abs_path not in self._added_song_urls:
            url = QtCore.QUrl.fromLocalFile(abs_path)
            song = MediaFactory.create_media(abs_path)
            if not song:
                return None
            added = self._qPlaylist.addMedia(QMediaContent(url))
            if not added:
                return None

            self._tracks.append(song)
            self._added_song_urls.add(abs_path)
            return song

    def remove_song(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        if self._qPlaylist.currentIndex() == row:
            if row < self.song_count():
                self._qPlaylist.setCurrentIndex(row + 1)
            else:
                self._qPlaylist.setCurrentIndex(row - 1)

        removed = self._qPlaylist.removeMedia(row)
        if not removed:
            return

        del self._tracks[row]
        url = self.get_song_abs_path(row)
        self._added_song_urls.discard(url)

    def add_directory(self, directory):
        if directory not in self._directories_urls:
            self._directories_urls.add(directory)
            songs = self.__traverse_directory(directory, self.add_song)
            return songs
        return None

    def add_directories(self, directories):
        songs = []
        for directory in directories:
            if directory not in self._directories_urls:
                current_songs = self.add_directory(directory)
                if current_songs:
                    songs.extend(current_songs)
        return songs

    def remove_directory(self, directory):
        if directory not in self._directories_urls:
            return False  # raise Error

        self.__traverse_directory(directory, self.remove_song)

    def setCurrentIndex(self, index):
        self._qPlaylist.setCurrentIndex(index)

    def getCurrentIndex(self):
        return self._qPlaylist.currentIndex()

    def getCurrentSong(self):
        return self._qPlaylist.currentMedia()

    def clear(self):
        self._tracks = []
        self._directories_urls = set()
        self._added_song_urls = set()
        self._qPlaylist.clear()

    @property
    def internalPlaylist(self):
        return self._qPlaylist

    def song_count(self):
        return len(self._tracks)

    def get_song_metadata(self, row, tags):
        if row < 0 or row > self.song_count() - 1:
            return None
        if not isinstance(tags, list):
            tags = [tags]
        return self._tracks[row].get_values(tags)

    def get_song(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        return self._tracks[row]

    def get_song_title(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None
        k, v = self.get_song_metadata(row, 'title').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_album(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None
        k, v = self.get_song_metadata(row, 'album').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_artist(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        k, v = self.get_song_metadata(row, 'artist').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_genre(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        k, v = self.get_song_metadata(row, 'genre').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_abs_path(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        return self._tracks[row].get_abs_path()

    def getDirectories(self):
        return self._directories_urls

    def getAddedSongUrls(self):
        return self._added_song_urls

    def __str__(self):
        return str(self._tracks)

    def __eq__(self, other):
        return (isinstance(other, self.__class__) and
                self._directories_urls == other._directories_urls and
                self._added_song_urls == other._added_song_urls)
Beispiel #7
0
class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()

        self.time_label = QLabel(self)
        self.volume_slider = QSlider(self)
        self.progress_slider = QSlider(self)
        self.sound_btn = QPushButton(self)
        self.previous_btn = QPushButton(self)
        self.play_pause_btn = QPushButton(self)
        self.next_btn = QPushButton(self)
        self.mode_btn = QPushButton(self)
        self.list_btn = QPushButton(self)
        self.list_widget = QListWidget(self)

        self.h1_layout = QHBoxLayout()
        self.h2_layout = QHBoxLayout()
        self.all_v_layout = QVBoxLayout()

        self.playlist = QMediaPlaylist(self)        
        self.player = QMediaPlayer(self)

        self.widget_init()
        self.layout_init()
        self.signal_init()

    def widget_init(self):
        self.time_label.setText('--/--')
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(100)
        self.volume_slider.setOrientation(Qt.Horizontal)
        self.progress_slider.setEnabled(False)
        self.progress_slider.setOrientation(Qt.Horizontal)
        self.sound_btn.setIcon(QIcon('images/sound_on.png'))
        self.previous_btn.setIcon(QIcon('images/previous.png'))
        self.play_pause_btn.setIcon(QIcon('images/play.png'))
        self.next_btn.setIcon(QIcon('images/next.png'))
        self.mode_btn.setIcon(QIcon('images/list_loop.png'))
        self.list_btn.setIcon(QIcon('images/show.png'))

        self.player.setPlaylist(self.playlist)
        self.media_list = ['/Users/louis/Downloads/music1.mp3',
                           '/Users/louis/Downloads/music2.mp4',
                           '/Users/louis/Downloads/music3.mp3']
        for m in self.media_list:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(m)))
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

        self.list_widget.addItems([m.split('/')[-1] for m in self.media_list])

    def layout_init(self):
        self.h1_layout.addWidget(self.progress_slider)
        self.h1_layout.addWidget(self.time_label)
        self.h2_layout.addWidget(self.volume_slider)
        self.h2_layout.addWidget(self.sound_btn)
        self.h2_layout.addWidget(self.previous_btn)
        self.h2_layout.addWidget(self.play_pause_btn)
        self.h2_layout.addWidget(self.next_btn)
        self.h2_layout.addWidget(self.mode_btn)
        self.h2_layout.addWidget(self.list_btn)

        self.all_v_layout.addLayout(self.h1_layout)
        self.all_v_layout.addLayout(self.h2_layout)
        self.all_v_layout.addWidget(self.list_widget)
        self.all_v_layout.setSizeConstraint(QVBoxLayout.SetFixedSize)

        self.setLayout(self.all_v_layout)

    def signal_init(self):
        self.sound_btn.clicked.connect(lambda: self.btn_func(self.sound_btn))
        self.previous_btn.clicked.connect(lambda: self.btn_func(self.previous_btn))
        self.play_pause_btn.clicked.connect(lambda: self.btn_func(self.play_pause_btn))
        self.next_btn.clicked.connect(lambda: self.btn_func(self.next_btn))
        self.mode_btn.clicked.connect(lambda: self.btn_func(self.mode_btn))
        self.list_btn.clicked.connect(lambda: self.btn_func(self.list_btn))
        self.volume_slider.valueChanged.connect(self.volume_slider_func)
        self.list_widget.doubleClicked.connect(self.list_play_func)
        self.player.durationChanged.connect(self.get_duration_func)
        self.player.positionChanged.connect(self.get_position_func)
        self.progress_slider.sliderMoved.connect(self.update_position_func)

    def btn_func(self, btn):
        if btn == self.sound_btn:              
            if self.player.isMuted():
                self.player.setMuted(False)
                self.sound_btn.setIcon(QIcon('images/sound_on'))
            else:
                self.player.setMuted(True)
                self.sound_btn.setIcon(QIcon('images/sound_off'))

        elif btn == self.previous_btn:          
            if self.playlist.currentIndex() == 0:
                self.playlist.setCurrentIndex(self.playlist.mediaCount() - 1)
            else:
                self.playlist.previous()

        elif btn == self.play_pause_btn:      
            if self.player.state() == 1:
                self.player.pause()
                self.play_pause_btn.setIcon(QIcon('images/play.png'))
            else:
                self.player.play()
                self.play_pause_btn.setIcon(QIcon('images/pause.png'))

        elif btn == self.next_btn:              
            if self.playlist.currentIndex() == self.playlist.mediaCount() - 1:
                self.playlist.setCurrentIndex(0)
            else:
                self.playlist.next()

        elif btn == self.mode_btn:             
            if self.playlist.playbackMode() == 2:
                self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
                self.mode_btn.setIcon(QIcon('images/item_loop.png'))

            elif self.playlist.playbackMode() == 3:
                self.playlist.setPlaybackMode(QMediaPlaylist.Random)
                self.mode_btn.setIcon(QIcon('images/random.png'))

            elif self.playlist.playbackMode() == 4:
                self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
                self.mode_btn.setIcon(QIcon('images/list_loop.png'))

        elif btn == self.list_btn:             
            if self.list_widget.isHidden():
                self.list_widget.show()
                self.list_btn.setIcon(QIcon('images/show.png'))
            else:
                self.list_widget.hide()
                self.list_btn.setIcon(QIcon('images/hide.png'))

    def volume_slider_func(self, value):
        self.player.setVolume(value)
        if value == 0:
            self.sound_btn.setIcon(QIcon('images/sound_off.png'))
        else:
            self.sound_btn.setIcon(QIcon('images/sound_on.png'))

    def list_play_func(self):
        self.playlist.setCurrentIndex(self.list_widget.currentRow())
        self.player.play()
        self.play_pause_btn.setIcon(QIcon('images/pause.png'))

    def get_duration_func(self, d):
        self.progress_slider.setRange(0, d)
        self.progress_slider.setEnabled(True)
        self.get_time_func(d)

    def get_time_func(self, d):
        seconds = int(d / 1000)
        minutes = int(seconds / 60)
        seconds -= minutes * 60
        if minutes == 0 and seconds == 0:
            self.time_label.setText('--/--')
            self.play_pause_btn.setIcon(QIcon('images/play.png'))
        else:
            self.time_label.setText('{}:{}'.format(minutes, seconds))

    def get_position_func(self, p):
        self.progress_slider.setValue(p)

    def update_position_func(self, v):
        self.player.setPosition(v)
        d = self.progress_slider.maximum() - v
        self.get_time_func(d)
Beispiel #8
0
class play(QMainWindow, Ui_Form):
    def __init__(self):
        super(play, self).__init__()
        self.setupUi(self)
        self.setWindowTitle("VIP音乐播放器")
        self.m_filepath = 'E:/MusicMedia/MusicMedia/music/'
        # self.m_filepath = 'E:/ProgramData/PyUI/music'
        self.player = QMediaPlayer()
        self.PlayList = QMediaPlaylist()
        self.player.setPlaylist(self.PlayList)
        self.count = 0  #做一个计数器

    def search(self):
        self.listWidget_2.clear()
        music = self.lineEdit.text()  #地心
        author = self.lineEdit_2.text()  #汪峰
        self.music = search_song(music, author)
        self.music.song.connect(self.get_music)
        # 启动线程
        self.music.start()

    def get_music(self, data):
        if data != None:
            music = self.lineEdit.text()  # 地心
            self.listWidget_2.addItem("{} - {}".format(data[0], data[1]))
            #启动下载歌曲的线程
            self.dowm = download_song(music, data[1], data[2])
            # self.music.song.connect(self.music_dowm)   #没有信号的发送这里也可以不用定义槽函数
            self.dowm.start()
        else:
            music = self.lineEdit.text()  # 地心
            author = self.lineEdit_2.text()  # 汪峰
            # 启动下载歌曲的线程
            self.Intel = download_song2(music, author)
            self.Intel.song.connect(self.Intelnet_song)
            self.Intel.start()

    def Intelnet_song(self, data):
        self.listWidget_2.addItem("{} - {}".format(data['title'],
                                                   data['author']))
        # 启动下载歌曲的线程
        self.dowm = download_song(data['title'], data['author'], data['url'])
        self.dowm.start()

    def load_Local(self):
        if self.count == 0:
            self.PlayList.clear()  # 便于网络歌曲加入
            self.listWidget.clear()  # 刷新播放列表
            list = os.listdir(self.m_filepath)
            for cur_music in list:
                self.listWidget.addItem(cur_music[:-4])
                self.PlayList.addMedia(
                    QMediaContent(
                        QUrl.fromLocalFile(self.m_filepath + cur_music)))
            self.count += 1
        else:
            cur_music = self.listWidget_2.currentItem().text()
            row = self.listWidget.currentRow()
            self.listWidget.insertItem(row, cur_music)
            self.listWidget_2.clear()  # 清空在线的列表,造成一种从左边移动到右边的视觉
            self.PlayList.addMedia(
                QMediaContent(
                    QUrl.fromLocalFile(self.m_filepath + cur_music + '.mp3')))

    def custom_current_music(self):
        cur_music = self.listWidget.currentItem().text()  #获取当前播放的歌曲的名字
        item = self.listWidget.currentRow()
        self.PlayList.setCurrentIndex(item)
        self.player.play()  # 开始播放当前指定的歌曲

    def delete_song(self):
        cur_music = self.listWidget.currentItem().text()
        os.remove(self.m_filepath + cur_music + '.mp3')  #从磁盘上删除
        row = self.listWidget.currentRow()  #获取当前鼠标所选行
        self.listWidget.takeItem(row)  #从列表上删除该行
        self.PlayList.next()  #歌曲列表顺势往下
        self.player.play()  #播放

    # 重写窗口paintEvent函数
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(self.rect(), QPixmap("image/back.jpg"))
Beispiel #9
0
class MyWidget(QMainWindow):
    def __init__(self):
        super().__init__()
        #  !Костыль
        #  Запрещаю менять размер окна, т.к. не хочу работать с layout`ами
        self.setFixedSize(656, 532)
        self.setWindowIcon(QIcon('icons/icon.ico'))

        #  Добавляем эквалайзер громкости
        self.equalizer = QVolumeEq((255, 255, 102), (255, 26, 10), bg_color=(0, 0, 0, 20))
        self.equalizer.setParent(self)
        self.equalizer.move(20, 391)
        self.equalizer.resize(341, 31)

        uic.loadUi('icons/djap.ui', self)

        self.lightThemeAction.triggered.connect(self.change_theme)
        self.darkThemeAction.triggered.connect(self.change_theme)

        #  Создаём организатор плейлистов
        self.playlist_handler = QPlaylistHandler()
        self.playlist_handler.setParent(self)
        self.playlist_handler.move(380, 40)

        #  Настраиваем меню
        self.saveOption.triggered.connect(self.playlist_handler.save_playlist)
        self.saveAsOption.triggered.connect(self.playlist_handler.save_playlist_as)
        self.deleteOption.triggered.connect(self.playlist_handler.delete_playlist)
        self.aboutOption.triggered.connect(self.about)
        self.helpOption.triggered.connect(self.help)
        self.repeatModeOption.triggered.connect(self.playlist_handler.change_playmode)
        self.oneModeOption.triggered.connect(self.playlist_handler.change_playmode)
        self.randomModeOption.triggered.connect(self.playlist_handler.change_playmode)

        #  Реализация проигрывателя и основного плейлиста
        self.player = QMediaPlayer()
        self.player.durationChanged.connect(self.update_song)
        self.player.setVolume(25)
        self.player.positionChanged.connect(self.update_timeline_position)
        self.queue = QMediaPlaylist(self.player)
        self.player.setPlaylist(self.queue)

        self.queue.setPlaybackMode(QMediaPlaylist.Loop)
        self.is_looped_queue = True

        #  Загрузка музыки из плейлиста
        self.load_songs_from_playlist()

        #  Подключаем кнопки к их функциям
        self.is_playing = False
        self.playBtn.clicked.connect(self.play_or_pause)
        self.queue.currentMediaChanged.connect(self.check_to_stop)

        self.nextBtn.clicked.connect(self.next_audio)
        self.prevBtn.clicked.connect(self.prev_audio)

        self.is_looped_current_track = False
        self.loopBtn.clicked.connect(self.loop_or_unloop_current_track)

        #  Настройка слайдера звука
        self.volumeSlider.hide()
        self.volumeSlider.setValue(25)
        self.equalizer.setValue(25)
        self.volumeSlider.sliderReleased.connect(self.volumeSlider.hide)
        self.volumeSlider.valueChanged.connect(self.change_volume)
        self.volumeBtn.clicked.connect(self.change_volume)

        #  Настройка таймлайна
        self.is_timeline_dragged = False
        self.timeline.sliderReleased.connect(self.timeline_changed)
        self.timeline.sliderPressed.connect(self.timeline_is_dragged)

        #  !Костыль
        #  Имитируем запуск аудиодорожки, чтобы подгрузить данные
        self.play_or_pause()
        self.play_or_pause()
        self.icon_changed()

    def palette(self):
        """Функция для создания темы"""
        con = sqlite3.connect('user_data.sqlite')
        cur = con.cursor()
        if int(cur.execute('SELECT * FROM theme').fetchone()[0]):
            palette = QPalette()
            palette.setColor(QPalette.Window, QColor(240, 240, 240))
            palette.setColor(QPalette.WindowText, Qt.black)
            palette.setColor(QPalette.Base, Qt.white)
            palette.setColor(QPalette.AlternateBase, QColor(246, 246, 246))
            palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 240))
            palette.setColor(QPalette.ToolTipText, Qt.black)
            palette.setColor(QPalette.Text, Qt.black)
            palette.setColor(QPalette.Button, QColor(240, 240, 240))
            palette.setColor(QPalette.ButtonText, Qt.black)
            palette.setColor(QPalette.BrightText, Qt.white)
            palette.setColor(QPalette.Highlight, QColor(0, 120, 215).lighter())
            palette.setColor(QPalette.HighlightedText, Qt.white)
        else:
            palette = QPalette()
            palette.setColor(QPalette.Window, QColor(53, 53, 53))
            palette.setColor(QPalette.WindowText, Qt.white)
            palette.setColor(QPalette.Base, QColor(15, 15, 15))
            palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
            palette.setColor(QPalette.ToolTipBase, Qt.white)
            palette.setColor(QPalette.ToolTipText, Qt.white)
            palette.setColor(QPalette.Text, Qt.white)
            palette.setColor(QPalette.Button, QColor(53, 53, 53))
            palette.setColor(QPalette.ButtonText, Qt.white)
            palette.setColor(QPalette.BrightText, Qt.red)
            palette.setColor(QPalette.Highlight, QColor(142, 45, 197).lighter())
            palette.setColor(QPalette.HighlightedText, Qt.black)
        return palette

    def change_theme(self):
        """Функция для смены темы"""
        con = sqlite3.connect('user_data.sqlite')
        cur = con.cursor()
        if self.sender() == self.lightThemeAction:
            cur.execute('UPDATE theme SET isit = 1')
        else:
            cur.execute('UPDATE theme SET isit = 0')
        con.commit()

        QMessageBox.warning(self, 'DJust Audio Player', 'Чтобы изменения вступили в силу, '
                                                        'перезапустите приложение.', QMessageBox.Ok)

    def help(self):
        """Функция для показа формы справки"""
        self.help = QHelp()

    def about(self):
        """Функция для показа формы О программе"""
        self.about = QAbout()

    def delete_song_from_mediaplayer(self, index):
        """Удалить трек из медиаплеера"""
        self.queue.removeMedia(index)

    def add_song_to_mediaplayer(self, url):
        """Добавить трек в медиаплеер"""
        self.queue.addMedia(QMediaContent(QUrl(url)))

    def change_track_by_click(self, row):
        """Функция для смены трека по нажатию в списке"""
        self.queue.setCurrentIndex(row)

    def check_to_stop(self):
        """Проверяем, чтобы плеер не играл с пустым плейлистом"""
        if self.queue.isEmpty() and self.is_playing:
            self.play_or_pause()

    def load_songs_from_playlist(self):
        """Загрузка музыки из БД в плейлист"""
        self.queue.clear()
        for url in self.playlist_handler.urls():
            self.queue.addMedia(QMediaContent(QUrl(url)))

    def icon_changed(self):
        """Функция для вывода обложки трека"""

        def noicon():
            """В случае отсутствия обложки эта функция ставить свою заглушку"""
            try:
                pixmap = QPixmap()
                if pixmap.load('icons/noicon.png'):
                    self.audioPic.setPixmap(pixmap)
            except Exception as e:
                print(e.__class__.__name__, ': ', e, sep='')

        try:
            #  Читаем метаданные трека
            n = self.queue.currentIndex()
            url = self.playlist_handler.urls()[n if n > -1 else 0]
            file = File(url)
            for i in file.tags.keys():
                if 'APIC:' in i:
                    artwork = file.tags[i].data
                    break
            else:
                raise KeyError
            #  Переводим их в байтовый массив
            ba = QByteArray(artwork)
            #  И загружаем на форму, если это возможно
            pixmap = QPixmap()
            if pixmap.loadFromData(ba):
                self.audioPic.setPixmap(pixmap.scaled(341, 341, Qt.IgnoreAspectRatio))
            else:
                raise KeyError
        except Exception as e:
            #  print(e.__class__.__name__, ': ', e, sep='')
            noicon()

    def timeline_is_dragged(self):
        """Мини-функция для изменения переменной"""
        #  При вызове этой функции мы понимаем, что пользователь
        #  взаимодействует с таймлайном трека
        self.is_timeline_dragged = True

    def timeline_changed(self):
        """Функция для пользовательской перемотки данного трека"""
        #  Перематываем позицию плеера
        self.player.setPosition(self.timeline.value() * 1000)

        #  Пользователь отпустил язычок слайдера и больше не взаимодействует с таймлайном
        self.is_timeline_dragged = False

        #  Вызываем обновление временной шкалы, т.к. произошла перемотка
        self.update_timeline_position()

    def update_song(self):
        """Изменение данных о треке"""
        #  !Костыль
        #  Проматываем несколько миллисекунд, чтобы избежать повреждённых треков
        self.player.setPosition(10)

        #  Меняем обложку
        self.icon_changed()

        #  Выделяем в списке новый трек
        self.playlist_handler.set_current_select(self.queue.currentIndex())

        #  Меняем название окна в соответствии с играющим треком
        title = self.queue.currentMedia().canonicalUrl().path().split('/')[-1]
        if title:
            self.setWindowTitle('DJust Audio Player | %s' % title)
        else:
            self.setWindowTitle('DJust Audio Player')

        #  Изменяем длину таймлайна на длину трека
        self.timeline.setMaximum(self.player.duration() // 1000)

        #  Выводим длину трека в минутах/секундах на экран
        minutes, seconds = self.player.duration() // 1000 // 60, self.player.duration() // 1000 % 60
        self.endTimeLabel.setText(str(minutes) + ':{:02d}'.format(seconds))

    def update_timeline_position(self):
        """Функция для обновления временной шкалы"""
        #  Выводим текущее положение плеера в минутах/секундах
        minutes, seconds = self.player.position() // 1000 // 60, self.player.position() // 1000 % 60
        self.currentTimeLabel.setText(str(minutes) + ':{:02d}'.format(seconds))

        #  Чтобы не "вырывать" язычок слайдера из рук пользователя,
        #  проверяем, что пользователь НЕ взаимодейтсвует с таймлайном.
        if not self.is_timeline_dragged:
            self.timeline.setValue(minutes * 60 + seconds)

    def loop_or_unloop_current_track(self):
        """Мини-функция для зацикливания данного трека"""
        if not self.is_looped_current_track:
            #  Зацикливаем
            self.is_looped_current_track = True
            self.queue.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            #  Меняем картинку на перечёркнутый круг
            self.loopBtn.setStyleSheet('background-image: url(icons/unloop.png)')
        else:
            #  убираем цикл
            self.is_looped_current_track = False
            self.queue.setPlaybackMode(self.playlist_handler.mode)
            self.loopBtn.setStyleSheet('background-image: url(icons/loop.png)')

    def next_audio(self):
        """Функция для перемотки на следующий в списке трек"""
        if self.queue.mediaCount() - 1 == self.queue.currentIndex():
            #  Если трек ппоследний в списке, возвращаемся к первому
            self.queue.setCurrentIndex(0)
        else:
            #  Иначе просто перемещаемся к следующему
            self.queue.next()

    def prev_audio(self):
        """Функция для перемотки на предыдущий в списке трек"""
        if 0 == self.queue.currentIndex():
            #  Если трек первый в списке, возвращаемся к последнему
            self.queue.setCurrentIndex(self.queue.mediaCount() - 1)
        else:
            #  Иначе просто возвращаемся к предыдущему
            self.queue.previous()

    def play_or_pause(self):
        """Функция для запуска или остановки проигрывателя"""
        if self.queue.isEmpty():
            #  Меняем картинку на стрелочку (проигрывание)
            self.is_playing = False
            self.playBtn.setStyleSheet('background-image: url(icons/play.png)')
            #  Ставим на паузу
            self.player.pause()
            return
        if self.is_playing:
            #  Меняем картинку на стрелочку (проигрывание)
            self.is_playing = False
            self.playBtn.setStyleSheet('background-image: url(icons/play.png)')
            #  Ставим на паузу
            self.player.pause()
        else:
            #  Меняем картинку на 2 палочки (пауза)
            self.is_playing = True
            self.playBtn.setStyleSheet('background-image: url(icons/pause.png)')
            #  Запускаем звук
            self.player.play()

    def change_volume(self):
        """Мини-Функция для передачи уровня громкости в плеер"""
        #  Функцию использует несколько объектов сразу, проверяем вызывателя
        if self.sender() == self.volumeBtn:
            #  Если функцию вызвала кнопка, то включаем/выключаем отображение слайдера
            if not self.volumeSlider.isHidden():
                self.volumeSlider.hide()
            else:
                self.volumeSlider.show()
        else:
            #  Иначе функцию вызвал сам слайдер. Значит, меняем значение
            self.player.setVolume(self.volumeSlider.value())
            self.equalizer.setValue(self.volumeSlider.value())
Beispiel #10
0
class Player(QWidget):
 
    fullScreenChanged = pyqtSignal(bool)
 
    def __init__(self, playlist, parent=None):
        super(Player, self).__init__(parent)
 
        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0
 
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)
 
        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)
 
        self.videoWidget = VideoWidget()
        self.player.setVideoOutput(self.videoWidget)
 
        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)
 
        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(self.playlist.currentIndex(), 0))
 
        self.playlistView.activated.connect(self.jump)

        self.script_box = QPlainTextEdit()
        self.segmentList = QTreeWidget()
        self.segmentList.setSortingEnabled(True)
        #self.segmentList.setColumnCount(5)
        self.segmentList.setColumnCount(4)
        #self.segmentList.setHeaderLabels(['Product','Start','Label','Tool','Behavior'])
        self.segmentList.setHeaderLabels(['Start segment', 'End segment', 'Label', 'Event'])

        '''
        self.productTextInput = QLineEdit()
        self.startTextInput = QLineEdit()
        self.labelTextInput = QLineEdit()
        self.toolTextInput = QLineEdit()
        self.behaviorTextInput = QLineEdit()
        '''
        self.startTextInput = QLineEdit()
        self.endTextInput = QLineEdit()
        self.labelTextInput = QLineEdit()
        self.contentTextInput = QLineEdit()

        self.addBtn = QPushButton("Add")
        self.addBtn.clicked.connect(self.addSegment)

        self.saveBtn = QPushButton("Save")
        self.saveBtn.clicked.connect(self.saveSegments)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)
 
        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)
 
        self.labelHistogram = QLabel()
        self.labelHistogram.setText("Histogram:")
        self.histogram = HistogramWidget()
        histogramLayout = QHBoxLayout()
        histogramLayout.addWidget(self.labelHistogram)
        histogramLayout.addWidget(self.histogram, 1)
 
        self.probe = QVideoProbe()
        self.probe.videoFrameProbed.connect(self.histogram.processFrame)
        self.probe.setSource(self.player)
 
        openButton = QPushButton("Open", clicked=self.open)
        if os.path.isdir(VIDEO_DIR):
            self.open_folder(VIDEO_DIR)

        controls = PlayerControls()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())
 
        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        controls.changeRate.connect(self.player.setPlaybackRate)
        controls.stop.connect(self.videoWidget.update)
 
        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)

        #self.segmentButton = QPushButton("Segment")
        #self.segmentButton.clicked.connect(self.createNewSegment)
        self.startSegmentButton = QPushButton("Start Segment")
        self.startSegmentButton.clicked.connect(self.createNewStartSegment)
        # self.segmentButton.setCheckable(True)

        self.endSegmentButton = QPushButton("End Segment")
        self.endSegmentButton.clicked.connect(self.createNewEndSegment)

        #self.fullScreenButton = QPushButton("FullScreen")
        #self.fullScreenButton.setCheckable(True)
 
        self.colorButton = QPushButton("Color Options...")
        self.colorButton.setEnabled(False)
        self.colorButton.clicked.connect(self.showColorDialog)
 
        displayLayout = QHBoxLayout()
        # videoLayout = QVBoxLayout()
        # videoLayout.addWidget(self.videoWidget)
        # videoLayout.addWidget(self.script_box)
        
        displayLayout.addWidget(self.videoWidget, 3)

        editLayout = QVBoxLayout()
        editLayout.addWidget(self.playlistView, 2)
        #editLayout.addWidget(self.script_box, 4)
        editLayout.addWidget(self.segmentList, 3)
        segmentInputLayout = QHBoxLayout()
        '''
        segmentInputLayout.addWidget(self.productTextInput)
        segmentInputLayout.addWidget(self.startTextInput)
        segmentInputLayout.addWidget(self.labelTextInput)
        segmentInputLayout.addWidget(self.toolTextInput)
        segmentInputLayout.addWidget(self.behaviorTextInput)
        '''
        segmentInputLayout.addWidget(self.startTextInput)
        segmentInputLayout.addWidget(self.endTextInput)
        segmentInputLayout.addWidget(self.labelTextInput)
        segmentInputLayout.addWidget(self.contentTextInput)

        editLayout.addLayout(segmentInputLayout,1)

        displayLayout.addLayout(editLayout, 2)
 
        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addStretch(1)
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        #controlLayout.addWidget(self.segmentButton)
        controlLayout.addWidget(self.startSegmentButton)
        controlLayout.addWidget(self.endSegmentButton)
        controlLayout.addWidget(self.addBtn)
        controlLayout.addWidget(self.saveBtn)
        #controlLayout.addWidget(self.fullScreenButton)
        # controlLayout.addWidget(self.colorButton)
 
        layout = QVBoxLayout()
        layout.addLayout(displayLayout, 2)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)
        # layout.addLayout(histogramLayout)
 
        self.setLayout(layout)
 
        if not self.player.isAvailable():
            QMessageBox.warning(self, "Service not available",
                    "The QMediaPlayer object does not have a valid service.\n"
                    "Please check the media service plugins are installed.")
 
            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            openButton.setEnabled(False)
            self.colorButton.setEnabled(False)
            #self.fullScreenButton.setEnabled(False)
 
        self.metaDataChanged()
 
        self.addToPlaylist(playlist)
    
    def open(self):
        fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
        self.addToPlaylist(fileNames)

    def open_folder(self, folder_path):
        fileNames = [folder_path+x for x in os.listdir(folder_path) if x.endswith('.mp4')]
        self.addToPlaylist(fileNames)
 
    def addToPlaylist(self, fileNames):
        for name in fileNames:
            fileInfo = QFileInfo(name)
            if fileInfo.exists():
                url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(QMediaContent(url))
            else:
                url = QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(QMediaContent(url))

    def addSegment(self):
        item = TreeWidgetItem(self.segmentList)
        '''
        item.setText(0, self.productTextInput.text())
        item.setText(1, self.startTextInput.text())
        item.setText(2, self.labelTextInput.text())
        item.setText(3, self.toolTextInput.text())
        item.setText(4, self.behaviorTextInput.text())
        '''

        item.setText(0, self.startTextInput.text())
        item.setText(1, self.endTextInput.text())
        item.setText(2, self.labelTextInput.text())
        item.setText(3, self.contentTextInput.text())

        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.segmentList.addTopLevelItem(item)
        self.segmentList.sortByColumn(0, Qt.AscendingOrder)

        self.clear_input_boxes()
        self.player.play()
    
    def saveSegments(self):
        itemCnt = self.segmentList.topLevelItemCount()
        colCnt = self.segmentList.columnCount()
        save_dict = {'segments':[]}

        for i in range(itemCnt):
            item = self.segmentList.topLevelItem(i)
            temp_data = []
            for j in range(colCnt):
                temp_data.append(item.text(j))
            #temp_dict = {'product': temp_data[0], 'start': temp_data[1], 'label': temp_data[2], 'tool': temp_data[3], 'behavior': temp_data[4]}

            if len(temp_data[0]) > 0 and len(temp_data[1]) > 0 and (':' in temp_data[0]) and (':' in temp_data[1]):

                start_interval_seconds = 0
                j = 0
                while j < len(temp_data[0].split(':')):
                    start_interval_seconds += (int(temp_data[0].split(':')[- 1 - j]) * (60 ** j))
                    j += 1

                end_interval_seconds = 0
                j = 0
                while j < len(temp_data[1].split(':')):
                    end_interval_seconds += (int(temp_data[1].split(':')[- 1 - j]) * (60 ** j))
                    j += 1

            else:
                start_interval_seconds = ''
                end_interval_seconds = ''

            temp_dict = {'start_segment': start_interval_seconds, 'end_segment': end_interval_seconds, 'label': temp_data[2], 'event': temp_data[3]}
            save_dict['segments'].append(temp_dict)
        
        import json
        file_name = self.playlist.currentMedia().canonicalUrl().fileName()
        with open(SEGMENT_DIR+file_name.replace('.mp4','.json'),'w') as file:
            json.dump(save_dict, file)

    def durationChanged(self, duration):
        duration /= 1000
 
        self.duration = duration
        self.slider.setMaximum(duration)
 
    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)
 
        self.updateDurationInfo(progress)
 
    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo("%s - %s" % (
                    self.player.metaData(QMediaMetaData.AlbumArtist),
                    self.player.metaData(QMediaMetaData.Title)))
 
    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)
    
    def clear_input_boxes(self):
        '''
        self.productTextInput.clear()
        self.startTextInput.clear()
        self.labelTextInput.clear()
        self.toolTextInput.clear()
        self.behaviorTextInput.clear()
        '''
        self.startTextInput.clear()
        self.endTextInput.clear()
        self.labelTextInput.clear()
        self.contentTextInput.clear()


    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()
            file_name = self.playlist.currentMedia().canonicalUrl().fileName()
            '''
            script_file_name = file_name.replace('.mp4','.txt')
            if os.path.isfile(SCRIPT_DIR+script_file_name):
                text=open(SCRIPT_DIR+script_file_name).read()
                self.script_box.setPlainText(text)
            '''

            segment_file_path = SEGMENT_DIR + file_name.replace('.mp4','.json')
            json_dict = self.open_json(segment_file_path)
            self.clear_input_boxes()
            self.segmentList.clear()
            for segment in json_dict["segments"]:
                item = TreeWidgetItem(self.segmentList)
                '''
                item.setText(0, segment['product'])
                item.setText(1, str(segment['start']))
                item.setText(2, segment['label'])
                item.setText(3, segment['tool'])
                item.setText(4, segment['behavior'])
                '''
                item.setText(0, segment['start_segment'])
                item.setText(1, segment['end_segment'])
                item.setText(2, segment['label'])
                item.setText(3, segment['content'])

                item.setFlags(item.flags() | Qt.ItemIsEditable)
                self.segmentList.addTopLevelItem(item)
                
            
            
            # print([str(x.text()) for x in self.segmentList.currentItem()])

    def open_json(self, file_path):
        import json
        try:
            with open(file_path, 'r') as file:
                json_dict = json.loads(file.read())
        except:
            json_dict = {"segments":[]}
            # json_dict = {"segments":[{"product":"Sorry","start":"File not found.","label":"","tool":"","behavior":""}]}
        return json_dict
    
    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(position, 0))
 
    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)
 
    def statusChanged(self, status):
        self.handleCursor(status)
 
        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")
 
    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()
 
    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)
 
    def videoAvailableChanged(self, available):
        '''
        if available:
            self.fullScreenButton.clicked.connect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.connect(
                    self.fullScreenButton.setChecked)
 
            if self.fullScreenButton.isChecked():
                self.videoWidget.setFullScreen(True)
        else:
            self.fullScreenButton.clicked.disconnect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.disconnect(
                    self.fullScreenButton.setChecked)
 
            self.videoWidget.setFullScreen(False)

        '''
        self.colorButton.setEnabled(available)
 
    def setTrackInfo(self, info):
        self.trackInfo = info
 
        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)
 
    def setStatusInfo(self, info):
        self.statusInfo = info
 
        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)
 
    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())
 
    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60,
                    currentInfo%60, (currentInfo*1000)%1000)
            totalTime = QTime((duration/3600)%60, (duration/60)%60,
                    duration%60, (duration*1000)%1000);
 
            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(format)
        else:
            tStr = ""
 
        self.labelDuration.setText(tStr)
    '''
    def createNewSegment(self):
        self.startTextInput.setText(str(int(self.player.position()/1000)))
    '''

    def createNewStartSegment(self):
        seconds = int(self.player.position()/1000)
        self.startTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format(
            math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60))

    def createNewEndSegment(self):
        seconds = int(self.player.position() / 1000)
        self.endTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format(
            math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60))
        self.player.pause()

    def showColorDialog(self):
        if self.colorDialog is None:
            brightnessSlider = QSlider(Qt.Horizontal)
            brightnessSlider.setRange(-100, 100)
            brightnessSlider.setValue(self.videoWidget.brightness())
            brightnessSlider.sliderMoved.connect(
                    self.videoWidget.setBrightness)
            self.videoWidget.brightnessChanged.connect(
                    brightnessSlider.setValue)
 
            contrastSlider = QSlider(Qt.Horizontal)
            contrastSlider.setRange(-100, 100)
            contrastSlider.setValue(self.videoWidget.contrast())
            contrastSlider.sliderMoved.connect(self.videoWidget.setContrast)
            self.videoWidget.contrastChanged.connect(contrastSlider.setValue)
 
            hueSlider = QSlider(Qt.Horizontal)
            hueSlider.setRange(-100, 100)
            hueSlider.setValue(self.videoWidget.hue())
            hueSlider.sliderMoved.connect(self.videoWidget.setHue)
            self.videoWidget.hueChanged.connect(hueSlider.setValue)
 
            saturationSlider = QSlider(Qt.Horizontal)
            saturationSlider.setRange(-100, 100)
            saturationSlider.setValue(self.videoWidget.saturation())
            saturationSlider.sliderMoved.connect(
                    self.videoWidget.setSaturation)
            self.videoWidget.saturationChanged.connect(
                    saturationSlider.setValue)
 
            layout = QFormLayout()
            layout.addRow("Brightness", brightnessSlider)
            layout.addRow("Contrast", contrastSlider)
            layout.addRow("Hue", hueSlider)
            layout.addRow("Saturation", saturationSlider)
 
            button = QPushButton("Close")
            layout.addRow(button)
 
            self.colorDialog = QDialog(self)
            self.colorDialog.setWindowTitle("Color Options")
            self.colorDialog.setLayout(layout)
 
            button.clicked.connect(self.colorDialog.close)
 
        self.colorDialog.show()
Beispiel #11
0
class MainWindow(QWidget):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.playlistView = QListView()
        self.switch_status = 2
        self.video_widget = QVideoWidget()
        self.playlist = QMediaPlaylist()
        self.model = PlaylistModel(self.playlist)
        self.titleBar = TitleBar(self)
        self.currentTimeLabel = QLabel()
        self.timeSlider = QSlider()
        self.totalTimeLabel = QLabel()
        self.mediaPlayer = QMediaPlayer()
        self.open_btn = QPushButton('Open File')
        self.play_btn = QPushButton()
        self.prev_btn = QPushButton()
        self.stop_btn = QPushButton()
        self.next_btn = QPushButton()
        self.switch_media_widgets_btn = QPushButton()
        self.pseudo_label = QLabel()

        self.vol_label = QLabel()
        self.volume_slider = Slider(Qt.Horizontal)
        self.gui()
        self.set_children_focus_policy(Qt.NoFocus)

    def gui(self):
        self.currentTimeLabel.setMinimumSize(QSize(80, 0))
        self.currentTimeLabel.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter)

        self.timeSlider.setOrientation(Qt.Horizontal)
        self.totalTimeLabel.setMinimumSize(QSize(80, 0))
        self.totalTimeLabel.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignVCenter)

        self.playlistView.setAcceptDrops(True)
        self.playlistView.setProperty("showDropIndicator", True)
        self.playlistView.setDragDropMode(QAbstractItemView.DropOnly)
        self.playlistView.setAlternatingRowColors(True)
        self.playlistView.setUniformItemSizes(True)

        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setWindowTitle('Media Player')
        self.titleBar.label.setText('Media Player')
        self.setWindowIcon(QIcon('icon_png/media_player.png'))

        self.setGeometry(600, 200, 850, 600)
        self.timeSlider.setRange(0, 0)
        self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.prev_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward))
        self.next_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward))
        self.stop_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.switch_media_widgets_btn.setIcon(self.style().standardIcon(QStyle.SP_FileDialogDetailedView))
        self.vol_label.setText("")
        self.vol_label.setPixmap(QPixmap("icon_png/speaker-volume.png"))
        self.currentTimeLabel.setText("00:00")
        self.totalTimeLabel.setText("00:00")
        self.volume_slider.setValue(self.mediaPlayer.volume())
        self.mediaPlayer.setVideoOutput(self.video_widget)
        self.mediaPlayer.setPlaylist(self.playlist)
        self.playlistView.setModel(self.model)
        self.video_widget.hide()

        sizegrip = QSizeGrip(self)

        self.setAcceptDrops(True)

        inner_h_box = QHBoxLayout()
        inner_h_box.addWidget(self.prev_btn)
        inner_h_box.addWidget(self.stop_btn)
        inner_h_box.addWidget(self.next_btn)

        vol_h_box = QHBoxLayout()
        vol_h_box.addWidget(self.vol_label, 0)
        vol_h_box.addWidget(self.volume_slider, 1)

        h_box = QHBoxLayout()
        h_box.addWidget(self.open_btn)
        h_box.addWidget(self.play_btn, 0)
        h_box.addLayout(inner_h_box, 0)
        h_box.addWidget(self.switch_media_widgets_btn, 0)
        h_box.addWidget(self.pseudo_label, 1)
        h_box.addLayout(vol_h_box, 0)
        h_box.addWidget(sizegrip, 0, Qt.AlignBottom | Qt.AlignRight)

        video_slider_h_box = QHBoxLayout()
        video_slider_h_box.addWidget(self.currentTimeLabel)
        video_slider_h_box.addWidget(self.timeSlider)
        video_slider_h_box.addWidget(self.totalTimeLabel)

        v_box = QVBoxLayout()
        v_box.addWidget(self.titleBar, 0)
        v_box.addWidget(self.video_widget, 1)
        v_box.addWidget(self.playlistView, 1)
        v_box.addLayout(video_slider_h_box, 0)
        v_box.addLayout(h_box, 0)

        inner_h_box.setContentsMargins(20, 0, 10, 0)
        vol_h_box.setContentsMargins(0, 0, 20, 0)
        h_box.setContentsMargins(20, 0, 0, 0)
        v_box.setContentsMargins(0, 0, 0, 0)
        video_slider_h_box.setSpacing(10)
        h_box.setSpacing(0)
        v_box.setSpacing(0)

        self.setLayout(v_box)
        self.enabler()

        # connections
        self.open_btn.clicked.connect(self.open_file)
        self.play_btn.clicked.connect(self.play_media)
        self.stop_btn.clicked.connect(self.stop_media)

        self.prev_btn.pressed.connect(self.play_prev)
        self.next_btn.pressed.connect(self.play_next)
        self.switch_media_widgets_btn.pressed.connect(self.switch_media)

        self.playlist.currentIndexChanged.connect(self.playlist_position_changed)
        selection_model = self.playlistView.selectionModel()
        selection_model.selectionChanged.connect(self.playlist_selection_changed)

        self.mediaPlayer.durationChanged.connect(self.update_duration)
        self.mediaPlayer.positionChanged.connect(self.update_position)
        self.timeSlider.valueChanged.connect(self.mediaPlayer.setPosition)

        self.mediaPlayer.stateChanged.connect(self.media_state)

        self.mediaPlayer.volumeChanged.connect(self.volume_changed)
        self.volume_slider.valueChanged.connect(self.set_volume)

    def set_children_focus_policy(self, policy):
        def recursive_set_child_focus_policy(parent_q_widget):
            for childQWidget in parent_q_widget.findChildren(QWidget):
                childQWidget.setFocusPolicy(policy)
                recursive_set_child_focus_policy(childQWidget)

        recursive_set_child_focus_policy(self)

    def enabler(self, state=False):
        if state is False:
            self.play_btn.setEnabled(False)
            self.prev_btn.setEnabled(False)
            self.stop_btn.setEnabled(False)
            self.next_btn.setEnabled(False)
        else:
            self.play_btn.setEnabled(True)
            self.stop_btn.setEnabled(True)
            self.prev_btn.setEnabled(True)
            self.next_btn.setEnabled(True)

    def switch_media(self):
        if self.switch_status == 0:
            self.video_widget.hide()
            self.playlistView.show()
            self.switch_status = 1
            self.switch_media_widgets_btn.setEnabled(True)
        elif self.switch_status == 1:
            self.video_widget.show()
            self.playlistView.hide()
            self.switch_status = 0
            self.switch_media_widgets_btn.setEnabled(True)
        else:
            self.video_widget.hide()
            self.playlistView.show()
            self.switch_media_widgets_btn.setEnabled(False)

    def play_media(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()
        self.ui_handler()

    def ui_handler(self):
        if not self.playlist.isEmpty():
            self.enabler(True)
        file_path = QFileInfo(self.mediaPlayer.currentMedia().canonicalUrl().toString()).fileName()
        ext = os.path.splitext(file_path)[-1].lower()
        audio_ext = ['.flac', '.mp3']
        video_ext = ['.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv']

        if ext in audio_ext:
            self.switch_status = 2
            self.switch_media()
            if self.isFullScreen():
                self.fullscreen()
        elif ext in video_ext:
            self.switch_status = 1
            self.switch_media()
        self.setWindowTitle(file_path + ' - Media Player')
        self.titleBar.label.setText(file_path + ' - Media Player')

    def stop_media(self):
        if self.mediaPlayer.state() != QMediaPlayer.StoppedState:
            self.mediaPlayer.stop()
            self.setWindowTitle('Media Player')
            self.titleBar.label.setText('Media Player')

    def fullscreen(self):
        if self.switch_status == 2 or self.isFullScreen():
            self.titleBar.show()
            self.timeSlider.show()
            self.currentTimeLabel.show()
            self.totalTimeLabel.show()
            self.volume_slider.show()
            self.open_btn.show()
            self.play_btn.show()
            self.prev_btn.show()
            self.stop_btn.show()
            self.next_btn.show()
            self.switch_media_widgets_btn.show()
            self.pseudo_label.show()
            self.vol_label.show()
            self.showNormal()
        else:
            self.titleBar.hide()
            self.timeSlider.hide()
            self.currentTimeLabel.hide()
            self.totalTimeLabel.hide()
            self.volume_slider.hide()
            self.open_btn.hide()
            self.play_btn.hide()
            self.prev_btn.hide()
            self.stop_btn.hide()
            self.next_btn.hide()
            self.switch_media_widgets_btn.hide()
            self.pseudo_label.hide()
            self.vol_label.hide()
            self.showFullScreen()

    def mouseDoubleClickEvent(self, event: QMouseEvent):
        event.accept()
        if event.button() == Qt.LeftButton:
            self.fullscreen()

    def media_state(self):

        os_sleep = WindowsInhibitor()
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
            if os.name == 'nt':
                os_sleep = WindowsInhibitor()
                os_sleep.inhibit()
        else:
            self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
            if os_sleep:
                os_sleep.uninhibit()

    def play_next(self):
        self.playlist.next()

    def media_seek(self, seek):
        if not self.playlist.isEmpty():
            player = self.mediaPlayer
            if (player.duration() - seek) > player.position():
                player.setPosition(player.position() + seek)

    def play_prev(self):
        self.playlist.previous()

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.acceptProposedAction()

    def dropEvent(self, e):
        for url in e.mimeData().urls():
            ext = os.path.splitext(url.fileName())[-1].lower()
            allowed_ext = ['.flac', '.mp3', '.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv']
            if ext in allowed_ext:
                self.playlist.addMedia(
                    QMediaContent(url)
                )

        self.model.layoutChanged.emit()

        if self.mediaPlayer.state() != QMediaPlayer.PlayingState:
            i = self.playlist.mediaCount() - len(e.mimeData().urls())
            self.playlist.setCurrentIndex(i)
            if not self.playlist.isEmpty():
                self.play_media()

    def open_file(self):
        filter_files = "Media (*.mp3 *.mp4 *.mkv);; Videos files (*.mp4 *.mkv);; Music Files(*.mp3)"
        paths, _ = QFileDialog.getOpenFileNames(self, "Open file", "", filter_files)

        if paths:
            self.mediaPlayer.pause()
            for path in paths:
                self.playlist.addMedia(
                    QMediaContent(
                        QUrl.fromLocalFile(path)
                    )
                )
            i = self.playlist.mediaCount() - len(paths)
            self.playlist.setCurrentIndex(i)
            self.play_media()

        self.model.layoutChanged.emit()

    def update_duration(self, duration):
        self.mediaPlayer.duration()

        self.timeSlider.setMaximum(duration)

        if duration >= 0:
            self.totalTimeLabel.setText(hhmmss(duration))

    def update_position(self, position):
        if position >= 0:
            self.currentTimeLabel.setText(hhmmss(position))

        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        self.timeSlider.blockSignals(False)

    def playlist_selection_changed(self, ix):
        i = ix.indexes()[0].row()
        self.playlist.setCurrentIndex(i)
        self.ui_handler()

    def playlist_position_changed(self, i):
        if i > -1:
            ix = self.model.index(i)
            self.playlistView.setCurrentIndex(ix)

    def set_volume(self, value):
        self.mediaPlayer.setVolume(value)

    def volume_changed(self, value):
        self.volume_slider.setValue(value)

    def keyPressEvent(self, event):
        key = event.key()
        modifiers = int(event.modifiers())
        if (modifiers and modifiers & MOD_MASK == modifiers and
                key > 0 and key != Qt.Key_Shift and key != Qt.Key_Alt and
                key != Qt.Key_Control and key != Qt.Key_Meta):
            key_name = QKeySequence(modifiers + key).toString()
            if key_name == 'Ctrl+Right':
                self.media_seek(30000)
            elif key_name == 'Ctrl+Left':
                self.media_seek(-30000)
            elif key_name == 'Ctrl+Up':
                self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 5)
            elif key_name == 'Ctrl+Down':
                self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 5)
            elif key_name == 'Ctrl+O':
                self.open_file()

        else:
            if event.key() == Qt.Key_Space:
                self.play_media()
            elif event.key() == Qt.Key_MediaPlay:
                self.play_media()
            elif event.key() == Qt.Key_MediaNext:
                self.play_next()
            elif event.key() == Qt.Key_MediaPrevious:
                self.play_prev()
            elif event.key() == Qt.Key_Escape:
                self.close()
            elif event.key() == Qt.Key_F:
                self.fullscreen()
            elif event.key() == Qt.Key_Right:
                self.media_seek(5000)
            elif event.key() == Qt.Key_Left:
                self.media_seek(-5000)
Beispiel #12
0
class YtdlMusic(QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)
        self.setupUi(self)
        self.setWindowIcon(QIcon(LOCAL_DIR + '/ytdl_music.svg'))

        self.player = QMediaPlayer()
        self.player.isSeekable()
        self.playList = QMediaPlaylist()
        self.playListData = []
        self.player.setPlaylist(self.playList)
        self.currentPos = 0
        self.currentTrackDuration = '0:00:00'

        self.player.positionChanged.connect(self.positionChanged)
        self.player.durationChanged.connect(self.durationChanged)
        self.playList.currentIndexChanged.connect(self.playlistPosChanged)
        self.playlistTable.itemDoubleClicked.connect(self.changeTrack)
        self.playlistTable.itemSelectionChanged.connect(self.selectedTracks)
        # self.timeSlider.valueChanged.connect(self.setPosition)
        self.addBtn.clicked.connect(self.addDialog)
        self.removeBtn.clicked.connect(self.delTracks)
        self.playBtn.clicked.connect(self.playPause)
        self.stopBtn.clicked.connect(self.stop)
        self.prevBtn.clicked.connect(self.playList.previous)
        self.nextBtn.clicked.connect(self.playList.next)

        self.playlistTable.setHorizontalHeaderLabels([
            '',
            _translate('MainWindow', 'Channel'),
            _translate('MainWindow', 'Title')
        ])
        header = self.playlistTable.horizontalHeader()
        header.setSectionResizeMode(1, QHeaderView.Stretch)
        header.setSectionResizeMode(2, QHeaderView.Stretch)

    def setPosition(self, pos):
        self.player.setPosition(pos)

    def durationChanged(self, duration):
        total_time = '0:00:00'
        duration = self.player.duration()
        total_time = ms_to_time(duration)
        # self.timeSlider.setMaximum(duration)
        self.currentTrackDuration = duration
        # self.totalTimeLabel.setText(total_time)
        self.currentTrackDuration = total_time

    def mediaStatusChanged(self, status):
        icon = QIcon.fromTheme("media-playback-pause")
        if self.player.state() == QMediaPlayer.StoppedState:
            icon = QIcon.fromTheme("media-playback-start")
        elif self.player.state() == QMediaPlayer.PausedState:
            icon = QIcon.fromTheme("media-playback-start")

        self.playBtn.setIcon(icon)

    def positionChanged(self, position, senderType=False):
        self.currentTime = position
        current_time = '0:00:00'

        if position != -1:
            current_time = ms_to_time(position)
            self.timeLabel.setText('{0} / {1}'.format(
                current_time, self.currentTrackDuration))
        '''self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        self.timeSlider.blockSignals(False)'''

    def playlistPosChanged(self):
        pos = self.playList.currentIndex()
        data = self.playListData[pos]
        self.setWindowTitle('YouTube-dl Music: ' + data['title'])
        duration = ms_to_time(data['duration'] * 1000)
        self.timeLabel.setText('0:00:00 / {0}'.format(duration))
        # self.totalTimeLabel.setText(ms_to_time(data['duration'] * 1000))
        if self.playList.mediaCount() > 1:
            if pos < self.playList.mediaCount() - 1:
                self.nextBtn.setEnabled(True)
            else:
                self.nextBtn.setEnabled(False)

            if pos > 0:
                self.prevBtn.setEnabled(True)
            else:
                self.prevBtn.setEnabled(False)

            prevPos = 0
            if pos < self.playList.mediaCount():
                if self.currentPos < pos:
                    prevPos = pos - 1
                else:
                    prevPos = pos + 1

                statusItem = QLabel()
                icon = QIcon.fromTheme("media-playback-start")
                statusItem.setPixmap(icon.pixmap(16, 16))
                statusItem.setAlignment(Qt.AlignCenter)
                self.playlistTable.setCellWidget(pos, 0, statusItem)
                if prevPos > -1:
                    self.playlistTable.setCellWidget(prevPos, 0, QLabel())
            else:
                self.playlistTable.setItem(pos, 0, QTableWidgetItem(''))

            self.currentPos = pos

        else:
            statusItem = QLabel()
            icon = QIcon.fromTheme("media-playback-start")
            statusItem.setPixmap(icon.pixmap(16, 16))
            statusItem.setAlignment(Qt.AlignCenter)
            self.playlistTable.setCellWidget(pos, 0, statusItem)

    def playPause(self):
        icon = QIcon.fromTheme("media-playback-pause")

        if self.player.state() == QMediaPlayer.StoppedState:
            if self.player.mediaStatus() == QMediaPlayer.NoMedia:
                if self.playList.mediaCount() != 0:
                    self.player.play()
            elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia:
                self.playList.setCurrentIndex(self.currentPos)
                self.player.play()
            elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia:
                self.player.play()
        elif self.player.state() == QMediaPlayer.PlayingState:
            icon = QIcon.fromTheme("media-playback-start")
            self.player.pause()
        elif self.player.state() == QMediaPlayer.PausedState:
            self.player.play()

        self.playBtn.setIcon(icon)

    def stop(self):
        self.player.stop()
        icon = QIcon.fromTheme("media-playback-start")
        self.playBtn.setIcon(icon)

    def insertTrack(self, data):
        if data:
            self.playListData.append(data)
            totalTracks = self.playList.mediaCount()
            pos = totalTracks
            self.playlistTable.insertRow(totalTracks)
            self.playlistTable.setRowCount(totalTracks + 1)
            self.playlistTable.setItem(pos, 0, QTableWidgetItem(''))
            self.playlistTable.setItem(pos, 1,
                                       QTableWidgetItem(data['channel']))
            self.playlistTable.setItem(pos, 2, QTableWidgetItem(data['title']))
            media = QMediaContent(QUrl(data['url']))
            self.playList.addMedia(media)
            if totalTracks > 1:
                self.nextBtn.setEnabled(True)
        else:
            self.statusBar().showMessage('Total pistas: {0}'.format(
                self.playList.mediaCount()))

    def addDialog(self):
        url, ok = QInputDialog.getText(
            self, _translate('MainWindow', 'Add video/playlist'), 'URL:')
        if ok and url != '':
            self.addPCThread = addVideos(self, url)
            self.addPCThread.video.connect(self.insertTrack)
            self.addPCThread.start()

    def changeTrack(self, item):
        pos = item.row()
        self.playlistTable.setCellWidget(self.currentPos, 0, QLabel())
        self.playList.setCurrentIndex(pos)
        if self.player.state() == QMediaPlayer.StoppedState:
            icon = QIcon.fromTheme("media-playback-pause")
            self.playBtn.setIcon(icon)
            self.player.play()

    def delTracks(self):
        indexes = self.playlistTable.selectionModel().selectedRows()
        del_first = True
        for index in sorted(indexes):
            pos = index.row()
            if not del_first:
                pos -= 1
            else:
                del_first = False

            self.playlistTable.removeRow(pos)
            self.playListData.pop(pos)
            self.playList.removeMedia(pos)

        self.playlistPosChanged()

    def selectedTracks(self):
        totalSelected = len(self.playlistTable.selectedItems())
        if totalSelected > 0:
            self.removeBtn.setEnabled(True)
        else:
            self.removeBtn.setEnabled(False)
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        self.player = QMediaPlayer()

        self.player.error.connect(self.erroralert)
        self.player.play()
        self.player.stateChanged.connect(self.Set_Icons)
        # self.player.volumeChanged.connect(self.prev_volume)
        # Connect control buttons/slides for media player.
        self.playButton.pressed.connect(self.play_pause)
        self.stopButton.pressed.connect(self.player.stop)
        self.showButton.pressed.connect(self.playlist_toggle)
        self.equalizerButton.pressed.connect(self.ShowEqualizer)
        self.volumeButton.pressed.connect(self.mute)

        self.volumeSlider.valueChanged.connect(self.volumeChanged)
        self.currentVolume = self.volumeSlider.value()
        self.timeSlider.valueChanged.connect(self.player.setPosition)

        # Setup the playlist.
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        self.model = PlaylistModel(self.playlist)
        self.listWidget.setModel(self.model)
        self.playlist.currentIndexChanged.connect(
            self.playlist_position_changed)
        selection_model = self.listWidget.selectionModel()
        selection_model.selectionChanged.connect(
            self.playlist_selection_changed)

        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)

        self.actionOpen_File.triggered.connect(self.open_file)
        self.files = []
        self.setAcceptDrops(True)

        self.graphWidget.setBackground((60, 60, 60))
        self.graphWidget.GetViewBox().setMenuEnabled(False)
        self.graphWidget.GetViewBox().setMouseEnabled(x=False, y=False)
        self.graphWidget.setPlotEQ((42, 130, 218))

        self.Visualizer = FFTAnalyser(self.player)
        self.Visualizer.calculated_visual.connect(self.draw)
        self.Visualizer.start()
        self.Equalizer = QWidget()
        self.visdata = np.array([])
        self.show()

    def draw(self, visdata):
        self.visdata = np.array(visdata)
        self.graphWidget.UpdatePlotEQ(self.visdata)

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.acceptProposedAction()

    def play_pause(self):
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def Set_Icons(self, state):
        if state == QMediaPlayer.StoppedState:
            self.stopButton.setIcon(
                qta.icon('fa5s.stop-circle',
                         active='fa5s.stop-circle',
                         color='white',
                         color_active='grey'))
            self.playButton.setIcon(qta.icon('fa5s.play-circle',
                                             color='white'))
            self.playButton.setToolTip('Play')
        elif state == QMediaPlayer.PlayingState:
            self.playButton.setIcon(
                qta.icon('fa5s.pause-circle', color='white'))
            self.playButton.setToolTip('Pause')
        elif state == QMediaPlayer.PausedState:
            self.playButton.setIcon(qta.icon('fa5s.play-circle',
                                             color='white'))
            self.playButton.setToolTip('Play')

    def playlist_toggle(self):
        if self.listWidget.isHidden():
            self.listWidget.setHidden(False)
            self.listWidget.setProperty("showDropIndicator", True)
            self.showButton.setIcon(qta.icon('fa5s.eye-slash', color='white'))
            self.showButton.setToolTip('Hide Playlist')
        else:
            self.listWidget.setHidden(True)
            self.listWidget.setProperty("showDropIndicator", False)
            self.showButton.setIcon(qta.icon('fa5s.list-ul', color='white'))
            self.showButton.setToolTip('Show Playlist')

    def dropEvent(self, e):
        for url in e.mimeData().urls():
            self.playlist.addMedia(QMediaContent(url))

        self.model.layoutChanged.emit()

        # If not playing, seeking to first of newly added + play.
        if self.player.state() != QMediaPlayer.PlayingState:
            i = self.playlist.mediaCount() - len(e.mimeData().urls())
            self.playlist.setCurrentIndex(i)
            self.player.play()

    def open_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        path, _ = QFileDialog.getOpenFileName(self,
                                              "Open file",
                                              "",
                                              "Music Files (*.mp3 *.wav)",
                                              options=options)

        if path:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))
            self.files.append(QMediaContent(QUrl.fromLocalFile(path)))

        self.model.layoutChanged.emit()

    # def contextMenuEvent(self, event):
    # contextMenu = QMenu(self)
    # graph = contextMenu.addAction("Show Graph")

    def update_duration(self, duration):
        print("!", duration)
        print("?", self.player.duration())

        self.timeSlider.setMaximum(duration)

        if duration >= 0:
            self.totalTimeLabel.setText(hhmmss(duration))

    def update_position(self, position):
        if position >= 0:
            self.currentTimeLabel.setText(hhmmss(position))

        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        self.timeSlider.blockSignals(False)

    def playlist_selection_changed(self, ix):
        i = ix.indexes()[0].row()
        self.playlist.setCurrentIndex(i)

    def playlist_position_changed(self, i):
        if i > -1:
            ix = self.model.index(i)
            self.listWidget.setCurrentIndex(ix)

    def erroralert(self, *args):
        print(args)

    def ShowEqualizer(self):
        if self.player.currentMedia().canonicalUrl().path() != "":
            self.Equalizer = WindowingWidget(
                self.player.currentMedia().canonicalUrl().path())
            self.Equalizer.SendPath.connect(self.AddPathToPlaylist)
            self.Equalizer.show()

    def AddPathToPlaylist(self, path):
        if path:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))
            self.files.append(path)

        self.model.layoutChanged.emit()

    def volumeChanged(self):
        self.currentVolume = self.volumeSlider.value()
        self.player.setVolume(self.volumeSlider.value())

    def mute(self):
        if self.player.isMuted():
            self.player.setMuted(False)
            self.volumeButton.setIcon(qta.icon('fa5s.volume-up',
                                               color='white'))
            self.volumeButton.setToolTip('Mute')
            self.volumeSlider.setEnabled(True)
        else:
            self.player.setMuted(True)
            self.volumeButton.setIcon(
                qta.icon('fa5s.volume-mute', color='white'))
            self.volumeButton.setToolTip('Unmute')
            self.volumeSlider.setEnabled(False)

    def closeEvent(self, event):
        self.Visualizer.terminate()
        if self.Equalizer.isVisible():
            self.Equalizer.close()
Beispiel #14
0
class MusicPlayer(QMainWindow):
    """MusicPlayer houses all of elements that directly interact with the main window."""

    def __init__(self, parent=None):
        """Initialize the QMainWindow widget.

        The window title, window icon, and window size are initialized here as well
        as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar,
        QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and
        QVBoxLayout. The connect signals for relavant widgets are also initialized.
        """
        super(MusicPlayer, self).__init__(parent)
        self.setWindowTitle('Mosaic')

        window_icon = utilities.resource_filename('mosaic.images', 'icon.png')
        self.setWindowIcon(QIcon(window_icon))
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

        # Initiates Qt objects to be used by MusicPlayer
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist_location = defaults.Settings().playlist_path
        self.content = QMediaContent()
        self.menu = self.menuBar()
        self.toolbar = QToolBar()
        self.art = QLabel()
        self.pixmap = QPixmap()
        self.slider = QSlider(Qt.Horizontal)
        self.duration_label = QLabel()
        self.playlist_dock = QDockWidget('Playlist', self)
        self.library_dock = QDockWidget('Media Library', self)
        self.playlist_view = QListWidget()
        self.library_view = library.MediaLibraryView()
        self.library_model = library.MediaLibraryModel()
        self.preferences = configuration.PreferencesDialog()
        self.widget = QWidget()
        self.layout = QVBoxLayout(self.widget)
        self.duration = 0
        self.playlist_dock_state = None
        self.library_dock_state = None

        # Sets QWidget() as the central widget of the main window
        self.setCentralWidget(self.widget)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        # Initiates the playlist dock widget and the library dock widget
        self.addDockWidget(defaults.Settings().dock_position, self.playlist_dock)
        self.playlist_dock.setWidget(self.playlist_view)
        self.playlist_dock.setVisible(defaults.Settings().playlist_on_start)
        self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable)

        self.addDockWidget(defaults.Settings().dock_position, self.library_dock)
        self.library_dock.setWidget(self.library_view)
        self.library_dock.setVisible(defaults.Settings().media_library_on_start)
        self.library_dock.setFeatures(QDockWidget.DockWidgetClosable)
        self.tabifyDockWidget(self.playlist_dock, self.library_dock)

        # Sets the range of the playback slider and sets the playback mode as looping
        self.slider.setRange(0, self.player.duration() / 1000)
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

        # OSX system menu bar causes conflicts with PyQt5 menu bar
        if sys.platform == 'darwin':
            self.menu.setNativeMenuBar(False)

        # Initiates Settings in the defaults module to give access to settings.toml
        defaults.Settings()

        # Signals that connect to other methods when they're called
        self.player.metaDataChanged.connect(self.display_meta_data)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.song_duration)
        self.player.positionChanged.connect(self.song_position)
        self.player.stateChanged.connect(self.set_state)
        self.playlist_view.itemActivated.connect(self.activate_playlist_item)
        self.library_view.activated.connect(self.open_media_library)
        self.playlist.currentIndexChanged.connect(self.change_index)
        self.playlist.mediaInserted.connect(self.initialize_playlist)
        self.playlist_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.library_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.preferences.dialog_media_library.media_library_line.textChanged.connect(self.change_media_library_path)
        self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(self.change_window_size)
        self.art.mousePressEvent = self.press_playback

        # Creating the menu controls, media controls, and window size of the music player
        self.menu_controls()
        self.media_controls()
        self.load_saved_playlist()

    def menu_controls(self):
        """Initiate the menu bar and add it to the QMainWindow widget."""
        self.file = self.menu.addMenu('File')
        self.edit = self.menu.addMenu('Edit')
        self.playback = self.menu.addMenu('Playback')
        self.view = self.menu.addMenu('View')
        self.help_ = self.menu.addMenu('Help')

        self.file_menu()
        self.edit_menu()
        self.playback_menu()
        self.view_menu()
        self.help_menu()

    def media_controls(self):
        """Create the bottom toolbar and controls used for media playback."""
        self.addToolBar(Qt.BottomToolBarArea, self.toolbar)
        self.toolbar.setMovable(False)

        play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
        self.play_action = QAction(QIcon(play_icon), 'Play', self)
        self.play_action.triggered.connect(self.player.play)

        stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png')
        self.stop_action = QAction(QIcon(stop_icon), 'Stop', self)
        self.stop_action.triggered.connect(self.player.stop)

        previous_icon = utilities.resource_filename('mosaic.images', 'md_previous.png')
        self.previous_action = QAction(QIcon(previous_icon), 'Previous', self)
        self.previous_action.triggered.connect(self.previous)

        next_icon = utilities.resource_filename('mosaic.images', 'md_next.png')
        self.next_action = QAction(QIcon(next_icon), 'Next', self)
        self.next_action.triggered.connect(self.playlist.next)

        repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
        self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self)
        self.repeat_action.setShortcut('R')
        self.repeat_action.triggered.connect(self.repeat_song)

        self.toolbar.addAction(self.play_action)
        self.toolbar.addAction(self.stop_action)
        self.toolbar.addAction(self.previous_action)
        self.toolbar.addAction(self.next_action)
        self.toolbar.addAction(self.repeat_action)
        self.toolbar.addWidget(self.slider)
        self.toolbar.addWidget(self.duration_label)

    def file_menu(self):
        """Add a file menu to the menu bar.

        The file menu houses the Open File, Open Multiple Files, Open Playlist,
        Open Directory, and Exit Application menu items.
        """
        self.open_action = QAction('Open File', self)
        self.open_action.setShortcut('O')
        self.open_action.triggered.connect(self.open_file)

        self.open_multiple_files_action = QAction('Open Multiple Files', self)
        self.open_multiple_files_action.setShortcut('M')
        self.open_multiple_files_action.triggered.connect(self.open_multiple_files)

        self.open_playlist_action = QAction('Open Playlist', self)
        self.open_playlist_action.setShortcut('CTRL+P')
        self.open_playlist_action.triggered.connect(self.open_playlist)

        self.open_directory_action = QAction('Open Directory', self)
        self.open_directory_action.setShortcut('D')
        self.open_directory_action.triggered.connect(self.open_directory)

        self.save_playlist_action = QAction('Save Playlist', self)
        self.save_playlist_action.setShortcut('CTRL+S')
        self.save_playlist_action.triggered.connect(self.save_playlist)

        self.exit_action = QAction('Quit', self)
        self.exit_action.setShortcut('CTRL+Q')
        self.exit_action.triggered.connect(self.closeEvent)

        self.file.addAction(self.open_action)
        self.file.addAction(self.open_multiple_files_action)
        self.file.addAction(self.open_playlist_action)
        self.file.addAction(self.open_directory_action)
        self.file.addSeparator()
        self.file.addAction(self.save_playlist_action)
        self.file.addSeparator()
        self.file.addAction(self.exit_action)

    def edit_menu(self):
        """Add an edit menu to the menu bar.

        The edit menu houses the preferences item that opens a preferences dialog
        that allows the user to customize features of the music player.
        """
        self.preferences_action = QAction('Preferences', self)
        self.preferences_action.setShortcut('CTRL+SHIFT+P')
        self.preferences_action.triggered.connect(lambda: self.preferences.exec_())

        self.edit.addAction(self.preferences_action)

    def playback_menu(self):
        """Add a playback menu to the menu bar.

        The playback menu houses
        """
        self.play_playback_action = QAction('Play', self)
        self.play_playback_action.setShortcut('P')
        self.play_playback_action.triggered.connect(self.player.play)

        self.stop_playback_action = QAction('Stop', self)
        self.stop_playback_action.setShortcut('S')
        self.stop_playback_action.triggered.connect(self.player.stop)

        self.previous_playback_action = QAction('Previous', self)
        self.previous_playback_action.setShortcut('B')
        self.previous_playback_action.triggered.connect(self.previous)

        self.next_playback_action = QAction('Next', self)
        self.next_playback_action.setShortcut('N')
        self.next_playback_action.triggered.connect(self.playlist.next)

        self.playback.addAction(self.play_playback_action)
        self.playback.addAction(self.stop_playback_action)
        self.playback.addAction(self.previous_playback_action)
        self.playback.addAction(self.next_playback_action)

    def view_menu(self):
        """Add a view menu to the menu bar.

        The view menu houses the Playlist, Media Library, Minimalist View, and Media
        Information menu items. The Playlist item toggles the playlist dock into and
        out of view. The Media Library items toggles the media library dock into and
        out of view. The Minimalist View item resizes the window and shows only the
        menu bar and player controls. The Media Information item opens a dialog that
        shows information relevant to the currently playing song.
        """
        self.dock_action = self.playlist_dock.toggleViewAction()
        self.dock_action.setShortcut('CTRL+ALT+P')

        self.library_dock_action = self.library_dock.toggleViewAction()
        self.library_dock_action.setShortcut('CTRL+ALT+L')

        self.minimalist_view_action = QAction('Minimalist View', self)
        self.minimalist_view_action.setShortcut('CTRL+ALT+M')
        self.minimalist_view_action.setCheckable(True)
        self.minimalist_view_action.triggered.connect(self.minimalist_view)

        self.view_media_info_action = QAction('Media Information', self)
        self.view_media_info_action.setShortcut('CTRL+SHIFT+M')
        self.view_media_info_action.triggered.connect(self.media_information_dialog)

        self.view.addAction(self.dock_action)
        self.view.addAction(self.library_dock_action)
        self.view.addSeparator()
        self.view.addAction(self.minimalist_view_action)
        self.view.addSeparator()
        self.view.addAction(self.view_media_info_action)

    def help_menu(self):
        """Add a help menu to the menu bar.

        The help menu houses the about dialog that shows the user information
        related to the application.
        """
        self.about_action = QAction('About', self)
        self.about_action.setShortcut('H')
        self.about_action.triggered.connect(lambda: about.AboutDialog().exec_())

        self.help_.addAction(self.about_action)

    def open_file(self):
        """Open the selected file and add it to a new playlist."""
        filename, success = QFileDialog.getOpenFileName(self, 'Open File', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            file_info = QFileInfo(filename).fileName()
            playlist_item = QListWidgetItem(file_info)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(filename)))
            self.player.setPlaylist(self.playlist)
            playlist_item.setToolTip(file_info)
            self.playlist_view.addItem(playlist_item)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_multiple_files(self):
        """Open the selected files and add them to a new playlist."""
        filenames, success = QFileDialog.getOpenFileNames(self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            self.playlist.clear()
            self.playlist_view.clear()
            for file in natsort.natsorted(filenames, alg=natsort.ns.PATH):
                file_info = QFileInfo(file).fileName()
                playlist_item = QListWidgetItem(file_info)
                self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                self.player.setPlaylist(self.playlist)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)
                self.playlist_view.setCurrentRow(0)
                self.player.play()

    def open_playlist(self):
        """Load an M3U or PLS file into a new playlist."""
        playlist, success = QFileDialog.getOpenFileName(self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '', QFileDialog.ReadOnly)

        if success:
            playlist = QUrl.fromLocalFile(playlist)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def save_playlist(self):
        """Save the media in the playlist dock as a new M3U playlist."""
        playlist, success = QFileDialog.getSaveFileName(self, 'Save Playlist', '', 'Playlist (*.m3u)', '')
        if success:
            saved_playlist = "{}.m3u" .format(playlist)
            self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u")

    def load_saved_playlist(self):
        """Load the saved playlist if user setting permits."""
        saved_playlist = "{}/.m3u" .format(self.playlist_location)
        if os.path.exists(saved_playlist):
            playlist = QUrl().fromLocalFile(saved_playlist)
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)

    def open_directory(self):
        """Open the selected directory and add the files within to an empty playlist."""
        directory = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ReadOnly)

        if directory:
            self.playlist.clear()
            self.playlist_view.clear()
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

            self.player.setPlaylist(self.playlist)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_media_library(self, index):
        """Open a directory or file from the media library into an empty playlist."""
        self.playlist.clear()
        self.playlist_view.clear()

        if self.library_model.fileName(index).endswith(('mp3', 'flac')):
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(self.library_model.filePath(index))))
            self.playlist_view.addItem(self.library_model.fileName(index))

        elif self.library_model.isDir(index):
            directory = self.library_model.filePath(index)
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

        self.player.setPlaylist(self.playlist)
        self.player.play()

    def display_meta_data(self):
        """Display the current song's metadata in the main window.

        If the current song contains metadata, its cover art is extracted and shown in
        the main window while the track number, artist, album, and track title are shown
        in the window title.
        """
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
            (album, artist, title, track_number, *__, artwork) = metadata.metadata(file_path)

            try:
                self.pixmap.loadFromData(artwork)
            except TypeError:
                self.pixmap = QPixmap(artwork)

            meta_data = '{} - {} - {} - {}' .format(track_number, artist, album, title)

            self.setWindowTitle(meta_data)
            self.art.setScaledContents(True)
            self.art.setPixmap(self.pixmap)
            self.layout.addWidget(self.art)

    def initialize_playlist(self, start):
        """Display playlist and reset playback mode when media inserted into playlist."""
        if start == 0:
            if self.library_dock.isVisible():
                self.playlist_dock.setVisible(True)
                self.playlist_dock.show()
                self.playlist_dock.raise_()

            if self.playlist.playbackMode() != QMediaPlaylist.Sequential:
                self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
                repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
                self.repeat_action.setIcon(QIcon(repeat_icon))

    def press_playback(self, event):
        """Change the playback of the player on cover art mouse event.

        When the cover art is clicked, the player will play the media if the player is
        either paused or stopped. If the media is playing, the media is set
        to pause.
        """
        if event.button() == 1 and configuration.Playback().cover_art_playback.isChecked():
            if (self.player.state() == QMediaPlayer.StoppedState or
                    self.player.state() == QMediaPlayer.PausedState):
                self.player.play()
            elif self.player.state() == QMediaPlayer.PlayingState:
                self.player.pause()

    def seek(self, seconds):
        """Set the position of the song to the position dragged to by the user."""
        self.player.setPosition(seconds * 1000)

    def song_duration(self, duration):
        """Set the slider to the duration of the currently played media."""
        duration /= 1000
        self.duration = duration
        self.slider.setMaximum(duration)

    def song_position(self, progress):
        """Move the horizontal slider in sync with the duration of the song.

        The progress is relayed to update_duration() in order
        to display the time label next to the slider.
        """
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.update_duration(progress)

    def update_duration(self, current_duration):
        """Calculate the time played and the length of the song.

        Both of these times are sent to duration_label() in order to display the
        times on the toolbar.
        """
        duration = self.duration

        if current_duration or duration:
            time_played = QTime((current_duration / 3600) % 60, (current_duration / 60) % 60,
                                (current_duration % 60), (current_duration * 1000) % 1000)
            song_length = QTime((duration / 3600) % 60, (duration / 60) % 60, (duration % 60),
                                (duration * 1000) % 1000)

            if duration > 3600:
                time_format = "hh:mm:ss"
            else:
                time_format = "mm:ss"

            time_display = "{} / {}" .format(time_played.toString(time_format), song_length.toString(time_format))

        else:
            time_display = ""

        self.duration_label.setText(time_display)

    def set_state(self, state):
        """Change the icon in the toolbar in relation to the state of the player.

        The play icon changes to the pause icon when a song is playing and
        the pause icon changes back to the play icon when either paused or
        stopped.
        """
        if self.player.state() == QMediaPlayer.PlayingState:
            pause_icon = utilities.resource_filename('mosaic.images', 'md_pause.png')
            self.play_action.setIcon(QIcon(pause_icon))
            self.play_action.triggered.connect(self.player.pause)

        elif (self.player.state() == QMediaPlayer.PausedState or self.player.state() == QMediaPlayer.StoppedState):
            self.play_action.triggered.connect(self.player.play)
            play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
            self.play_action.setIcon(QIcon(play_icon))

    def previous(self):
        """Move to the previous song in the playlist.

        Moves to the previous song in the playlist if the current song is less
        than five seconds in. Otherwise, restarts the current song.
        """
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def repeat_song(self):
        """Set the current media to repeat and change the repeat icon accordingly.

        There are four playback modes: repeat none, repeat all, repeat once, and shuffle.
        Clicking the repeat button cycles through each playback mode.
        """
        if self.playlist.playbackMode() == QMediaPlaylist.Sequential:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_all.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Loop:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_once.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop:
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_shuffle.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Random:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

    def activate_playlist_item(self, item):
        """Set the active media to the playlist item dobule-clicked on by the user."""
        current_index = self.playlist_view.row(item)
        if self.playlist.currentIndex() != current_index:
            self.playlist.setCurrentIndex(current_index)

        if self.player.state() != QMediaPlayer.PlayingState:
            self.player.play()

    def change_index(self, row):
        """Highlight the row in the playlist of the active media."""
        self.playlist_view.setCurrentRow(row)

    def minimalist_view(self):
        """Resize the window to only show the menu bar and audio controls."""
        if self.minimalist_view_action.isChecked():

            if self.playlist_dock.isVisible():
                self.playlist_dock_state = True
            if self.library_dock.isVisible():
                self.library_dock_state = True

            self.library_dock.close()
            self.playlist_dock.close()

            QTimer.singleShot(10, lambda: self.resize(500, 0))

        else:
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

            if self.library_dock_state:
                self.library_dock.setVisible(True)

            if self.playlist_dock_state:
                self.playlist_dock.setVisible(True)

    def dock_visiblity_change(self, visible):
        """Change the size of the main window when the docks are toggled."""
        if visible and self.playlist_dock.isVisible() and not self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.playlist_dock.width() + 6,
                        self.height())

        elif visible and not self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif visible and self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif (not visible and not self.playlist_dock.isVisible() and not
                self.library_dock.isVisible()):
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def media_information_dialog(self):
        """Show a dialog of the current song's metadata."""
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
        else:
            file_path = None
        dialog = information.InformationDialog(file_path)
        dialog.exec_()

    def change_window_size(self):
        """Change the window size of the music player."""
        self.playlist_dock.close()
        self.library_dock.close()
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def change_media_library_path(self, path):
        """Change the media library path to the new path selected in the preferences dialog."""
        self.library_model.setRootPath(path)
        self.library_view.setModel(self.library_model)
        self.library_view.setRootIndex(self.library_model.index(path))

    def closeEvent(self, event):
        """Override the PyQt close event in order to handle save playlist on close."""
        playlist = "{}/.m3u" .format(self.playlist_location)
        if defaults.Settings().save_playlist_on_close:
            self.playlist.save(QUrl().fromLocalFile(playlist), "m3u")
        else:
            if os.path.exists(playlist):
                os.remove(playlist)
        QApplication.quit()
Beispiel #15
0
class Player(QFrame):
    def __init__(self, parent=None):
        """头部区域,包括图标/搜索/设置/登陆/最大/小化/关闭。"""
        super().__init__()

        self.setObjectName('Header')
        self.parent = parent

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)
        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)

        self.mainLayout = QHBoxLayout(self)
        #self.mainLayout.setSpacing(0)

        self.preButton = QPushButton()
        #self.preButton.setIcon(QIcon("../icons/music_pre.png"))
        self.preButton.setStyleSheet(
            "QPushButton{border-image: url(icons/music_pre.png)}")
        #self.preButton.setMaximumSize(48,48)
        self.preButton.setMinimumSize(36, 36)
        self.preButton.setObjectName("preButton")
        self.mainLayout.addWidget(self.preButton)

        self.playButton = QPushButton()
        self.playButton.setStyleSheet(
            "QPushButton{border-image: url(icons/music_on.png)}")
        #self.playButton.setMaximumSize(48, 48)
        self.playButton.setMinimumSize(36, 36)
        self.playButton.setObjectName("playButton")
        self.mainLayout.addWidget(self.playButton)

        self.nextButton = QPushButton()
        self.nextButton.setStyleSheet(
            "QPushButton{border-image: url(icons/music_next.png)}")
        #self.nextButton.setMaximumSize(48, 48)
        self.nextButton.setMinimumSize(36, 36)
        self.nextButton.setObjectName("nextButton")
        self.mainLayout.addWidget(self.nextButton)

        self.currentTimeLabel = QLabel("00:00")
        self.currentTimeLabel.setMinimumSize(QSize(60, 0))
        self.currentTimeLabel.setAlignment(Qt.AlignRight | Qt.AlignTrailing
                                           | Qt.AlignVCenter)
        self.currentTimeLabel.setObjectName("currentTimeLabel")
        self.mainLayout.addWidget(self.currentTimeLabel)

        self.timeSlider = QSlider()
        self.timeSlider.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        self.timeSlider.setOrientation(Qt.Horizontal)
        self.timeSlider.setObjectName("timeSlider")
        self.mainLayout.addWidget(self.timeSlider)

        self.totalTimeLabel = QLabel("00:00")
        self.totalTimeLabel.setMinimumSize(QSize(60, 0))
        self.totalTimeLabel.setAlignment(Qt.AlignLeading | Qt.AlignLeft
                                         | Qt.AlignVCenter)
        self.totalTimeLabel.setObjectName("totalTimeLabel")
        self.mainLayout.addWidget(self.totalTimeLabel)

        self.volumeButton = QPushButton()
        self.volumeButton.setObjectName("volumeButton")
        self.mainLayout.addWidget(self.volumeButton)

        self.volumeSlider = QSlider()
        self.volumeSlider.setMinimumWidth(100)
        self.volumeSlider.setMaximumWidth(150)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setProperty("value", 5)
        self.volumeSlider.setOrientation(Qt.Horizontal)
        self.volumeSlider.setSizePolicy(QSizePolicy.Minimum,
                                        QSizePolicy.Expanding)
        self.volumeSlider.setObjectName("volumeSlider")
        self.player.setVolume(self.volumeSlider.value())
        self.mainLayout.addWidget(self.volumeSlider)

        self.musicCycleButton = QPushButton()
        self.musicCycleButton.setObjectName("musicCycle")
        self.musicCycleButton.setToolTip("音乐循环")
        self.mainLayout.addWidget(self.musicCycleButton)

        self.musicCycleButton = QPushButton("词")
        self.musicCycleButton.setObjectName("musicCycle")
        self.musicCycleButton.setToolTip("歌词")
        self.mainLayout.addWidget(self.musicCycleButton)

        self.playlistButton = QPushButton("列")
        self.playlistButton.setObjectName("playlistButton")
        self.mainLayout.addWidget(self.playlistButton)

        #self.mainLayout.addStretch(1)

        self.registerSignalConnect()

    def registerSignalConnect(self):
        self.player.error.connect(self.erroralert)

        self.preButton.pressed.connect(self.playlist.previous)
        self.playButton.pressed.connect(self.playButtonClicked)
        self.nextButton.pressed.connect(self.playlist.next)

        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)
        self.volumeSlider.valueChanged.connect(self.player.setVolume)
        #self.timeSlider.valueChanged.connect(self.player.setPosition)
        #self.timeSlider.sliderMoved.connect(self.player.setPosition)
        self.timeSlider.sliderReleased.connect(self.timeSliderReleased)
        self.timeSlider.sliderPressed.connect(self.timeSliderPressed)
        self.timeSlider.sliderMoved.connect(self.timeSliderMoved)

    def playMusic(self, qurl):
        print(qurl)
        content = QMediaContent(qurl)
        self.playlist.addMedia(content)
        self.playlist.setCurrentIndex(self.playlist.mediaCount() - 1)
        if self.player.state() != QMediaPlayer.PlayingState:
            self.player.play()
        #self.player.setMedia(content)
        #self.player.play()

    def playButtonClicked(self):
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def timeSliderPressed(self):
        """按下准备拖动时。"""
        # 将进度条自动更新取消。
        self.player.durationChanged.disconnect()
        self.player.positionChanged.disconnect()
        # 添加进度条移动事件。
        #self.slider.sliderMoved.connect(self.sliderMovedEvent)

    def timeSliderReleased(self):
        """拖动进度条的事件,用于快进快退。"""
        value = self.timeSlider.value()
        self.player.setPosition(value)

        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)

    def timeSliderMoved(self):
        self.currentTimeLabel.setText(hhmmss(self.timeSlider.value()))

    def update_duration(self, mc):
        self.timeSlider.setMaximum(self.player.duration())
        duration = self.player.duration()

        if duration >= 0:
            self.totalTimeLabel.setText(hhmmss(duration))

    def update_position(self, *args):
        position = self.player.position()
        if position >= 0:
            self.currentTimeLabel.setText(hhmmss(position))

        # Disable the events to prevent updating triggering a setPosition event (can cause stuttering).
        #self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        #self.timeSlider.blockSignals(False)

    def erroralert(self, *args):
        print(args)
Beispiel #16
0
class BF4TimerGUI(QMainWindow):
    """Class which inherits QMainWindow to produce the GUI object of the program."""
    counter = 90
    """This variable stores the default (90 seconds) OR remaining seconds in the countdown."""
    def __init__(self):
        """Sets window size, window title and calls 10 """
        super(BF4TimerGUI, self).__init__()
        self.setGeometry(0, 0, 1920, 1080)
        self.setWindowTitle("BF4 Deployment Timer")
        self.vehicle_audio_index = 0  # sets a default index value for selecting an audio video_playlist later
        print("Main Window Configuration successful")
        # Content initialization methods
        self.init_default_variable_states()
        self.init_fonts()
        self.init_video_background()
        self.init_background_music()
        self.init_background_images()
        self.init_buttons()
        self.init_sound_effects()
        self.init_vehicle_audio()
        self.init_vehicle_buttons()
        self.init_timer()
        self.init_timer_audio_lists()
        self.init_icon_dict()

    def init_default_variable_states(self):
        """Defines and sets default values for important, miscellaneous class variables."""

        self.blacktile_default_style = "border-image: url('./media/images/backgrounds/control console.png');"
        self.logo_label_default_style = "border-image: url('./media/images/backgrounds/title background.png'); " \
                                        "background-color:black; color: rgb(136, 204, 241)"
        self.timer_label_default_style = "border-image: url('./media/images/backgrounds/tile background.jpg'); color:" \
                                         "rgb(136, 204, 241) "
        self.timer_label_10sec_style = "border-image: url('./media/images/backgrounds/tile background.jpg'); color: " \
                                       "red; "
        self.timer_label_deploy_style = "border-image: url('./media/images/backgrounds/tile background.jpg'); color: " \
                                        "rgb(98, 255, 0);"

    def init_fonts(self):
        """In this method font attributes are passed to QFont Objects.

        These QFont objects are then passed to other text-based PyQt5 objects to set their font style.
        """

        self.cancel_font = QFont("Agency FB", 12)
        self.logo_font = QFont('Agency FB', 26)
        self.standard_font = QFont('Agency FB', 38)
        self.timer_display_font = QFont("Agency FB", 88)

        # CREATE VIDEO BACKGROUND

    def init_video_background(self):
        """Creates/configures the PyQt5 objects necessary to launch the video background of the application.

         A new QVideoWidget is passed to a QMediaPlayer object ( a general media playback object in PyQt5). The
         QMediaPlayer is configured as a 'VideoSurface' for video compatibility. The url to the video background is
         passed to a QMediaPlaylist set to loop. The video_playlist is then passed to the QMediaPlayer and playback
         starts.
         """

        self.video_widget = QVideoWidget()
        # QVideoWidget must be set as Central Widget to play in background - otherwise it plays in a separate window
        self.setCentralWidget(self.video_widget)

        self.video_player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.video_player.setVideoOutput(self.video_widget)

        self.video_playlist = QMediaPlaylist()
        self.video_playlist.setCurrentIndex(0)
        self.video_playlist.setPlaybackMode(QMediaPlaylist.Loop)
        self.video_playlist.addMedia(
            QMediaContent(
                QUrl.fromLocalFile('./media/video/background_video.mp4')))

        self.video_player.setPlaylist(self.video_playlist)
        self.video_player.play()

    def init_background_music(self):
        """Creates/configures the PyQt5 objects necessary to play the background music of the application.

        A url to the background music is passed to a QMediaPlaylist object set to loop. The video_playlist is passed to
        a QMediaPlayer object which sets the volume and plays the music.
        """

        self.music_file = QUrl.fromLocalFile(
            './media/audio/music/deadline.mp3')
        self.background_music_playlist = QMediaPlaylist()
        self.background_music_playlist.setPlaybackMode(QMediaPlaylist.Loop)
        self.background_music_playlist.addMedia(QMediaContent(self.music_file))

        self.background_music_player = QMediaPlayer(None,
                                                    QMediaPlayer.LowLatency)
        self.background_music_player.setPlaylist(
            self.background_music_playlist)
        self.background_music_player.setVolume(35)
        self.background_music_player.play()

    def init_background_images(self):
        """ Creates/styles the PyQt5 objects that serve as image backgrounds for various GUI widgets."""

        self.blacktile_label = QLabel(self)
        self.blacktile_label.setGeometry(QRect(1313, 0, 601, 1080))
        self.blacktile_label.setFrameShadow(QFrame.Raised)
        self.blacktile_label.setStyleSheet(self.blacktile_default_style)
        self.blacktile_label.show()

        self.logo_label = QLabel(self)
        self.logo_label.setGeometry(QRect(1400, 90, 425, 100))
        self.logo_label.setFrameShadow(QFrame.Raised)
        self.logo_label.setTextFormat(Qt.AutoText)
        self.logo_label.setAlignment(Qt.AlignCenter)
        self.logo_label.setLayoutDirection(Qt.RightToLeft)
        self.logo_label.setText('Reinforcements Available')
        self.logo_label.setFont(self.logo_font)
        self.logo_label.setStyleSheet(self.logo_label_default_style)
        self.logo_label.show()

        self.timer_label = QLabel(self)
        self.timer_label.setGeometry(QRect(1411, 720, 417, 271))
        self.timer_label.setFrameShadow(QFrame.Raised)
        self.timer_label.setStyleSheet(self.timer_label_default_style)
        self.timer_label.setFont(self.standard_font)
        self.timer_label.setTextFormat(Qt.AutoText)
        self.timer_label.setText('Awaiting Orders')
        self.timer_label.setAlignment(Qt.AlignCenter)
        self.timer_label.setLayoutDirection(Qt.RightToLeft)
        self.timer_label.show()

    def init_buttons(self):
        """Creates, styles and connects buttons on the GUI to their "on-click" functions.

        Attributes:
            self.timer_down         A down-arrow button that increments active timer by -1
            self.timer_up           An up-arrow button that increments active timer by +1
            self.cancel_button      Cancels timer and resets GUI to default state
        """

        # TIMER DOWN BUTTON
        self.timer_down = QPushButton(self)
        self.timer_down.setGeometry(QRect(1747, 938, 30, 30))
        downbutton_icon = QIcon()
        downbutton_icon.addPixmap(
            QPixmap('./media/images/controls/down arrow.png'), QIcon.Normal,
            QIcon.Off)
        self.timer_down.setIcon(downbutton_icon)
        self.timer_down.setIconSize(QSize(30, 30))
        self.timer_down.clicked.connect(self.timer_down_click)

        # TIMER UP BUTTON
        self.timer_up = QPushButton(self)
        self.timer_up.setGeometry(QRect(1777, 938, 30, 30))
        up_button_icon = QIcon()
        up_button_icon.addPixmap(
            QPixmap('./media/images/controls/up arrow.jpg'), QIcon.Normal,
            QIcon.Off)
        self.timer_up.setIcon(up_button_icon)
        self.timer_up.setIconSize(QSize(30, 30))
        self.timer_up.clicked.connect(self.up_button_click)

        # "Cancel Timer" BUTTON

        self.cancel_button = QPushButton(self)
        self.cancel_button.setFont(self.cancel_font)
        self.cancel_button.setGeometry(QRect(1396, 980, 160, 30))
        self.cancel_button.setText('Cancel Orders')
        self.cancel_button.setStyleSheet(
            'color: rgb(136, 204, 241); background-color: black;')
        self.cancel_button.hide()
        self.cancel_button.clicked.connect(self.cancel_clicked)

        # CREATE QMEDIAPLAYER OBJECTS FOR SOUND EFFECTS (menu clicks)

    def init_sound_effects(self):
        """Links sound effects to various menu button clicks."""

        # TIMER DOWN BEEP
        self.url_timeDown = QUrl.fromLocalFile(
            './media/audio/sound effects/timer down.mp3')
        self.timeDown = QMediaContent(self.url_timeDown)
        self.timeDown_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.timeDown_player.setMedia(self.timeDown)

        # TIMER UP BEEP
        self.url_timeUp = QUrl.fromLocalFile(
            './media/audio/sound effects/timer up.mp3')
        self.timeUp = QMediaContent(self.url_timeUp)
        self.timeUp_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.timeUp_player.setMedia(self.timeUp)

        # ERROR SOUND
        self.url_error = QUrl.fromLocalFile(
            './media/audio/sound effects/error sound.mp3')
        self.error = QMediaContent(self.url_error)
        self.error_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.error_player.setMedia(self.error)
        self.error_player.setVolume(18)

        # RADIO BEEP
        self.url_radio = QUrl.fromLocalFile(
            './media/audio/sound effects/double radio beep.wav')
        self.radio = QMediaContent(self.url_radio)
        self.radio_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.radio_player.setMedia(self.radio)

    def init_vehicle_audio(self):
        """Creates QMediaPlayer objects to play audio files for command center dialogue."""

        # 1. Anti-Air

        # Audio File #1
        self.AA1 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/AA/AA1.mp3'))
        self.AA1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.AA1_player.setMedia(self.AA1)

        # Audio File #2
        self.AA2 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/AA/AA2.mp3'))
        self.AA2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.AA2_player.setMedia(self.AA2)

        # Audio File #3
        self.AA3 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/AA/AA3.mp3'))
        self.AA3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.AA3_player.setMedia(self.AA3)

        # Audio File #4
        self.AA4 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/AA/AA4.mp3'))
        self.AA4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.AA4_player.setMedia(self.AA4)

        # 2. Scout Helicopter

        # Audio File #1
        self.sh1 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/scout heli/SH1.mp3'))
        self.sh1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.sh1_player.setMedia(self.sh1)

        # Audio File #2
        self.sh2 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/scout heli/SH2.mp3'))
        self.sh2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.sh2_player.setMedia(self.sh2)

        # Audio File #3
        self.sh3 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/scout heli/SH3.mp3'))
        self.sh3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.sh3_player.setMedia(self.sh3)

        # Audio File #4
        self.sh4 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/scout heli/SH4.mp3'))
        self.sh4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.sh4_player.setMedia(self.sh4)

        # 3. Attack Helicopter

        # Audio File 1
        self.ah1 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack heli/AH1.wav'))
        self.ah1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.ah1_player.setMedia(self.ah1)

        # Audio File #2
        self.ah2 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack heli/AH2.wav'))
        self.ah2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.ah2_player.setMedia(self.ah2)

        # Audio File #3
        self.ah3 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack heli/AH3.wav'))
        self.ah3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.ah3_player.setMedia(self.ah3)

        # Audio File #4
        self.ah4 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack heli/AH4.wav'))
        self.ah4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.ah4_player.setMedia(self.ah4)

        # 4. Attack Boat

        # Audio File #1
        self.b1 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack boat/B1.wav'))
        self.b1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.b1_player.setMedia(self.b1)

        # Audio File #2
        self.b2 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack boat/B2.wav'))
        self.b2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.b2_player.setMedia(self.b2)

        # Audio File #3
        self.b3 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack boat/B3.wav'))
        self.b3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.b3_player.setMedia(self.b3)

        # Audio File #4
        self.b4 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/attack boat/B4.wav'))
        self.b4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.b4_player.setMedia(self.b4)

        # 5. Tank

        # Audio File #1
        self.t1 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/tank/T1.wav'))
        self.t1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.t1_player.setMedia(self.t1)

        # Audio File #2
        self.t2 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/tank/T2.wav'))
        self.t2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.t2_player.setMedia(self.t2)

        # Audio File #3
        self.t3 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/tank/T3.wav'))
        self.t3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.t3_player.setMedia(self.t3)

        # Audio File #4
        self.t4 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/tank/T4.wav'))
        self.t4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.t4_player.setMedia(self.t4)

        # 6. LAV

        # Audio File #1
        self.lav1 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/lav/LAV1.wav'))
        self.lav1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.lav1_player.setMedia(self.lav1)

        # Audio File #2
        self.lav2 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/lav/LAV2.wav'))
        self.lav2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.lav2_player.setMedia(self.lav2)

        # Audio File #3
        self.lav3 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/lav/LAV3.wav'))
        self.lav3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.lav3_player.setMedia(self.lav3)

        # Audio File #4
        self.lav4 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/lav/LAV4.wav'))
        self.lav4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.lav4_player.setMedia(self.lav4)

        # 7. Jet

        # Audio File #1
        self.j1 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/jet/J1.wav'))
        self.j1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.j1_player.setMedia(self.j1)

        # Audio File #2
        self.j2 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/jet/J2.wav'))
        self.j2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.j2_player.setMedia(self.j2)

        # Audio File #3
        self.j3 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/jet/J3.wav'))
        self.j3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.j3_player.setMedia(self.j3)

        # Audio File #4
        self.j4 = QMediaContent(
            QUrl.fromLocalFile('./media/audio/friendly timers/jet/J4.wav'))
        self.j4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.j4_player.setMedia(self.j4)

        # 8. Fighter Bomber

        # Audio File #1
        self.fb1 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/fighter bomber/FB1.wav'))
        self.fb1_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.fb1_player.setMedia(self.fb1)

        # Audio File #2
        self.fb2 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/fighter bomber/FB2.wav'))
        self.fb2_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.fb2_player.setMedia(self.fb2)

        # Audio File #3
        self.fb3 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/fighter bomber/FB3.wav'))
        self.fb3_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.fb3_player.setMedia(self.fb3)

        # Audio File #4
        self.fb4 = QMediaContent(
            QUrl.fromLocalFile(
                './media/audio/friendly timers/fighter bomber/FB4.wav'))
        self.fb4_player = QMediaPlayer(None, QMediaPlayer.LowLatency)
        self.fb4_player.setMedia(self.fb4)

        # END OF VEHICLE AUDIO FILE UPLOADS

    def init_vehicle_buttons(self):
        """Creates, styles and connects buttons representing Battlefield 4 vehicles to their corresponding methods.

        QIcon objects containing images of each vehicle are applied to QPushButtons. There are 2 variants of QIcon for
        each vehicle - green and blue. Green is applied to the button when it has been pressed.
        """

        # 1. Anti Air Button
        self.AA_button = QPushButton(self)
        self.AA_button.setGeometry(QRect(1450, 600, 146, 89))
        self.AA_icon = QIcon()
        self.AA_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/AA blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.AA_icon_green = QIcon()
        self.AA_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/AA green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.AA_button.setIcon(self.AA_icon)
        self.AA_button.setIconSize(QSize(350, 350))
        self.AA_button.clicked.connect(self.AA_click)

        # 2. Tank Button
        self.tank_button = QPushButton(self)
        self.tank_button.setGeometry(QRect(1450, 475, 146, 89))
        self.tank_icon = QIcon()
        self.tank_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/tank blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.tank_icon_green = QIcon()
        self.tank_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/tank green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.tank_button.setIcon(self.tank_icon)
        self.tank_button.setIconSize(QSize(350, 350))
        self.tank_button.clicked.connect(self.tank_click)

        # 3. Jet Button
        self.jet_button = QPushButton(self)
        self.jet_button.setGeometry(QRect(1650, 225, 146, 89))
        self.jet_icon = QIcon()
        self.jet_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/jet blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.jet_icon_green = QIcon()
        self.jet_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/jet green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.jet_button.setIcon(self.jet_icon)
        self.jet_button.setIconSize(QSize(350, 350))
        self.jet_button.clicked.connect(self.jet_click)

        # 4. Scout Helicopter Button
        self.scout_heli_button = QPushButton(self)
        self.scout_heli_button.setGeometry(QRect(1650, 350, 146, 89))
        self.scout_heli_icon = QIcon()
        self.scout_heli_icon.addPixmap(
            QPixmap(
                './media/images/vehicle icons/blue icons/scout heli blue.png'),
            QIcon.Normal, QIcon.Off)
        self.scout_heli_icon_green = QIcon()
        self.scout_heli_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/'
                    'scout heli green.png'), QIcon.Normal, QIcon.Off)
        self.scout_heli_button.setIcon(self.scout_heli_icon)
        self.scout_heli_button.setIconSize(QSize(350, 350))
        self.scout_heli_button.clicked.connect(self.scout_helo_click)

        # 5. Attack Boat Button
        self.boat_button = QPushButton(self)
        self.boat_button.setGeometry(QRect(1650, 600, 146, 89))
        self.boat_icon = QIcon()
        self.boat_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/boat blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.boat_icon_green = QIcon()
        self.boat_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/boat green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.boat_button.setIcon(self.boat_icon)
        self.boat_button.setIconSize(QSize(350, 350))
        self.boat_button.clicked.connect(self.boat_click)

        # 6. LAV Button
        self.lav_button = QPushButton(self)
        self.lav_button.setGeometry(QRect(1650, 475, 146, 89))
        self.lav_icon = QIcon()
        self.lav_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/lav blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.lav_icon_green = QIcon()
        self.lav_icon_green.addPixmap(
            QPixmap('./media/images/vehicle icons/green icons/lav green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.lav_button.setIcon(self.lav_icon)
        self.lav_button.setIconSize(QSize(350, 350))
        self.lav_button.clicked.connect(self.lav_click)

        # 7. Attack Helicopter Button
        self.attack_helo_button = QPushButton(self)
        self.attack_helo_button.setGeometry(QRect(1450, 350, 146, 89))
        self.attack_helo_icon = QIcon()
        self.attack_helo_icon.addPixmap(
            QPixmap(
                './media/images/vehicle icons/blue icons/attack helo blue.jpg'
            ), QIcon.Normal, QIcon.Off)
        self.attack_helo_icon_green = QIcon()
        self.attack_helo_icon_green.addPixmap(
            QPixmap(
                './media/images/vehicle icons/green icons/attack helo green.jpg'
            ), QIcon.Normal, QIcon.Off)
        self.attack_helo_button.setIcon(self.attack_helo_icon)
        self.attack_helo_button.setIconSize(QSize(350, 350))
        self.attack_helo_button.clicked.connect(self.attack_helo_click)

        # 8. Fighter Bomber Button
        self.fighter_bomber_button = QPushButton(self)
        self.fighter_bomber_button.setGeometry(QRect(1450, 225, 146, 89))
        self.fighter_bomber_icon = QIcon()
        self.fighter_bomber_icon.addPixmap(
            QPixmap('./media/images/vehicle icons/blue icons/bomber blue.jpg'),
            QIcon.Normal, QIcon.Off)
        self.fighter_bomber_icon_green = QIcon()
        self.fighter_bomber_icon_green.addPixmap(
            QPixmap(
                './media/images/vehicle icons/green icons/bomber green.jpg'),
            QIcon.Normal, QIcon.Off)
        self.fighter_bomber_button.setIcon(self.fighter_bomber_icon)
        self.fighter_bomber_button.setIconSize(QSize(350, 350))
        self.fighter_bomber_button.clicked.connect(self.fighter_bomber_click)

    def init_timer(self):
        """Creates QTimer object that serves as countdown mechanism for the application.

        The connected method is called every 1 second when timer is active.
        """

        self.timer = QTimer()
        self.timer.timeout.connect(self.timer_start)

    def init_timer_audio_lists(self):
        """Creates two lists comprised of audio file objects and playlists.

        The self.timer_start and self."vehicle"_click methods reference self.vehicle_audio_playlists by index to start
        playback of audio files according to corresponding button clicks by the user. self.vehicle_audio_list is
        referenced by the self.reset_audio method to stop audio playback.
        """

        self.vehicle_audio_playlists = [
            self.aa_playlist, self.tank_playlist, self.jet_playlist,
            self.scout_helo_playlist, self.boat_playlist, self.lav_playlist,
            self.fighter_bomber_playlist, self.attack_helo_playlist
        ]

        self.vehicle_audio_list = [
            self.AA1_player, self.AA2_player, self.AA3_player, self.AA4_player,
            self.sh1_player, self.sh2_player, self.sh3_player, self.sh4_player,
            self.ah1_player, self.ah2_player, self.ah3_player, self.ah4_player,
            self.b1_player, self.b2_player, self.b3_player, self.b4_player,
            self.t1_player, self.t2_player, self.t3_player, self.t4_player,
            self.lav1_player, self.lav2_player, self.lav3_player,
            self.lav4_player, self.j1_player, self.j2_player, self.j3_player,
            self.j4_player, self.fb1_player, self.fb2_player, self.fb3_player,
            self.fb4_player
        ]

    def init_icon_dict(self):
        """Creates a dictionary linking vehicle buttons with their default blue icons.

        The self.reset_button_colors() method references the dictionary to set all vehicle icons to their default blue.
        """

        self.button_icon_dict = {
            self.fighter_bomber_button: self.fighter_bomber_icon,
            self.attack_helo_button: self.attack_helo_icon,
            self.lav_button: self.lav_icon,
            self.boat_button: self.boat_icon,
            self.scout_heli_button: self.scout_heli_icon,
            self.jet_button: self.jet_icon,
            self.tank_button: self.tank_icon,
            self.AA_button: self.AA_icon,
        }

        #                                 END OF INITIALIZATION METHODS

    #                                METHODS NEEDED FOR WIDGET FUNCTIONALITY

    def timer_down_click(self):
        """Called by when user clicks self.timer_down_button. Increments timer by -1 second."""
        BF4TimerGUI.counter -= 1
        self.timeUp_player.play()
        self.timer_label.setText(str(BF4TimerGUI.counter))

    def up_button_click(self):
        """Called by when user clicks self.timer_up_button. Increments timer by -1 second."""
        BF4TimerGUI.counter += 1
        self.timer_label.setText(str(BF4TimerGUI.counter))
        self.timeDown_player.play()

        # RESET METHODS

    def reset_timer(self):
        """Stops current timer, resets time and sets default timer background."""
        self.timer.stop()
        BF4TimerGUI.counter = 90
        self.timer_label.setStyleSheet(self.timer_label_default_style)

    def reset_button_colors(self):
        """Resets all button icons to default blue color representing an 'unclicked' button state."""
        for vehicle_button in self.button_icon_dict.keys():
            vehicle_button.setIcon(self.button_icon_dict.get(vehicle_button))

    def reset_audio(self):
        """Stops all vehicle-audio playback. state() == 1 identifies actively playing audio files."""
        for audio_file in self.vehicle_audio_list:
            if audio_file.state() == 1:
                audio_file.stop()

    def reset_process(self):
        """Combines self.reset_timer, self.reset_button_colors and self.reset_audio in a comprehensive reset process."""
        self.reset_timer()
        self.reset_button_colors()
        self.reset_audio()

        # END OF RESET METHODS

    def cancel_clicked(self):
        """Cancels/resets timer, plays click sound effect and returns GUI to default state."""
        self.error_player.play()
        self.reset_process()
        self.timer_label.setFont(self.standard_font)
        self.timer_label.setText('Awaiting Orders')
        self.cancel_button.hide()

        # VEHICLE SOUND PLAYLIST/TIMING METHODS

    def aa_playlist(self):
        """Called by self.timer_start each second during countdown and plays AA audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.AA1_player.play()
        if BF4TimerGUI.counter == 65:
            self.AA2_player.play()
        if BF4TimerGUI.counter == 31:
            self.AA3_player.play()
        if BF4TimerGUI.counter == 12:
            self.AA4_player.play()
            self.AA_button.setIcon(self.AA_icon)

    def tank_playlist(self):
        """Called by self.timer_start each second during countdown and plays Tank audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.t1_player.play()
        if BF4TimerGUI.counter == 63:
            self.t2_player.play()
        if BF4TimerGUI.counter == 32:
            self.t3_player.play()
        if BF4TimerGUI.counter == 12:
            self.t4_player.play()
        if not self.timer.isActive():
            self.tank_button.setIcon(self.tank_icon)

    def jet_playlist(self):
        """Called by self.timer_start each second during countdown and plays Jet audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.j1_player.play()
        if BF4TimerGUI.counter == 62:
            self.j2_player.play()
        if BF4TimerGUI.counter == 32:
            self.j3_player.play()
        if BF4TimerGUI.counter == 12:
            self.j4_player.play()
        if not self.timer.isActive():
            self.jet_button.setIcon(self.jet_icon)

    def scout_helo_playlist(self):
        """Called by self.timer_start each second during countdown and plays Scout Helo audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.sh1_player.play()
        if BF4TimerGUI.counter == 63:
            self.sh2_player.play()
        if BF4TimerGUI.counter == 31:
            self.sh3_player.play()
        if BF4TimerGUI.counter == 12:
            self.sh4_player.play()
        if not self.timer.isActive():
            self.scout_heli_button.setIcon(self.scout_heli_icon)

    def boat_playlist(self):
        """Called by self.timer_start each second during countdown and plays Attack Boat audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.b1_player.play()
        if BF4TimerGUI.counter == 63:
            self.b2_player.play()
        if BF4TimerGUI.counter == 31:
            self.b3_player.play()
        if BF4TimerGUI.counter == 12:
            self.b4_player.play()
        if not self.timer.isActive():
            self.boat_button.setIcon(self.boat_icon)

    def lav_playlist(self):
        """Called by self.timer_start each second during countdown and plays LAV audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.lav1_player.play()
        if BF4TimerGUI.counter == 62:
            self.lav2_player.play()
        if BF4TimerGUI.counter == 32:
            self.lav3_player.play()
        if BF4TimerGUI.counter == 11:
            self.lav4_player.play()
        if not self.timer.isActive():
            self.lav_button.setIcon(self.lav_icon)

    def fighter_bomber_playlist(self):
        """Called by self.timer_start each second during countdown and plays fighter bomber audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.fb1_player.play()
        if BF4TimerGUI.counter == 64:
            self.fb2_player.play()
        if BF4TimerGUI.counter == 31:
            self.fb3_player.play()
        if BF4TimerGUI.counter == 12:
            self.fb4_player.play()
        if not self.timer.isActive():
            self.fighter_bomber_button.setIcon(self.fighter_bomber_icon)

    def attack_helo_playlist(self):
        """Called by self.timer_start each second during countdown and plays Attack Helo audio at specified times."""
        if BF4TimerGUI.counter == 90:
            self.ah1_player.play()
        if BF4TimerGUI.counter == 63:
            self.ah2_player.play()
        if BF4TimerGUI.counter == 32:
            self.ah3_player.play()
        if BF4TimerGUI.counter == 12:
            self.ah4_player.play()
        if not self.timer.isActive():
            self.attack_helo_button.setIcon(self.attack_helo_icon)

    def timer_start(self):
        """Called by active QTimer to update timer, time-display, audio playback and GUI style elements by the second.

        While the display counts down to 0, but the QTimer runs for an additional 4 seconds during which additional
        styling/display variables are updated. The QTimer resets the GUI to it's default state upon reaching -4.
        This method references self.vehicle_audio_playlists by index to play audio for user-selected vehicle.
        """

        # Checks countdown against the selected vehicle's video_playlist method and plays audio when triggered
        self.vehicle_audio_playlists[self.vehicle_audio_index]()
        self.timer_label.setFont(self.timer_display_font)
        self.timer_label.setText(str(BF4TimerGUI.counter))
        BF4TimerGUI.counter -= 1
        self.cancel_button.show()

        if BF4TimerGUI.counter in range(10, 90):
            self.timer_label.setStyleSheet(self.timer_label_default_style)
        if BF4TimerGUI.counter in range(0, 10):
            self.timer_label.setStyleSheet(self.timer_label_10sec_style)
        if BF4TimerGUI.counter in range(-4, 0):
            self.timer_label.setFont(self.standard_font)
            self.timer_label.setStyleSheet(self.timer_label_deploy_style)
            self.timer_label.setText('Ready to Deploy')
            self.reset_button_colors()
        if BF4TimerGUI.counter == -4:
            self.reset_process()
            self.cancel_button.hide()
            self.timer_label.setText('Awaiting Orders')
            self.timer_label.setFont(self.standard_font)
            # print('process ended')

    def changing_orders(self):
        """Displays message 'changing orders' when user switches vehicle timers while another countdown is active."""
        if self.timer.isActive():
            self.timer_label.setFont(self.standard_font)
            self.timer_label.setText('Changing Orders')

    #                                       VEHICLE BUTTON CLICK METHODS

    # The following 8 "vehicle_click" methods reset the GUI (and display "Changing Orders" if a timer was already
    # active), prepare the audio files of the respective vehicle, update the vehicle icon color to green to indicate
    # it's selection, and starts the countdown.

    def AA_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.aa_playlist)
        # sets vehicle audio index to the correct video_playlist for use in self.timer_start()
        self.reset_process()
        self.radio_player.play()
        self.AA_button.setIcon(self.AA_icon_green)
        self.timer.start(1000)

    def tank_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.tank_playlist)
        self.reset_process()
        self.radio_player.play()
        self.tank_button.setIcon(self.tank_icon_green)
        self.timer.start(1000)

    def jet_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.jet_playlist)
        self.reset_process()
        self.radio_player.play()
        self.jet_button.setIcon(self.jet_icon_green)
        self.timer.start(1000)

    def scout_helo_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.scout_helo_playlist)
        self.reset_process()
        self.radio_player.play()
        self.scout_heli_button.setIcon(self.scout_heli_icon_green)
        self.timer.start(1000)

    def boat_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.boat_playlist)
        self.reset_process()
        self.radio_player.play()
        self.boat_button.setIcon(self.boat_icon_green)
        self.timer.start(1000)

    def lav_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.lav_playlist)
        self.reset_process()
        self.radio_player.play()
        self.lav_button.setIcon(self.lav_icon_green)
        self.timer.start(1000)

    def fighter_bomber_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.fighter_bomber_playlist)
        self.reset_process()
        self.radio_player.play()
        self.fighter_bomber_button.setIcon(self.fighter_bomber_icon_green)
        self.timer.start(1000)

    def attack_helo_click(self):
        self.changing_orders()
        self.vehicle_audio_index = self.vehicle_audio_playlists.index(
            self.attack_helo_playlist)
        self.reset_process()
        self.radio_player.play()
        self.attack_helo_button.setIcon(self.attack_helo_icon_green)
        self.timer.start(1000)
class Player(QMediaPlayer):
    def __init__(self, parent=None):
        super(Player, self).__init__(parent)
        self.parent = parent
        self.player = QMediaPlayer()
        self.queueList = QMediaPlaylist()
        self.player.setPlaylist(self.queueList)
        self.queueData = []
        self.position = 0
        self.volume = 100

        self.player.mediaStatusChanged.connect(self.qmp_mediaStatusChanged)
        self.player.positionChanged.connect(self.qmp_positionChanged)
        self.player.durationChanged.connect(self.durationChanged)
        self.queueList.currentIndexChanged.connect(self.playlistPosChanged)

    def add(self, data):
        """Add track to the queue"""
        queueData = {
            'pc_title': data['pc_title'],
            'title': data['title'],
            'url': data['url'],
            'date': data['date_format'],
            'description': data['description']
        }
        self.queueData.append(queueData)
        self.queueList.addMedia(QMediaContent(QUrl(data['url'])))

    def playPause(self):
        icon = QIcon.fromTheme("media-playback-pause")

        if self.player.state() == QMediaPlayer.StoppedState:
            if self.player.mediaStatus() == QMediaPlayer.NoMedia:
                if self.queueList.mediaCount() != 0:
                    self.player.play()
            elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia:
                self.queueList.setCurrentIndex(self.position)
                self.player.play()
            elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia:
                self.player.play()
        elif self.player.state() == QMediaPlayer.PlayingState:
            icon = QIcon.fromTheme("media-playback-start")
            self.player.pause()
        elif self.player.state() == QMediaPlayer.PausedState:
            self.player.play()

        self.parent.playBtn.setIcon(icon)

    def startPlay(self):
        data = self.queueData[0]
        self.queueList.setCurrentIndex(0)
        self.parent.curPCLabel.setText(data['pc_title'])
        self.parent.curTrackName.setText(data['title'])
        self.player.play()
        icon = QIcon.fromTheme("media-playback-pause")
        self.parent.playBtn.setIcon(icon)

    def stop(self):
        self.player.stop()
        icon = QIcon.fromTheme("media-playback-start")
        self.parent.playBtn.setIcon(icon)

    def setPosition(self, pos):
        self.player.setPosition(pos)

    def durationChanged(self, duration):
        total_time = '0:00:00'
        duration = self.player.duration()
        total_time = ms_to_time(duration)
        self.parent.timeSlider.setMaximum(duration)
        self.currentTrackDuration = duration
        self.parent.totalTimeLabel.setText(total_time)

    def qmp_mediaStatusChanged(self, status):
        icon = QIcon.fromTheme("media-playback-pause")
        if self.player.state() == QMediaPlayer.StoppedState:
            icon = QIcon.fromTheme("media-playback-start")
        elif self.player.state() == QMediaPlayer.PausedState:
            icon = QIcon.fromTheme("media-playback-start")

        self.parent.playBtn.setIcon(icon)

    def qmp_positionChanged(self, position, senderType=False):
        self.currentTime = position
        current_time = '0:00:00'

        if position != -1:
            current_time = ms_to_time(position)
            self.parent.timeLabel.setText(current_time)

        self.parent.timeSlider.blockSignals(True)
        self.parent.timeSlider.setValue(position)
        self.parent.timeSlider.blockSignals(False)

    def playlistPosChanged(self):
        pos = self.queueList.currentIndex()
        data = self.queueData[pos]
        self.parent.curPCLabel.setText(data['pc_title'])
        self.parent.curTrackName.setText(data['title'])
        windowTitle = '{0} - {1}'.format(data['pc_title'], data['title'])
        self.parent.setWindowTitle(windowTitle)
        if self.queueList.mediaCount() > 1:
            if pos < self.queueList.mediaCount() - 1:
                self.parent.queueNextBtn.setEnabled(True)
            else:
                self.parent.queueNextBtn.setEnabled(False)

            if pos > 0:
                self.parent.queuePrevBtn.setEnabled(True)
            else:
                self.parent.queuePrevBtn.setEnabled(False)

            if pos < self.queueList.mediaCount():
                prevPos = 0
                if self.position < pos:
                    prevPos = pos - 1
                else:
                    prevPos = pos + 1
                prevItem = self.parent.queueList.item(prevPos)
                prevWidget = self.parent.queueList.itemWidget(prevItem)
                if prevItem:
                    prevWidget.statusIcon.setPixmap(QPixmap())

        self.position = pos
        item = self.parent.queueList.item(pos)
        widget = self.parent.queueList.itemWidget(item)
        if widget:
            icon = QIcon.fromTheme("media-playback-start")
            widget.statusIcon.setPixmap(icon.pixmap(16, 16))

    def setVolume(self, volume):
        self.player.setVolume(volume)

    def rev10Secs(self):
        position = self.player.position()
        new_pos = position - 10000
        self.player.setPosition(new_pos)

    def for10Secs(self):
        position = self.player.position()
        new_pos = position + 10000
        self.player.setPosition(new_pos)

    def delete(self, position):
        """ Delete the track and her data from position"""
        self.queueData.pop(position)
        self.queueList.removeMedia(position)
        if (position == self.position):
            self.playlistPosChanged()
Beispiel #18
0
class FmvManager(QDockWidget, Ui_ManagerWindow):
    ''' Video Manager '''
    def __init__(self, iface, parent=None):
        super().__init__(parent)
        self.setupUi(self)

        self.parent = parent
        self.iface = iface
        self._PlayerDlg = None
        self.meta_reader = []
        self.initialPt = []
        self.pass_time = 250
        self.buf_interval = 2000
        self.update_interval = 2000
        self.loading = False
        self.playlist = QMediaPlaylist()
        self.VManager.viewport().installEventFilter(self)

        # Context Menu
        self.VManager.customContextMenuRequested.connect(self.__context_menu)
        self.removeAct = QAction(
            QIcon(":/imgFMV/images/mActionDeleteSelected.svg"),
            QCoreApplication.translate("ManagerDock", "Remove from list"),
            self,
            triggered=self.remove)

        self.VManager.setColumnWidth(1, 250)
        self.VManager.setColumnWidth(2, 140)
        self.VManager.setColumnWidth(3, 600)
        self.VManager.setColumnWidth(4, 600)
        self.VManager.setColumnWidth(5, 130)
        self.VManager.verticalHeader().setDefaultAlignment(Qt.AlignHCenter)
        self.VManager.hideColumn(0)

        self.videoPlayable = []
        self.videoIsStreaming = []
        self.dtm_path = parser['GENERAL']['DTM_file']
        draw.setValues()
        self.setAcceptDrops(True)

    def loadVideosFromSettings(self):

        # Get Video Manager List
        VideoList = getVideoManagerList()
        for load_id in VideoList:
            filename = s.value(getNameSpace() + "/Manager_List/" + load_id)
            _, name = os.path.split(filename)

            folder = getVideoFolder(filename)
            klv_folder = os.path.join(folder, "klv")
            exist = os.path.exists(klv_folder)

            if exist:
                self.AddFileRowToManager(name, filename, load_id, exist,
                                         klv_folder)
            else:
                if os.path.isfile(filename):
                    self.AddFileRowToManager(name, filename, load_id)

    def eventFilter(self, source, event):
        ''' Event Filter '''
        if (event.type() == QEvent.MouseButtonPress
                and source is self.VManager.viewport()
                and self.VManager.itemAt(event.pos()) is None):
            self.VManager.clearSelection()
        return QDockWidget.eventFilter(self, source, event)

    @pyqtSlot(QPoint)
    def __context_menu(self, position):
        ''' Context Menu Manager Rows '''
        if self.VManager.itemAt(position) is None:
            return
        menu = QMenu()
        menu.addAction(self.removeAct)
        menu.exec_(self.VManager.mapToGlobal(position))

    def remove(self):
        ''' Remove current row '''
        if self.loading:
            return

        # close video player (safer because it changes playlist internals)
        if self._PlayerDlg is not None:
            self._PlayerDlg.close()
        for cr in self.VManager.selectedItems():
            idx = 0
            # we browse cells but we need lines, so ignore already deleted rows
            try:
                idx = cr.row()
            except Exception:
                continue

            row_id = self.VManager.item(idx, 0).text()
            row_text = self.VManager.item(idx, 1).text()

            self.VManager.removeRow(idx)

            self.videoPlayable.pop(idx)
            self.videoIsStreaming.pop(idx)
            self.initialPt.pop(idx)

            # Remove video to Settings List
            RemoveVideoToSettings(row_id)
            # Remove folder if is local
            RemoveVideoFolder(row_text)

            if self.meta_reader[idx] is not None:
                self.meta_reader[idx].dispose()

            self.meta_reader.pop(idx)

            # remove from playlist
            self.playlist.removeMedia(idx)

    def closePlayer(self):
        ''' Close FMV '''
        try:
            self._PlayerDlg.close()
        except Exception:
            None

    def closeFMV(self):
        ''' Close FMV '''
        try:
            self._PlayerDlg.close()
        except Exception:
            None
        self.close()
        return

    def openStreamDialog(self):
        ''' Open Stream Dialog '''
        self.OpenStream = OpenStream(self.iface, parent=self)
        self.OpenStream.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
        self.OpenStream.exec_()
        return

    def openMuiltiplexorDialog(self):
        ''' Open Multiplexor Dialog '''
        self.Muiltiplexor = Multiplexor(self.iface,
                                        parent=self,
                                        Exts=ast.literal_eval(
                                            parser.get("FILES", "Exts")))
        self.Muiltiplexor.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
        self.Muiltiplexor.exec_()
        return

    def AddFileRowToManager(self,
                            name,
                            filename,
                            load_id=None,
                            islocal=False,
                            klv_folder=None):
        ''' Add file Video to new Row '''
        # We limit the number of videos due to the buffer
        self.loading = True
        if self.VManager.rowCount() > 5:
            qgsu.showUserAndLogMessage(QCoreApplication.translate(
                "ManagerDock",
                "You must delete some video from the list before adding a new one"
            ),
                                       level=QGis.Warning)
            self.loading = False
            return

        self.islocal = islocal
        self.klv_folder = klv_folder
        w = QWidget()
        layout = QVBoxLayout()
        pbar = QProgressBar()
        layout.addWidget(pbar)
        w.setLayout(layout)
        rowPosition = self.VManager.rowCount()
        self.videoPlayable.append(False)

        pbar.setGeometry(0, 0, 300, 30)
        pbar.setValue(0)
        pbar.setMaximumHeight(30)

        if load_id is None:
            row_id = 0
            if rowPosition != 0:
                row_id = int(self.VManager.item(rowPosition - 1, 0).text()) + 1
        else:
            row_id = load_id

        self.VManager.insertRow(rowPosition)

        self.VManager.setItem(rowPosition, 0, QTableWidgetItem(str(row_id)))

        self.VManager.setItem(rowPosition, 1, QTableWidgetItem(name))
        self.VManager.setItem(
            rowPosition, 2,
            QTableWidgetItem(
                QCoreApplication.translate("ManagerDock", "Loading")))
        self.VManager.setItem(rowPosition, 3, QTableWidgetItem(filename))
        self.VManager.setItem(rowPosition, 4, QTableWidgetItem("-"))
        self.VManager.setCellWidget(rowPosition, 5, w)

        self.VManager.setVisible(False)
        self.VManager.horizontalHeader().setStretchLastSection(True)
        self.VManager.setVisible(True)

        # resolve if it is a stream
        if "://" in filename:
            self.videoIsStreaming.append(True)
        else:
            self.videoIsStreaming.append(False)

        if not self.videoIsStreaming[-1]:
            # Disable row if not exist video file
            if not os.path.exists(filename):
                self.ToggleActiveRow(rowPosition, value="Missing source file")
                for j in range(self.VManager.columnCount()):
                    try:
                        self.VManager.item(rowPosition,
                                           j).setFlags(Qt.NoItemFlags
                                                       | Qt.ItemIsEnabled)
                        self.VManager.item(rowPosition, j).setBackground(
                            QColor(211, 211, 211))
                    except Exception:
                        self.VManager.cellWidget(rowPosition, j).setStyleSheet(
                            "background-color:rgb(211,211,211);")
                        pass
                self.loading = False
                return

            pbar.setValue(30)
            info = FFMpeg().probe(filename)
            if info is None:
                qgsu.showUserAndLogMessage(
                    QCoreApplication.translate("ManagerDock",
                                               "Failed loading FFMPEG ! "))

            klvIdx = getKlvStreamIndex(filename, islocal)

            # init non-blocking metadata buffered reader
            self.meta_reader.append(
                BufferedMetaReader(filename,
                                   klv_index=klvIdx,
                                   pass_time=self.pass_time,
                                   interval=self.buf_interval))

            pbar.setValue(60)
            try:
                # init point we can center the video on
                self.initialPt.append(
                    getVideoLocationInfo(filename, islocal, klv_folder))
                if not self.initialPt[rowPosition]:
                    self.VManager.setItem(
                        rowPosition, 4,
                        QTableWidgetItem(
                            QCoreApplication.translate(
                                "ManagerDock",
                                "Start location not available.")))
                    self.ToggleActiveRow(rowPosition,
                                         value="Video not applicable")
                    pbar.setValue(100)

                else:
                    self.VManager.setItem(
                        rowPosition, 4,
                        QTableWidgetItem(self.initialPt[rowPosition][2]))
                    pbar.setValue(90)
                    self.videoPlayable[rowPosition] = True
            except Exception:
                qgsu.showUserAndLogMessage(
                    QCoreApplication.translate(
                        "ManagerDock", "This video doesn't have Metadata ! "))
                pbar.setValue(100)
                self.ToggleActiveRow(rowPosition, value="Video not applicable")

        else:
            self.meta_reader.append(StreamMetaReader(filename))
            qgsu.showUserAndLogMessage("",
                                       "StreamMetaReader initialized.",
                                       onlyLog=True)
            self.initialPt.append(None)
            self.videoPlayable[rowPosition] = True

        url = ""
        if self.videoIsStreaming[-1]:
            # show video from splitter (port +1)
            oldPort = filename.split(":")[2]
            newPort = str(int(oldPort) + 10)
            proto = filename.split(":")[0]
            url = QUrl(proto + "://127.0.0.1:" + newPort)
        else:
            url = QUrl.fromLocalFile(filename)

        self.playlist.addMedia(QMediaContent(url))

        if self.videoPlayable[rowPosition]:
            pbar.setValue(100)
            if islocal:
                self.ToggleActiveRow(rowPosition, value="Ready Local")
            else:
                self.ToggleActiveRow(rowPosition, value="Ready")
            # Add video to settings list
            AddVideoToSettings(str(row_id), filename)

        self.loading = False

    def openVideoFileDialog(self):
        ''' Open video file dialog '''
        if self.loading:
            return

        Exts = ast.literal_eval(parser.get("FILES", "Exts"))

        filename, _ = askForFiles(self,
                                  QCoreApplication.translate(
                                      "ManagerDock", "Open video"),
                                  exts=Exts)

        if filename:
            if not self.isFileInPlaylist(filename):
                _, name = os.path.split(filename)
                self.AddFileRowToManager(name, filename)
            else:
                qgsu.showUserAndLogMessage(
                    QCoreApplication.translate(
                        "ManagerDock",
                        "File is already loaded in playlist: " + filename))

        return

    def isFileInPlaylist(self, filename):
        mcount = self.playlist.mediaCount()
        for x in range(mcount):
            if filename in self.playlist.media(x).canonicalUrl().toString():
                return True
        return False

    def PlayVideoFromManager(self, model):
        ''' Play video from manager dock.
            Manager row double clicked
        '''
        # Don't enable Play if video doesn't have metadata
        if not self.videoPlayable[model.row()]:
            return

        try:
            if self._PlayerDlg.isVisible():
                self._PlayerDlg.close()
        except Exception:
            None

        path = self.VManager.item(model.row(), 3).text()
        text = self.VManager.item(model.row(), 1).text()

        folder = getVideoFolder(text)
        klv_folder = os.path.join(folder, "klv")
        exist = os.path.exists(klv_folder)

        # First time we open the player
        if self._PlayerDlg is None:
            if exist:
                self.CreatePlayer(path,
                                  self.update_interval,
                                  model.row(),
                                  islocal=True,
                                  klv_folder=klv_folder)
            else:
                self.CreatePlayer(path, self.update_interval, model.row())

        self.SetupPlayer(model.row())
        if exist:
            self._PlayerDlg.playFile(path, islocal=True, klv_folder=klv_folder)
        else:
            self._PlayerDlg.playFile(path)

    def SetupPlayer(self, row):
        ''' Play video from manager dock.
            Manager row double clicked
        '''
        self.ToggleActiveRow(row)

        self.playlist.setCurrentIndex(row)

        # qgsu.CustomMessage("QGIS FMV", path, self._PlayerDlg.fileName, icon="Information")
        # if path != self._PlayerDlg.fileName:
        self._PlayerDlg.setMetaReader(self.meta_reader[row])
        self.ToggleActiveFromTitle()
        self._PlayerDlg.show()
        self._PlayerDlg.activateWindow()

        # zoom to map zone
        curAuthId = self.iface.mapCanvas().mapSettings().destinationCrs(
        ).authid()

        if self.initialPt[row][1] is not None and self.initialPt[row][
                0] is not None:
            map_pos = QgsPointXY(self.initialPt[row][1],
                                 self.initialPt[row][0])
            if curAuthId != "EPSG:4326":
                trgCode = int(curAuthId.split(":")[1])
                xform = QgsCoordinateTransform(
                    QgsCoordinateReferenceSystem(4326),
                    QgsCoordinateReferenceSystem(trgCode),
                    QgsProject().instance())
                map_pos = xform.transform(map_pos)

            self.iface.mapCanvas().setCenter(map_pos)

        self.iface.mapCanvas().zoomScale(50000)

    def CreatePlayer(self,
                     path,
                     interval,
                     row,
                     islocal=False,
                     klv_folder=None):
        ''' Create Player '''
        self._PlayerDlg = QgsFmvPlayer(self.iface,
                                       path,
                                       interval,
                                       parent=self,
                                       meta_reader=self.meta_reader[row],
                                       pass_time=self.pass_time,
                                       islocal=islocal,
                                       klv_folder=klv_folder)

        self._PlayerDlg.player.setPlaylist(self.playlist)
        self._PlayerDlg.setWindowFlags(Qt.Dialog | Qt.WindowCloseButtonHint)
        self._PlayerDlg.show()
        self._PlayerDlg.activateWindow()

    def ToggleActiveFromTitle(self):
        ''' Toggle Active video status '''
        column = 2
        for row in range(self.VManager.rowCount()):
            if self.VManager.item(row, column) is not None:
                v = self.VManager.item(row, column).text()
                text = self.VManager.item(row, 1).text()
                if v == "Playing":
                    folder = getVideoFolder(text)
                    klv_folder = os.path.join(folder, "klv")
                    exist = os.path.exists(klv_folder)
                    if exist:
                        self.ToggleActiveRow(row, value="Ready Local")
                    else:
                        self.ToggleActiveRow(row, value="Ready")
                    return

    def ToggleActiveRow(self, row, value="Playing"):
        ''' Toggle Active row manager video status '''
        self.VManager.setItem(
            row, 2,
            QTableWidgetItem(QCoreApplication.translate("ManagerDock", value)))
        return

    def closeEvent(self, _):
        ''' Close Manager Event '''
        FmvDock = qgis.utils.plugins[getNameSpace()]
        FmvDock._FMVManager = None
        try:
            if self._PlayerDlg.isVisible():
                self._PlayerDlg.close()
        except Exception:
            None
        return

    def dragEnterEvent(self, e):
        check = True
        Exts = ast.literal_eval(parser.get("FILES", "Exts"))
        if e.mimeData().hasUrls():
            for url in e.mimeData().urls():
                fileIsOk = False
                for ext in Exts:
                    if url.fileName().lower().endswith(ext):
                        fileIsOk = True
                        break
                if not fileIsOk:
                    check = False
                    break

        # Only accept if all files match a required extension
        if check:
            e.acceptProposedAction()
        # Ignore and stop propagation
        else:
            e.setDropAction(Qt.IgnoreAction)
            e.accept()

    def dropEvent(self, e):
        for url in e.mimeData().urls():
            # local files
            if "file:///" in url.toString():
                if not self.isFileInPlaylist(url.toString()[8:]):
                    self.AddFileRowToManager(url.fileName(),
                                             url.toString()[8:])
            # network drives
            else:
                if not self.isFileInPlaylist(url.toString()[5:]):
                    self.AddFileRowToManager(url.fileName(),
                                             url.toString()[5:])
Beispiel #19
0
class MusicPlayer(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.options = self.parent().options

        self.ffmpeg = self.options['paths']['ffmpeg_bin']
        self.thumbnails = self.options['paths']['thumbnails']
        self.thumb_width = self.options['thumbnail']['width']
        self.thumb_height = self.options['thumbnail']['height']

        self.jumping = False
        self.blocked = False
        self.durations = {}
        self.playback_value = 0

        self.text = ["None", "Repeat", "Random"]
        self.playlist_list = []
        self.values = [
            QMediaPlaylist.Loop, QMediaPlaylist.CurrentItemInLoop,
            QMediaPlaylist.Random
        ]

        # Thumbnail widget
        self.image_label = QLabel()

        # Control widgets
        self.playButton = QToolButton(clicked=self.play)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))

        self.stopButton = QToolButton(clicked=self.stop)
        self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.stopButton.setEnabled(False)

        self.playbackButton = QToolButton(clicked=self.playback_mode)
        self.playbackButton.setText(self.text[0])

        self.nextButton = QToolButton(clicked=self.next_song)
        self.nextButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipForward))

        self.previousButton = QToolButton(clicked=self.previous_song)
        self.previousButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipBackward))

        self.muteButton = QToolButton(clicked=self.mute_clicked)
        self.muteButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaVolume))

        self.volumeSlider = QSlider(Qt.Horizontal,
                                    sliderMoved=self.change_volume)
        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setPageStep(1)
        self.volumeSlider.setValue(50)

        # Player and playlist setup

        self.player = QMediaPlayer()
        self.player.setVolume(50)
        self.player.stateChanged.connect(self.waveform)

        self.playlist = QMediaPlaylist()
        self.playlist.setPlaybackMode(self.values[0])
        self.playlist.setCurrentIndex(1)

        self.player.setPlaylist(self.playlist)

        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))
        self.playlistView.activated.connect(self.jump)
        self.playlistView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.playlistView.customContextMenuRequested.connect(
            self.list_view_menu)
        self.playlist.currentIndexChanged.connect(
            lambda position: self.change_thumbnail(position))

        song_search = QLineEdit()
        song_search.textChanged.connect(self.search)
        song_search.setClearButtonEnabled(True)

        # Playlist
        self.playlist_name = QComboBox()
        self.playlist_name.currentTextChanged.connect(self.switch_playlist)
        self.refresh_lists()

        self.up_button = QToolButton(clicked=self.move_up)
        self.up_button.setIcon(self.style().standardIcon(QStyle.SP_ArrowUp))
        self.down_button = QToolButton(clicked=self.move_down)
        self.down_button.setIcon(self.style().standardIcon(
            QStyle.SP_ArrowDown))

        # Sound wave widget

        self.wave_graphic = WaveGraphic(self)
        #self.wave_graphic.hide()

        # Testing slider again
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)

        # Shortcuts
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self, song_search.setFocus)

        # Layouts setup

        playlist_layout = QHBoxLayout()
        playlist_layout.addWidget(self.playlist_name)
        playlist_layout.addWidget(self.up_button)
        playlist_layout.addWidget(self.down_button)

        control_layout = QHBoxLayout()
        control_layout.setContentsMargins(0, 0, 0, 0)
        control_layout.addWidget(self.stopButton)
        control_layout.addWidget(self.previousButton)
        control_layout.addWidget(self.playButton)
        control_layout.addWidget(self.nextButton)
        control_layout.addWidget(self.muteButton)
        control_layout.addWidget(self.volumeSlider)
        control_layout.addWidget(self.playbackButton)

        display_layout = QVBoxLayout()
        display_layout.addWidget(song_search)
        display_layout.addWidget(self.playlistView)
        display_layout.addLayout(playlist_layout)

        music_layout = QVBoxLayout()
        music_layout.addWidget(self.image_label)
        music_layout.addWidget(self.slider)
        music_layout.addLayout(control_layout)

        main_layout = QHBoxLayout()
        main_layout.addLayout(music_layout)
        main_layout.addLayout(display_layout)

        main_2_layout = QVBoxLayout()
        main_2_layout.addLayout(main_layout)
        main_2_layout.addWidget(self.wave_graphic)

        self.setLayout(main_2_layout)

    def waveform(self, status):
        if status == QMediaPlayer.PlayingState:
            self.wave_graphic.start()
        elif status == QMediaPlayer.PausedState:
            self.wave_graphic.pause()
        else:
            self.wave_graphic.stop()

    def list_view_menu(self, point):
        menu = QMenu("Menu", self)
        recommend_action = QAction('&Recommend Songs', self)
        menu.addAction(recommend_action)

        # TODO: [FEATURE] add rename song
        recommend_action.triggered.connect(
            lambda: self.parent().call_download_manager(self.get_links()))

        rename_action = QAction('&Rename', self)
        menu.addAction(rename_action)

        # TODO: [FEATURE] add rename song
        rename_action.triggered.connect(lambda: print("rename"))

        # Show the context menu.
        menu.exec_(self.playlistView.mapToGlobal(point))

    def get_links(self):
        title = self.playlistView.selectedIndexes()[0].data()
        link = getYoutubeURLFromSearch(title)
        if len(link) > 1:
            return youtube_recommendations(link)

    def move_up(self):
        index = self.playlistView.currentIndex().row()
        if index - 1 >= 0:
            item, above = self.playlist.media(index), self.playlist.media(
                index - 1)
            self.playlist.removeMedia(index)
            self.playlist.removeMedia(index - 1)
            self.playlist.insertMedia(index - 1, item)
            self.playlist.insertMedia(index, above)
            self.blocked = True
            self.playlistView.setCurrentIndex(
                self.playlistModel.index(index - 1, 0))
            self.blocked = False
            self.stop()

    def move_down(self):
        index = self.playlistView.currentIndex().row()
        if index + 1 <= self.playlistModel.rowCount():
            item, below = self.playlist.media(index), self.playlist.media(
                index + 1)
            self.playlist.removeMedia(index + 1)
            self.playlist.removeMedia(index)
            self.playlist.insertMedia(index, below)
            self.playlist.insertMedia(index + 1, item)
            self.blocked = True
            self.playlistView.setCurrentIndex(
                self.playlistModel.index(index + 1, 0))
            self.blocked = False
            self.stop()

    def search(self, part_of_song):
        for index in range(self.playlistModel.rowCount()):
            item = self.playlistModel.data(self.playlistModel.index(
                index, 0)).lower()
            self.playlistView.setRowHidden(index,
                                           part_of_song.lower() not in item)

    def change_thumbnail(self, position=0):

        self.playlistView.setCurrentIndex(self.playlistModel.index(
            position, 0))

        song = self.playlistView.selectedIndexes()[0].data()
        if self.wave_graphic.is_song_cached(song):
            self.wave_graphic.load_waves(song)
        else:
            wc_ = WaveConverter(song, self.wave_graphic.set_wav)
            wc_.convert()

        if self.playlistView.currentIndex().data() is None or self.blocked:
            return

        max_ratio = 0
        img = None

        for item in listdir(self.thumbnails):
            if item.endswith('.jpg'):
                ratio = similar(
                    item,
                    self.playlistView.currentIndex().data().replace(
                        '.mp3', '.jpg'))
                if ratio > max_ratio:
                    max_ratio = ratio
                    img = item

        if img:
            p = QPixmap(self.thumbnails + img)
            self.image_label.setPixmap(
                p.scaled(self.thumb_width, self.thumb_height,
                         Qt.KeepAspectRatio))

    def switch_playlist(self, current_text):
        self.playlist.clear()
        if current_text == "No Playlist":
            self.refresh()
        else:
            if read_playlist(current_text):
                songs = read_playlist(current_text).split('\n')
                for song in songs:
                    self.playlist.addMedia(
                        QMediaContent(QUrl.fromLocalFile(song)))

    def refresh(self):
        # Change it so it will go to same song.
        if self.playlist_name.currentText() != "No Playlist":
            return

        paths = fetch_options()['paths']['music_path'].split(';')

        current_songs = [
            self.playlistModel.data(self.playlistModel.index(row, 0))
            for row in range(self.playlistModel.rowCount())
        ]

        for path in paths:
            if not path:
                continue
            for item in listdir(path):
                if isfile(join(path, item)) and item.endswith(".mp3") and (
                        item not in current_songs):
                    self.playlist.addMedia(
                        QMediaContent(QUrl.fromLocalFile(join(path, item))))

    def refresh_lists(self):
        path = fetch_options()['paths']['playlist']
        self.playlist_name.clear()
        self.playlist_list = ["No Playlist"]
        self.playlist_name.addItem("No Playlist")
        for item in listdir(path):
            if isfile(join(path, item)) and item.endswith(".lst"):
                self.playlist_list.append(item.split('.')[0])
                self.playlist_name.addItem(item.split('.')[0])

    def playback_mode(self):
        # Normal -> Loop -> Random
        def up_value(value, max_value=3):
            if value + 1 == max_value:
                return 0
            return value + 1

        self.playback_value = up_value(self.playback_value)
        self.playlist.setPlaybackMode(self.values[self.playback_value])
        self.playbackButton.setText(self.text[self.playback_value])

    def jump(self, index):
        if index.isValid() and not self.blocked:
            self.playlist.setCurrentIndex(index.row())
            self.jumping = True
            self.play()

    def play(self):
        if self.blocked:
            return
        if self.player.state() != QMediaPlayer.PlayingState or self.jumping:
            self.player.play()
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
            self.jumping = False
        else:
            self.player.pause()
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))
        self.stopButton.setEnabled(True)

    def change_volume(self, value):
        self.player.setVolume(value)

    def stop(self):
        if self.player.state() != QMediaPlayer.StoppedState:
            self.player.stop()
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.stopButton.setEnabled(False)

    def next_song(self):
        self.playlist.next()
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))

    def previous_song(self):
        self.playlist.previous()
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))

    def mute_clicked(self):
        self.player.setMuted(not self.player.isMuted())
        self.muteButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaVolume if not self.player.isMuted() else QStyle.
            SP_MediaVolumeMuted))

    def durationChanged(self, duration):
        duration /= 1000
        self.slider.setMaximum(duration)

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)
class Player(QWidget):

    fullScreenChanged = pyqtSignal(bool)

    def __init__(self, playlist, parent=None, add_button = None):
        super(Player, self).__init__(parent)
        self.add_button = add_button

        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.error.connect(self.displayErrorMessage)

        self.videoWidget = VideoWidget()
        self.player.setVideoOutput(self.videoWidget)

        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(self.playlist.currentIndex(), 0))

        self.playlistView.activated.connect(self.jump)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)

        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)

        openButton = QPushButton("Open Audio/Video File", clicked=self.open)

        controls = PlayerControls()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())

        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        controls.changeRate.connect(self.player.setPlaybackRate)
        controls.stop.connect(self.videoWidget.update)

        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)


        displayLayout = QHBoxLayout()
        displayLayout.addWidget(self.videoWidget, 2)
        displayLayout.addWidget(self.playlistView)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        # button to add decoder
        if add_button:
            add_decoder_btn = QPushButton("Decode Keystrokes of Selected Media")
            add_decoder_btn.clicked.connect(add_button)            
            controlLayout.addWidget(add_decoder_btn)
        # controlLayout.addStretch(1)
        controlLayout.addWidget(controls)

        layout = QVBoxLayout()
        layout.addLayout(displayLayout)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)


        self.setLayout(layout)

        if not self.player.isAvailable():
            QMessageBox.warning(self, "Service not available",
                    "The QMediaPlayer object does not have a valid service.\n"
                    "Please check the media service plugins are installed.")

            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            openButton.setEnabled(False)

        self.metaDataChanged()

        self.addToPlaylist(playlist)

    def get_current_file(self):
        inds = self.playlistView.selectedIndexes()
        if len(inds) == 1:
            index = inds[0]
            location = self.playlistModel.m_playlist.media(index.row()).canonicalUrl()
            return location.path()
            
        

    def open(self):
        fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
        self.addToPlaylist(fileNames)

    def addToPlaylist(self, fileNames):
        for name in fileNames:
            fileInfo = QFileInfo(name)
            if fileInfo.exists():
                url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(QMediaContent(url))
            else:
                url = QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(QMediaContent(url))

    def durationChanged(self, duration):
        duration /= 1000

        self.duration = duration
        self.slider.setMaximum(duration)

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.updateDurationInfo(progress)

    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo("%s - %s" % (
                    self.player.metaData(QMediaMetaData.AlbumArtist),
                    self.player.metaData(QMediaMetaData.Title)))

    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(position, 0))

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)

    def statusChanged(self, status):
        self.handleCursor(status)

        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")

    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()

    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)

    def setTrackInfo(self, info):
        self.trackInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def setStatusInfo(self, info):
        self.statusInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())

    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60,
                    currentInfo%60, (currentInfo*1000)%1000)
            totalTime = QTime((duration/3600)%60, (duration/60)%60,
                    duration%60, (duration*1000)%1000);

            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(format)
        else:
            tStr = ""

        self.labelDuration.setText(tStr)
class AudioPlayerPage(QWidget):
    about_play_audio = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        self.audio_list_widget = QListWidget()
        self.audio_list_widget.installEventFilter(self)
        self.audio_list_widget.itemDoubleClicked.connect(self.play)

        # TODO: playlist объединить с audio_list_widget (см примеры работы с QMediaPlayer)
        self.playlist = QMediaPlaylist()
        self.playlist.currentIndexChanged.connect(
            lambda row: self.audio_list_widget.setCurrentRow(row))

        # TODO: обрабатывать сигналы плеера: http://doc.qt.io/qt-5/qmediaplayer.html#signals
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.currentMediaChanged.connect(
            lambda media: self.about_play_audio.emit(self.audio_list_widget.
                                                     currentItem().text()))

        if not self.player.isAvailable():
            # TODO: перевод
            text = "The QMediaPlayer object does not have a valid service.\n" \
                   "Please check the media service plugins are installed."

            log.warning(text)
            QMessageBox.warning(self, "Service not available", text)

            quit()

        self.controls = PlayerControls(self.player)
        self.controls.set_state(self.player.state())
        self.controls.set_volume(self.player.volume())
        self.controls.set_muted(self.controls.is_muted())

        self.controls.play_signal.connect(self.play)
        self.controls.pause_signal.connect(self.player.pause)
        self.controls.stop_signal.connect(self.player.stop)
        self.controls.next_signal.connect(self.playlist.next)
        self.controls.previous_signal.connect(self.playlist.previous)
        self.controls.change_volume_signal.connect(self.player.setVolume)
        self.controls.change_muting_signal.connect(self.player.setMuted)

        self.progress = QProgressBar()
        self.progress.hide()

        layout = QVBoxLayout()
        layout.addWidget(self.controls)
        layout.addWidget(self.audio_list_widget)
        layout.addWidget(self.progress)

        self.setLayout(layout)

        self.thread = LoadAudioListThread()
        self.thread.about_add_audio.connect(self._add_audio)
        self.thread.about_progress.connect(self.progress.setValue)
        self.thread.about_range_progress.connect(self.progress.setRange)
        self.thread.started.connect(self._start)
        self.thread.finished.connect(self._finished)

    def _add_audio(self, title, url):
        item = QListWidgetItem(title)
        item.setData(Qt.UserRole, url)
        self.audio_list_widget.addItem(item)
        self.playlist.addMedia(QMediaContent(QUrl(url)))

        # При добавлении первой аудизаписи, вызываем воспроизведение
        if self.audio_list_widget.count() == 1:
            self.audio_list_widget.setCurrentRow(0)
            self.playlist.setCurrentIndex(0)
            self.play()

    def _start(self):
        self.audio_list_widget.clear()
        self.playlist.clear()

        self.progress.show()

    def _finished(self):
        self.progress.hide()

    def fill(self, vk):
        self.thread.vk = vk

        # Если поток запущен, останавливаем его, иначе -- запускаем
        if self.thread.isRunning():
            self.thread.exit()
        else:
            self.thread.start()

    def play(self):
        if self.playlist.currentIndex() != self.audio_list_widget.currentRow():
            self.playlist.setCurrentIndex(self.audio_list_widget.currentRow())

        self.player.play()

    def eventFilter(self, obj, event):
        # Воспроизведение видео при клике на кнопки Enter/Return в плейлисте
        if obj == self.audio_list_widget and event.type(
        ) == QKeyEvent.KeyPress:
            if self.audio_list_widget.hasFocus() and event.key(
            ) == Qt.Key_Return or event.key() == Qt.Key_Enter:
                item = self.audio_list_widget.currentItem()
                if item is not None:
                    self.play()

        return super().eventFilter(obj, event)
class Window(QtWidgets.QDialog):

    def __init__(self):
        super().__init__()
        self.setGeometry(50, 50, 300, 400)
        self.setWindowTitle("Rolev Player")

# LIBRARY ROOT DIR FOLDER
        self.search_label = QtWidgets.QLabel("Select a music folder:", self)
        self.search_label.setGeometry(10, 5, 205, 10)

        self.btn_root_folder = QtWidgets.QPushButton("Browse", self)
        self.btn_root_folder.setGeometry(215, 20, 75, 25)

        # the text field of the currently selected root directory
        self.dir_text_field = QtWidgets.QLineEdit(self)
        self.dir_text_field.setGeometry(10, 20, 200, 25)

        self.btn_root_folder.clicked.connect(self.on_btn_root_folder)

# CURRENT MEDIA LABEL
        self.current_media_label = QtWidgets.QLabel("Now Playing: ", self)
        self.current_media_label.setGeometry(10, 260, 250, 15)

# CURRENT ALBUM COVER
        self.current_album_cover = QtWidgets.QLabel("Image", self)
        self.current_album_cover.setGeometry(10, 180, 75, 75)
        self.current_album_cover.setScaledContents(True)

# ARTIST DROP BOX
        self.artist_select_label = QtWidgets.QLabel("Artist", self)
        self.artist_select_label.setGeometry(10, 50, 250, 25)

        self.artist_select = QtWidgets.QComboBox(self)
        self.artist_select.setGeometry(10, 70, 250, 25)
        self.artist_select.activated[str].connect(self.on_artist_selection)

# ALBUMS DROP BOX
        self.album_select_label = QtWidgets.QLabel("Albums", self)
        self.album_select_label.setGeometry(10, 90, 250, 25)

        self.album_select = QtWidgets.QComboBox(self)
        self.album_select.setGeometry(10, 110, 250, 25)
        self.album_select.activated[str].connect(self.on_album_selection)

# SONGS DROP BOX
        self.song_select_label = QtWidgets.QLabel("Current Playlist", self)
        self.song_select_label.setGeometry(10, 130, 250, 25)

        self.song_select = QtWidgets.QComboBox(self)
        self.song_select.setGeometry(10, 150, 250, 25)
        self.song_select.activated[str].connect(self.on_song_selection)

# PLAYLIST
        self.playlist = QMediaPlaylist()
        self.playlist.currentIndexChanged.connect(self.meta_data_changed)

# MEDIA PLAYER
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.playlist().setPlaybackMode(QMediaPlaylist.Loop)
        self.player.setVolume(50)

        self.player.durationChanged.connect(self.on_dur_change)
        self.player.positionChanged.connect(self.on_pos_change)

# VOLUME SLIDER
        self.slider_volume_label = QtWidgets.QLabel("Volume", self)
        self.slider_volume_label.setGeometry(10, 345, 50, 25)

        self.slider_volume = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
        self.slider_volume.setGeometry(60, 350, 130, 20)
        self.slider_volume.setRange(0, 100)
        self.slider_volume.setValue(50)
        self.slider_volume.valueChanged.connect(self.volume_change)

# PROGRESS SLIDER
        self.slider_progress_label = QtWidgets.QLabel("Progress", self)
        self.slider_progress_label.setGeometry(10, 315, 50, 25)

        self.slider_progress = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
        self.slider_progress.setGeometry(60, 320, 130, 20)
        self.slider_progress.sliderMoved.connect(self.progress_change)

# LYRICS SEARCH
        self.btn_lyrics = QtWidgets.QPushButton("Search\n Lyrics", self)
        self.btn_lyrics.setGeometry(220, 310, 70, 80)
        self.btn_lyrics.clicked.connect(self.on_lyrics)

# ALBUM INFO SEARCH
        self.btn_album_info = QtWidgets.QPushButton(
            "Search\nAlbum\nInfo", self)
        self.btn_album_info.setGeometry(105, 180, 75, 75)
        self.btn_album_info.clicked.connect(self.on_album_info)

# ARTIST INFO SEARCH
        self.btn_artist_info = QtWidgets.QPushButton(
            "Search\nArtist\nInfo", self)
        self.btn_artist_info.setGeometry(200, 180, 75, 75)
        self.btn_artist_info.clicked.connect(self.on_artist_info)

# PREV SONG BUTTON
        self.btn_prev = QtWidgets.QPushButton("Prev", self)
        self.btn_prev.setGeometry(10, 280, 75, 25)
        self.btn_prev.clicked.connect(self.on_btn_prev)

# NEXT SONG BUTTON
        self.btn_next = QtWidgets.QPushButton("Next", self)
        self.btn_next.setGeometry(200, 280, 75, 25)
        self.btn_next.clicked.connect(self.on_btn_next)

# PLAY/PAUSE BUTTON
        self.btn_play_pause = QtWidgets.QPushButton("Play", self)
        self.btn_play_pause.setGeometry(105, 280, 75, 30)
        self.btn_play_pause.clicked.connect(self.on_btn_play_pause)

        self.show()

    def on_btn_root_folder(self):
        self.root_dir = QtWidgets.QFileDialog().getExistingDirectory()
        self.dir_text_field.setText(self.root_dir)
        self.library = LibraryLoader.load_music_from_dir(
            self.dir_text_field.text())

        self.artist_select.clear()
        self.album_select.clear()
        self.song_select.clear()
        self.playlist.clear()

        self.btn_play_pause.setText("Play")
        self.artist_select.addItem("All Artists")
        for artist in self.library:
            self.artist_select.addItem(artist)
            for album in self.library[artist]:
                self.album_select.addItem(album)
        self.load_all_songs()

    def on_artist_selection(self):
        current_artist = self.artist_select.currentText()

        self.album_select.clear()
        self.song_select.clear()
        self.playlist.clear()

        self.btn_play_pause.setText("Play")
        self.album_select.addItem("All Albums")
        if current_artist == "All Artists":
            for artist in self.library:
                for album in self.library[artist]:
                    self.album_select.addItem(album)
            self.load_all_songs()
        else:
            for album in self.library[current_artist]:
                self.album_select.addItem(album)
            self.load_all_from_artist(current_artist)

    def load_all_songs(self):
        for artist in self.library:
            for album in self.library[artist]:
                for song in self.library[artist][album]:
                    self.song_select.addItem(song[0])
                    self.playlist.addMedia(
                        QMediaContent(QtCore.QUrl.fromLocalFile(song[1])))

    def load_all_from_artist(self, artist):
        for album in self.library[artist]:
            for song in self.library[artist][album]:
                self.song_select.addItem(song[0])
                self.playlist.addMedia(
                    QMediaContent(QtCore.QUrl.fromLocalFile(song[1])))

    def on_album_selection(self):
        current_artist = self.artist_select.currentText()
        current_album = self.album_select.currentText()
        self.song_select.clear()
        self.playlist.clear()
        self.btn_play_pause.setText("Play")
        if current_album == "All Albums" and current_artist == "All Artists":
            self.load_all_songs()

        elif current_album == "All Albums":
            self.load_all_from_artist(current_artist)

        elif current_artist == "All Artists":
            for artist in self.library:
                for album in self.library[artist]:
                    if album == self.album_select.currentText():
                        for song in self.library[artist][album]:
                            self.song_select.addItem(song[0])
                            self.playlist.addMedia(
                                QMediaContent(
                                    QtCore.QUrl.fromLocalFile(song[1])))
        else:
            for song in self.library[current_artist][current_album]:
                self.song_select.addItem(song[0])
                self.playlist.addMedia(
                    QMediaContent(QtCore.QUrl.fromLocalFile(song[1])))

    def on_song_selection(self):
        index = self.song_select.currentIndex()
        self.playlist.setCurrentIndex(index)

# GETTING THE CURRENT SONG METADATA
    # Returns a SONG OBJECT and not the current song title
    # For the title of the currently playing song use get_current_title()
    def get_current_song(self):
        curr_url = self.playlist.currentMedia().canonicalUrl().toString()[8:]
        if curr_url:
            return LibraryLoader.create_song(curr_url)

    def get_current_artist(self):
        if self.get_current_song() is not None:
            return self.get_current_song().artist

    def get_current_album(self):
        if self.get_current_song() is not None:
            return self.get_current_song().album

    def get_current_path(self):
        if self.get_current_song() is not None:
            return self.get_current_song().path

    def get_current_album_path(self):
        if self.get_current_path() is not None:
            return self.get_current_path().rsplit("/", 1)[0]

    def get_current_title(self):
        if self.get_current_song() is not None:
            return self.get_current_song().name

    def on_lyrics(self):
        if self.get_current_song() is not None:
            curr_artist = self.get_current_artist()
            curr_song = self.get_current_title()

            found_lyrics = RequestLyrics.search_song_lyrics(
                curr_artist, curr_song)
            choice = QtWidgets.QMessageBox.question(
                self, "Lyrics", found_lyrics[0],
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
            if choice == QtWidgets.QMessageBox.Yes:
                webbrowser.open(found_lyrics[1])
        else:
            QtWidgets.QMessageBox.information(
                self, "Lyrics", "No lyrics found or no media is loaded!")

    def on_album_info(self):
        album = self.get_current_album()
        artist = self.get_current_artist()
        if (album is None) or (artist is None):
            print("Please, load a song first!")
        else:
            artist_info, album_info = AlbumArtwork.album_artist_info(
                artist, album)
            if album_info is not None:
                webbrowser.open(album_info)

    def on_artist_info(self):
        album = self.get_current_album()
        artist = self.get_current_artist()
        if (album is None) or (artist is None):
            print("Please, load a song first!")
        else:
            artist_info, album_info = AlbumArtwork.album_artist_info(
                artist, album)
            if artist_info is not None:
                webbrowser.open(artist_info)

    def on_btn_play_pause(self):
        if self.player.state() in (0, 2):
            self.player.play()
            if self.player.state() == 1:
                self.btn_play_pause.setText("Pause")
        else:
            self.player.pause()
            self.btn_play_pause.setText("Play")

    def on_btn_next(self):
        self.player.playlist().next()

    def on_btn_prev(self):
        self.player.playlist().previous()

    def on_dur_change(self, length):
        self.slider_progress.setMaximum(length)

    def on_pos_change(self, position):
        self.slider_progress.setValue(position)

    def volume_change(self):
        volume = self.slider_volume.value()
        self.player.setVolume(volume)

    def progress_change(self):
        position = self.slider_progress.value()
        self.player.setPosition(position)

    def meta_data_changed(self):

        now_playing = self.get_current_title()
        self.current_media_label.setText("Now Playing: " + now_playing)

        # Updating the currently playing album cover
        curr_album_path = self.get_current_album_path()
        curr_album = self.get_current_album()
        curr_artist = self.get_current_artist()
        cover_url = AlbumArtwork.album_cover(
            curr_album_path, curr_artist, curr_album)

        self.current_album_cover.setPixmap(QPixmap(cover_url))
        Scrobbler.scrobble(self.get_current_artist(), self.get_current_title())
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)
        self.threadpool = QThreadPool()
        print('Multithreading with maximum %d threads' %
              self.threadpool.maxThreadCount())

        self.player = QMediaPlayer()

        # Setup the playlist.
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        # Setup the player
        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)
        self.playlist.currentIndexChanged.connect(
            self.playlist_position_changed)
        self.player.error.connect(self.erroralert)
        self.videoWidget = QVideoWidget()
        self.player.setVideoOutput(self.videoWidget)

        self.model = PlaylistModel(self.playlist)
        self.playListView.setModel(self.model)
        selection_model = self.playListView.selectionModel()
        selection_model.selectionChanged.connect(
            self.playlist_selection_changed)

        self.currentFrame = QVideoFrame()

        # Connect control buttons/slides for media player.
        self.playButton.pressed.connect(self.player.play)
        self.pauseButton.pressed.connect(self.player.pause)
        self.stopButton.pressed.connect(self.player.stop)

        layout = QVBoxLayout()
        layout.addWidget(self.videoWidget)
        self.viewWidget.setLayout(layout)

        self.probe = QVideoProbe()
        self.probe.videoFrameProbed.connect(self.on_videoFrameProbed)
        self.probe.setSource(self.player)

        self.timeSlider.valueChanged.connect(self.player.setPosition)

        self.open_file_action.triggered.connect(self.open_file)

        # button for save current frame
        self.saveButton.pressed.connect(self.save_frame)

        self.setAcceptDrops(True)

        self.show()

    def on_videoFrameProbed(self, frame):
        self.frame = frame

    def save_frame(self):
        worker = Worker(self.frame)
        self.threadpool.start(worker)

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.acceptProposedAction()

    def dropEvent(self, e):
        for url in e.mimeData().urls():
            self.playlist.addMedia(QMediaContent(url))

        self.model.layoutChanged.emit()

        # If not playing, seeking to first of newly added + play.
        if self.player.state() != QMediaPlayer.PlayingState:
            i = self.playlist.mediaCount() - len(e.mimeData().urls())
            self.playlist.setCurrentIndex(i)
            self.player.play()

    def open_file(self):
        path, _ = QFileDialog.getOpenFileName(
            self, "Open file", "",
            "mp3 Audio (*.mp3);mp4 Video (*.mp4);Movie files (*.mov);All files (*.*)"
        )

        if path:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))

        self.model.layoutChanged.emit()

    def update_duration(self, duration):
        print("!", duration)
        print("?", self.player.duration())

        self.timeSlider.setMaximum(duration)

        if duration >= 0:
            self.totalTimeLabel.setText(hhmmss(duration))

    def update_position(self, position):
        if position >= 0:
            self.currentTimeLabel.setText(hhmmss(position))

        # Disable the events to prevent updating triggering a setPosition event (can cause stuttering).
        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        self.timeSlider.blockSignals(False)

    def playlist_selection_changed(self, ix):
        # We receive a QItemSelection from selectionChanged.
        i = ix.indexes()[0].row()
        self.playlist.setCurrentIndex(i)

    def playlist_position_changed(self, i):
        if i > -1:
            ix = self.model.index(i)
            self.playListView.setCurrentIndex(ix)
            # self.playlistView.setCurrentIndex(ix)

    def erroralert(self, *args):
        print(args)
Beispiel #24
0
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setupUI()

    def setupUI(self):
        self.playlistarr = listdir(PLAYLIST_KLASORU)
        self.setFullUI()
        self.show()
        try:
            self.setRPC()
        except:
            pass
        self.openMP3File()

    def openMP3File(self):
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist(self.player)
        for i in self.playlistarr:
            self.playlist.addMedia(
                QMediaContent(QUrl.fromLocalFile(PLAYLIST_KLASORU + "/" + i)))
        self.playlist.setCurrentIndex(0)
        self.playlist.setPlaybackMode(3)
        self.player.setPlaylist(self.playlist)
        self.player.play()
        self.buSarki = time()
        self.acik = True
        self.filename = self.playlistarr[self.playlist.currentIndex()][0:-4]
        try:
            self.updateRPC()
        except:
            pass
        self.label1.setText(self.playlistarr[self.playlist.currentIndex()])
        self.player.positionChanged.connect(self.playerValueChanged)
        self.slider.valueChanged.connect(self.sliderValueChanged)
        self.playlist.currentIndexChanged.connect(self.playlistcurrindchanged)
        tag = TinyTag.get(PLAYLIST_KLASORU + "/" +
                          self.playlistarr[self.playlist.currentIndex()])
        self.slider.setMaximum(int(self.intToMil(tag.duration)))

    def playlistcurrindchanged(self):
        print("değişti")
        self.filename = self.playlistarr[self.playlist.currentIndex()][0:-4]
        tag = TinyTag.get(PLAYLIST_KLASORU + "/" +
                          self.playlistarr[self.playlist.currentIndex()])
        self.label1.setText(self.filename)
        self.buSarki = time()
        self.slider.setMaximum(int(self.intToMil(tag.duration)))
        self.updateRPC()

    def setFullUI(self):
        self.setWindowTitle("Vagus Player v0.1")
        self.setMenuBars()
        self.label1 = QLabel("")
        self.label2 = QLabel("0:0:0")
        self.label1.setAlignment(Qt.AlignCenter)
        self.button1 = QPushButton("Durdur")
        self.button1.clicked.connect(self.durdurbaslat)
        self.button2 = QPushButton("<<")
        self.button2.clicked.connect(self.gerial)
        self.button3 = QPushButton(">>")
        self.button3.clicked.connect(self.ilerial)
        self.slider = QSlider(Qt.Horizontal)

        self.layout = QVBoxLayout()
        self.layout2 = QHBoxLayout()
        self.layout3 = QHBoxLayout()
        self.layout4 = QHBoxLayout()
        self.layout5 = QHBoxLayout()

        self.layout2.addWidget(self.label1)
        self.layout3.addWidget(self.slider)
        self.layout4.addWidget(self.label2)
        self.layout5.addWidget(self.button2)
        self.layout5.addWidget(self.button1)
        self.layout5.addWidget(self.button3)
        self.layout.addWidget(self.menubar)
        self.layout.addLayout(self.layout2)
        self.layout.addLayout(self.layout3)
        self.layout.addLayout(self.layout4)
        self.layout.addLayout(self.layout5)
        self.setLayout(self.layout)

    def setMenuBars(self):
        self.mp3Ac = QAction("MP3 Dosyası Aç", self)
        self.mp3Ac.triggered.connect(self.dosyaAc)
        self.menubar = QMenuBar()
        dosyaMenu = self.menubar.addMenu("Dosya")
        dosyaMenu.addAction(self.mp3Ac)

    def dosyaAc(self):
        self.durdurbaslat()
        self.openMP3File()

    def setRPC(self):
        self.RPC = Presence(CLIENTID)
        self.RPC.connect()

        self.RPC.update(large_image="logom",
                        large_text="Vagus Player",
                        state=f"Boşta",
                        start=time() * 1000)

    def updateRPC(self):
        if self.acik == True:
            self.RPC.update(large_image="logom",
                            large_text="Vagus Player",
                            small_image="ba_lat",
                            small_text="Dinliyor",
                            state=f"{self.filename} dinliyor",
                            start=self.buSarki * 1000)
        else:
            self.RPC.update(large_image="logom",
                            large_text="Vagus Player",
                            small_image="durdur",
                            small_text="Durdu",
                            state=f"{self.filename} dinliyor",
                            start=self.buSarki * 1000)

    def milis(self, syi):
        millis = int(syi)
        seconds = (millis / 1000) % 60
        seconds = int(seconds)
        minutes = (millis / (1000 * 60)) % 60
        minutes = int(minutes)
        return minutes, seconds

    def intToMil(self, sayi):
        return sayi * 1000

    def playerValueChanged(self):
        min, sec = self.milis(self.player.position())
        min2, sec2 = self.milis(self.slider.maximum())
        self.label2.setText(f"{min}:{sec}/{min2}:{sec2}")
        self.slider.setValue(self.player.position())
        """if min == min2 and sec == sec2:
            filename = 'test.mp3'
            fullpath = QDir.current().absoluteFilePath(filename)
            media = QUrl.fromLocalFile(fullpath)
            content = QMediaContent(media)
            self.player.setMedia(content)
            self.player.play()"""

    def sliderValueChanged(self):
        if self.slider.value() == self.intToMil(self.player.position()) / 1000:
            pass
        else:
            self.player.setPosition(self.slider.value())

    def durdurbaslat(self):
        if self.button1.text() == "Durdur":
            self.player.pause()
            self.button1.setText("Devam Et")
            self.acik = False
            self.updateRPC()
        else:
            self.player.play()
            self.button1.setText("Durdur")
            self.acik = True
            self.updateRPC()

    def gerial(self):
        if self.player.position() < 5000:
            self.player.setPosition(0)
        else:
            self.player.setPosition(self.player.position() - 5000)

    def ilerial(self):
        if ((self.slider.maximum() - self.player.position()) < 5000):
            self.player.setPosition(self.slider.maximum())
        else:
            self.player.setPosition(self.player.position() + 5000)
Beispiel #25
0
class Player(Qt.QWidget):
    """docstring for Player"""
    fullScreenChanged = Qt.pyqtSignal(bool)

    def __init__(self, playlist, parent=None):
        # create player
        super(Player, self).__init__(parent)

        self.trackInfo = ''
        self.statusInfo = ''
        self.duration = 0

        # create player object
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.name = 'Current playlist'
        self.player.setPlaylist(self.playlist)

        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)

        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        # self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)

        # connect with VideoWidget
        # self.videoWidget = VideoWidget()
        # self.player.setVideoOutput(self.videoWidget)

        # connect with PlaylistModel
        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = Qt.QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(self.playlistModel.index(
            self.playlist.currentIndex(), 0))

        # change to next song
        self.playlistView.activated.connect(self.jump)

        self.slider = Qt.QSlider(QtCore.Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)

        self.labelDuration = Qt.QLabel()
        self.slider.sliderMoved.connect(self.seek)

        # create histogram
        self.labelHistogram = Qt.QLabel()
        self.labelHistogram.setText('Histogram: ')
        self.histogram = HistogramWidget()
        histogramLayout = Qt.QHBoxLayout()
        histogramLayout.addWidget(self.labelHistogram)
        histogramLayout.addWidget(self.histogram, 1)

        # create videoProbe
        self.videoProbe = Qt.QVideoProbe()
        self.videoProbe.videoFrameProbed.connect(self.histogram.processFrame)
        self.videoProbe.setSource(self.player)

        # add control
        controls = Controllers()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())

        # connect player's controls with Controllers
        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousAction)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        # setPlaybackRate is from QMediaPlayer
        controls.changeSpeed.connect(self.player.setPlaybackRate)
        # controls.stop.connect(self.videoWidget.update)

        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)

        # create fullScreenButton
        # self.fullScreenButton = Qt.QPushButton('FullScreen')
        # self.fullScreenButton.setCheckable(True)

        # displayLayout
        displayLayout = Qt.QHBoxLayout()
        # displayLayout.addWidget(self.videoWidget, 2)
        displayLayout.addWidget(self.playlistView)

        # controlLayout
        controlLayout = Qt.QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        # connect controlLayout with controls
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        # connect controlLayout with fullScreenButton
        # controlLayout.addWidget(self.fullScreenButton)

        # visualize player
        layout = Qt.QVBoxLayout()
        layout.addLayout(displayLayout)

        # layout for sliding song playing
        hLayout = Qt.QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)

        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)
        layout.addLayout(histogramLayout)

        # set icon
        self.setWindowIcon(Qt.QIcon('favicon.ico'))

        # create menus
        toolBar = Qt.QToolBar()

        # create basic actions
        self.createActions()

        # create simple button to repeat song
        self.repeatButton = Qt.QToolButton()
        self.repeatButton.setDefaultAction(self.repeatAct)

        # create playOnceButton
        self.playOnceButton = Qt.QToolButton()
        self.playOnceButton.setDefaultAction(self.playOnceAct)
        self.playOnceButton.setEnabled(False)

        # create shuffleButton
        self.shuffleButton = Qt.QToolButton()
        self.shuffleButton.setDefaultAction(self.shuffleAct)

        # create sequentialButton
        self.sequentialButton = Qt.QToolButton()
        self.sequentialButton.setDefaultAction(self.sequentialAct)

        # create fileButton for fileMenu
        fileButton = Qt.QToolButton()
        fileButton.setText('File')
        fileButton.setPopupMode(Qt.QToolButton.MenuButtonPopup)
        fileButton.setMenu(self.popFileMenu())

        # create editButton for editMenu
        closeButton = Qt.QToolButton()
        closeButton.setText('Edit')
        closeButton.setDefaultAction(self.fileCloseAct)

        # display in toolBar these buttons
        toolBar.addWidget(self.repeatButton)
        toolBar.addWidget(self.playOnceButton)
        toolBar.addWidget(self.shuffleButton)
        toolBar.addWidget(self.sequentialButton)
        toolBar.addWidget(fileButton)
        toolBar.addWidget(closeButton)

        # add toolBar to layout of the player
        layout.addWidget(toolBar)
        layout.addWidget(Qt.QGroupBox())

        self.setWindowTitle("Python Music Player")
        self.setLayout(layout)

        if not self.player.isAvailable():
            Qt.QMessageBox(self, 'Unavailable service')
            # self.displayErrorMessage()
            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            self.fullScreenButton.setEnabled(False)

        self.metaDataChanged()

        self.addToPlaylist(playlist)

    # create fileMenu
    def popFileMenu(self):
        aMenu = Qt.QMenu(self)
        aMenu.addAction(self.fileOpenAct)
        aMenu.addAction(self.fileCloseAct)
        return aMenu

    def createActions(self):
        self.repeatAct = Qt.QAction('Repeat', self, triggered=self.repeatSong)
        self.playOnceAct = Qt.QAction(
            'Play once', self, triggered=self.playOnceSong)
        self.shuffleAct = Qt.QAction(
            'Shuffle', self, triggered=self.playlist.shuffle)
        self.sequentialAct = Qt.QAction(
            'Sequential', self, triggered=self.playSequential)
        self.fileOpenAct = Qt.QAction('Open', self, triggered=self.open)
        self.fileOpenAct.setShortcut('Ctrl+O')

        self.fileCloseAct = Qt.QAction('Close', self, triggered=self.close)
        self.fileCloseAct.setShortcut('Ctrl+Q')

    def repeatSong(self):
        self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
        self.repeatButton.setEnabled(False)
        self.playOnceButton.setEnabled(True)

    def playOnceSong(self):
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
        self.playOnceButton.setEnabled(False)
        self.repeatButton.setEnabled(True)

    # unproperly used
    def playSequential(self):
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

    # get and display song duration
    def durationChanged(self, duration):
        duration /= 1000

        self.duration = duration
        self.slider.setMaximum(duration)

    # change slider position
    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.updateDurationInfo(progress)

    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QtCore.QTime(
                (currentInfo / 3600) % 60,  # hours
                (currentInfo / 60) % 60,  # minutes
                currentInfo % 60,  # seconds
                (currentInfo * 1000) % 1000)  # miliseconds
            totalTime = QtCore.QTime(
                (duration / 3600) % 60,  # hours
                (duration / 60) % 60,  # minutes
                duration % 60,  # seconds
                (duration * 1000) % 1000)  # miliseconds
            formating = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            toString = (currentTime.toString(formating) + ' / ' +
                        totalTime.toString(formating))
        else:
            toString = ''

        self.labelDuration.setText(toString)

    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo('{0} - {1}'.format(
                self.player.metaData(Qt.QMediaMetaData.AlbumArtist),
                self.player.metaData(Qt.QMediaMetaData.Title)))

    def setTrackInfo(self, info):
        self.trackInfo = info

        if self.statusInfo:
            self.setWindowTitle('{0} | {1}'.format(
                self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(position, 0))

    def statusChanged(self, status):
        self.handleCursor(status)

        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo('Loading...')
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo('Media Stalled')
        elif status == QMediaPlayer.EndOfMedia:
            Qt.QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo('')

    def handleCursor(self, status):
        if status in [QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia,
                      QMediaPlayer.StalledMedia]:
            self.setCursor(QtCore.Qt.BusyCursor)
        else:
            self.unsetCursor()

    def setStatusInfo(self, info):
        self.statusInfo = info

        if self.statusInfo:
            self.setWindowTitle('{0} | {1}'.format(
                self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def bufferingProgress(self, progress):
        self.setStatusInfo('Buffering {0}'.format(progress))

    def displayErrorMessage(self):
        self.statusInfo(self.player.errorString())

    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)

    def previousAction(self):
        self.playlist.previous()

    def close(self):
        choice = Qt.QMessageBox.question(
            self,
            'Close',
            'Close the app?',
            Qt.QMessageBox.Yes | Qt.QMessageBox.No)

        if choice == Qt.QMessageBox.Yes:
            sys.exit()

    def open(self):
        names, _ = Qt.QFileDialog.getOpenFileNames(self, 'Open Files')
        # ['/home/milka/Documents/MusicPlayer/song.mp3']
        self.addToPlaylist(names)

    def addToPlaylist(self, names):
        for name in names:
            fileInfo = Qt.QFileInfo(name)
            if fileInfo.exists():
                url = QtCore.QUrl.fromLocalFile(fileInfo.absoluteFilePath())

                # save_to_db song url
                create_song(
                    url.path(), self.duration, playlist_name=self.name)

                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(Qt.QMediaContent(url))
            else:
                url = QtCore.QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(Qt.QMediaContent(url))
Beispiel #26
0
class MyUi(QMainWindow):
    def __init__(self, parent=None):
        # 主窗口界面
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setFixedSize(800, 600)

        self.difficulty = 3  # 难度
        self.setWindowTitle('小学算术题 难度:%d' % self.difficulty)
        self.setWindowIcon(QIcon('res/image/windowIcon.jpg'))
        self.ui.pauseBtn.setIcon(QIcon('res/image/pause.png'))

        # 设置窗口界面
        self.setting = Setting()
        self.setting._close_signal.connect(self.on_setting_closed)

        # 音效加载
        self.playlist = QMediaPlaylist()
        self.playlist.addMedia(QMediaContent(QUrl('res/audio/correct.mp3')))
        self.playlist.addMedia(QMediaContent(QUrl('res/audio/wrong.mp3')))
        self.playlist.addMedia(QMediaContent(QUrl('res/audio/complete.mp3')))
        self.playlist.addMedia(QMediaContent(QUrl('res/audio/timeOver.mp3')))
        self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemOnce)
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.play()

        # 定义变量
        self.answer = 0
        self.total = 0
        self.correct = 0
        self.accuracy = 0.
        self.overtime = 0
        self.tmpOutput = []

        # 保存路径
        self.fpath = 'history.txt'

        # 定时器初始化
        self.timeLimit = 30
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.currentTime = self.timeLimit
        self.ui.timeLabel.setText(str(self.currentTime))
        self.pause = False

        # 错题模式初始化
        self.mistakeBatchSize = 5
        self.mistakeMode = False
        self.exitingMistakeMode = False
        self.ui.tipLabel.clear()
        self.ui.remainingLabel.clear()
        self.questionQueue = []

        # 第一次开始运行
        self.refreshQuestion()
        self.refreshBoard()

        # 计时器开始计时
        self.timer.start(1000)

    # 刷新题目
    def refreshQuestion(self):
        # 清空self.tmpOutput以防刷新问题后将上一题也写入文件
        self.tmpOutput.clear()

        # 非错题模式随机出题
        if self.questionQueue == []:
            assert self.mistakeMode == False
            a = random.randint(0, 10 ** self.difficulty)
            b = random.randint(0, 10 ** self.difficulty)
            symbol, self.answer = (' + ', a + b) if random.random() > 0.5 else (' - ', a - b)

        # 错题模式从self.questionQueue中出题
        else:
            assert self.mistakeMode == True
            self.ui.remainingLabel.setText('剩余:{}/{}'.format(len(self.questionQueue), self.mistakeBatchSize))
            a, symbol, b = self.questionQueue.pop(0)
            self.answer = eval(a + symbol + b)
            self.tmpOutput.append('(*)')
            # 判断是否是最后一道错题
            if self.questionQueue == []:
                self.exitingMistakeMode = True

        # 将题目放入self.tmpOutput中等待写入文件
        self.tmpOutput.append('Question: ' + '{} {} {}:'.format(a, symbol, b))

        self.ui.questionLabel.setText(str(a) + symbol + str(b))
        self.ui.judgeLabel.setText('')
        self.ui.lineEdit.setFocus()

    # 更新记录板显示
    def refreshBoard(self):
        self.ui.correctLabel.setText('答对:%d/%d' % (self.correct, self.total))
        self.ui.accuracyLabel.setText('准确率:{:.0%}'.format(self.accuracy))
        self.ui.overtimeLabel.setText('超时次数:{}'.format(self.overtime))

    # 更新计时器时间
    def refreshTime(self):
        self.ui.timeLabel.setText(str(self.timeLimit))
        self.currentTime = self.timeLimit

    # 将self.tmpOutput中的字符串写入文件
    def writeFile(self):
        with open(self.fpath, 'a') as f:
            f.write('\t'.join(self.tmpOutput) + '\n')
        self.tmpOutput.clear()

    @pyqtSlot()
    def on_answerBtn_clicked(self):
        self.ui.lineEdit.setText(str(self.answer))

    @pyqtSlot()
    def on_refreshBtn_clicked(self):
        self.refreshQuestion()
        self.refreshTime()

    @pyqtSlot()
    def on_submitBtn_clicked(self):
        userInput = self.ui.lineEdit.text().strip()
        self.ui.lineEdit.clear()

        # 判断输入是否合法
        if re.match('^-?\d+$', userInput):
            # 若回答正确
            if eval(userInput) == self.answer:
                # 播放0号音效
                self.player.stop()
                self.playlist.setCurrentIndex(0)
                self.player.play()
                # UI响应
                self.ui.judgeLabel.setText('回答正确!')
                # 记录板更新变量,写入文件
                self.correct += 1
                self.total += 1
                self.accuracy = round(self.correct / self.total, 2)
                self.tmpOutput.append(userInput)
                self.writeFile()

                # 如果这是最后一个错题的话,有些地方要特殊处理
                if self.exitingMistakeMode == True:
                    # 修改状态
                    self.exitingMistakeMode = False
                    self.mistakeMode = False
                    # 播放2号音效
                    self.playlist.setCurrentIndex(2)
                    self.player.play()
                    # UI响应
                    self.ui.tipLabel.setText('完成错题模式!')
                    self.ui.remainingLabel.clear()

                # 更新问题,记录板显示,计时器时间
                self.refreshBoard()
                self.refreshQuestion()
                self.refreshTime()

            # 若回答错误
            else:
                # # 播放1号音效
                # self.player.stop()
                # self.playlist.setCurrentIndex(1)
                # self.player.play()

                # UI响应
                self.ui.judgeLabel.setText('回答错误!再思考一下!')
                # 记录板更新变量,不写入文件
                self.total += 1
                self.accuracy = round(self.correct / self.total, 2)
                self.tmpOutput.append('*' + userInput)

                # 更新记录板显示,计时器时间,不刷新问题
                self.refreshBoard()
                self.refreshTime()

    @pyqtSlot()
    def on_timer_timeout(self):
        self.currentTime -= 1
        # 若还有剩余时间
        if self.currentTime > 0:
            self.ui.timeLabel.setText(str(self.currentTime))
        # 若超时
        else:
            assert self.currentTime == 0
            # 播放3号音效
            self.player.stop()
            self.playlist.setCurrentIndex(3)
            self.player.play()

            # UI响应
            QMessageBox.information(self, '1', '超时了!')
            self.overtime += 1
            self.refreshTime()
            self.refreshBoard()

    @pyqtSlot()
    def on_pauseBtn_clicked(self):
        # 暂停
        if not self.pause:
            self.timer.stop()
            self.ui.pauseBtn.setIcon(QIcon('res/image/start.jpg'))
            self.pause = True
        # 取消暂停
        else:
            self.timer.start(1000)
            self.ui.pauseBtn.setIcon(QIcon('res/image/pause.png'))
            self.pause = False

    @pyqtSlot()
    def on_historyBtn_clicked(self):
        # 暂停
        if not self.pause:
            self.timer.stop()
            self.ui.pauseBtn.setIcon(QIcon('res/image/start.jpg'))
            self.pause = True

        # TODO 也许以后可以用QTableWidget美化输出
        # with open(self.fpath,'r') as f:
        #     content = f.read()

        # 用打开记事本的方法看历史记录
        os.system(self.fpath)

    @pyqtSlot()
    def on_mistakeModeBtn_clicked(self):
        # 开启错题模式
        self.mistakeMode = True
        # 更新计时器时间
        self.currentTime = self.timeLimit
        self.ui.timeLabel.setText(str(self.currentTime))

        # 读取历史记录中的错题(读取数不超过self.mistakeBatchSize个),并将其赋值给self.mistakeQueue
        with open(self.fpath, 'r') as f:
            lines = f.readlines()
        mistakeList = []
        for Question in lines:
            if '*' in Question:
                questionText = Question.split(':')[1].strip()
                assert len(questionText.split()) == 3
                mistakeList.append(questionText.split())
                if len(mistakeList) == self.mistakeBatchSize:
                    break
        assert len(mistakeList) <= self.mistakeBatchSize
        random.shuffle(mistakeList)  # 随机打乱这些错题
        self.questionQueue = mistakeList

        # UI响应
        self.ui.tipLabel.setText('正在重做错题模式')
        self.ui.lineEdit.clear()

        # 刷新问题
        self.refreshQuestion()

    @pyqtSlot()
    def on_settingBtn_clicked(self):
        # 暂停
        if not self.pause:
            self.timer.stop()
            self.ui.pauseBtn.setIcon(QIcon('res/image/start.jpg'))
            self.pause = True

        self.setting.show()

    @pyqtSlot()
    def on_setting_closed(self):
        # 将设置值赋予主窗口
        self.difficulty, self.timeLimit, self.mistakeBatchSize = \
            self.setting.difficultyValue, self.setting.timeLimitValue, self.setting.mistakeBatchSizeValue
Beispiel #27
0
class Player(QWidget):
    audio_path = "audio"
    lyrics_path = "lyrics"
    timings_path = os.path.join("lyrics", "timing")
    settings_path = "settings.json"

    fullScreenChanged = pyqtSignal(bool)

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

        self.setWindowTitle("SongScreen")

        self.setFocusPolicy(Qt.StrongFocus)

        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        # self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)

        # self.videoWidget = VideoWidget()
        # self.player.setVideoOutput(self.videoWidget)

        self.slider = MediaProgressWidget()  # QSlider(Qt.Horizontal)
        self.markers = []

        self.songtext_widget = SongTextWidget()
        self.songtext_widget.show()

        # self.playlistModel = PlaylistModel()
        # self.playlistModel.setPlaylist(self.playlist)
        #
        # self.playlistView = QListView()
        # self.playlistView.setModel(self.playlistModel)
        # self.playlistView.setCurrentIndex(
        #     self.playlistModel.index(self.playlist.currentIndex(), 0))
        #
        # self.playlistView.activated.connect(self.jump)

        self.slider.setRange(0, self.player.duration() / 1000)

        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)

        # openButton = QPushButton("Open", clicked=self.open)

        controls = PlayerControlsWidget()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        # controls.setMuted(controls.isMuted())

        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.stop_clicked)
        # controls.stop.connect(self.videoWidget.update)
        # controls.next.connect(self.playlist.next)
        # controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        # controls.changeMuting.connect(self.player.setMuted)
        # controls.changeRate.connect(self.player.setPlaybackRate)

        self.player.stateChanged.connect(controls.setState)
        self.player.stateChanged.connect(self.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        # self.player.mutedChanged.connect(controls.setMuted)

        # self.fullScreenButton = QPushButton("FullScreen")
        # self.fullScreenButton.setCheckable(True)
        #
        # self.colorButton = QPushButton("Color Options...")
        # self.colorButton.setEnabled(False)
        # self.colorButton.clicked.connect(self.showColorDialog)

        displayLayout = QHBoxLayout()
        # displayLayout.addWidget(self.videoWidget, 2)
        # displayLayout.addWidget(self.songtext_widget)
        # displayLayout.addWidget(self.playlistView)

        self.song_select_widget = SongSelectWidget()
        self.song_select_widget.song_selected.connect(self.load_song)

        self.screen_select_widget = ScreenSelectWidget()
        self.screen_select_widget.screen_selected.connect(self.display_lyrics_on_screen)
        self.screen_select_widget.active_screen = QApplication.desktop().screenNumber(self.songtext_widget)

        self.settings_button = QPushButton()
        self.settings_button.setText(self.tr("Settings..."))
        self.settings_button.clicked.connect(self.show_settings)

        sidebarLayout = QVBoxLayout()
        sidebarLayout.setContentsMargins(10, 1, 0, 1);

        sidebarLayout.addWidget(self.settings_button)
        sidebarLayout.addStretch(1);
        sidebarLayout.addWidget(self.screen_select_widget)

        displayLayout.addWidget(self.song_select_widget)
        displayLayout.addLayout(sidebarLayout)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        # controlLayout.addWidget(openButton)
        # controlLayout.addStretch(1)
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        controlLayout.addWidget(self.labelDuration)
        # controlLayout.addWidget(self.fullScreenButton)
        # controlLayout.addWidget(self.colorButton)

        layout = QVBoxLayout()
        layout.addLayout(displayLayout)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        # hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)

        self.setLayout(layout)

        if not self.player.isAvailable():
            QMessageBox.warning(self, "Service not available",
                                "The QMediaPlayer object does not have a valid service.\n"
                                "Please check the media service plugins are installed.")

            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            # openButton.setEnabled(False)
            self.colorButton.setEnabled(False)
            self.fullScreenButton.setEnabled(False)

        self.metaDataChanged()

        self._loading_audio = False
        self._finished_song = False
        self._lyrics_fading = False

        self._song_number = -1

        self.settings = {
            'font_size': 40,
            'line_increment': 2,
            'lyrics_language': '',
        }
        self._load_settings()

        self.settings_widget = SettingsWidget(self.settings, self.lyrics_path)
        self.settings_widget.font_size_changed.connect(self.songtext_widget.set_font_size)
        self.settings_widget.line_increment_changed.connect(self.songtext_widget.set_line_increment)
        self.settings_widget.language_changed.connect(self._language_changed)

        self.song_select_widget.reset(self.available_song_numbers)

    @property
    def lyrics_language_path(self):
        path = QStandardPaths.locate(QStandardPaths.AppDataLocation, self.lyrics_path, QStandardPaths.LocateDirectory)
        return os.path.join(path, self.settings['lyrics_language'])

    @property
    def available_song_numbers(self):
        audios = set(
            [int(os.path.splitext(filename)[0]) for filename in os.listdir(self.audio_path) if filename[0] != '.'])
        try:
            lyrics = set(
                [int(os.path.splitext(filename)[0])
                 for filename in os.listdir(self.lyrics_language_path)
                 if filename[0] != '.']
            )
        except (ValueError, FileNotFoundError):
            lyrics = set()

        return sorted(list(audios.intersection(lyrics)))

    def show_settings(self):
        self.settings_widget.hide()
        self.settings_widget.show()

    def display_lyrics_on_screen(self, screen_number):
        desktop = QApplication.desktop()

        if screen_number >= desktop.screenCount():
            screen_number = desktop.screenNumber(self)

        rect = desktop.availableGeometry(screen_number)

        for _ in range(3):
            if screen_number != desktop.screenNumber(self):
                self.songtext_widget.setWindowFlags(Qt.FramelessWindowHint)
                self.songtext_widget.hide()
                self.songtext_widget.move(rect.x(), rect.y())
                self.songtext_widget.resize(rect.width(), rect.height())
                self.songtext_widget.showFullScreen()
            else:
                self.songtext_widget.setWindowFlags(Qt.WindowTitleHint)
                self.songtext_widget.hide()
                self.songtext_widget.move(rect.x(), rect.y())
                self.songtext_widget.resize(self.songtext_widget.minimumSize())
                self.songtext_widget.show()

        self.screen_select_widget.active_screen = screen_number

        self.activateWindow()

    def load_song(self, song_number):
        if self._song_number == song_number:
            self.seek(0)
        else:
            if self._song_number > 0:
                self._save_timings()

            self._song_number = song_number
            self.slider.dirty = False
            self._load_audio()
            self._load_lyrics()

            # self.player.play()

    def _load_audio(self):
        filename = os.path.join(self.audio_path, "{:03}.mp3".format(self._song_number))
        self.playlist.clear()
        fileInfo = QFileInfo(filename)
        if fileInfo.exists():
            url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
            if fileInfo.suffix().lower() == 'm3u':
                self.playlist.load(url)
            else:
                self.playlist.addMedia(QMediaContent(url))
                self._loading_audio = True

            self.player.play()

    def _load_lyrics(self):
        with open(os.path.join(self.lyrics_language_path, "{}.json".format(self._song_number)), 'r') as f:
            song_markers = json.load(f)

            self.markers = []

            for m in song_markers['markers']:
                marker = MediaMarker(self.slider, m['name'])
                marker.text = m['text']
                marker.progress = 0.0
                self.markers.append(marker)

            self.songtext_widget.title = "{}  {}".format(self._song_number, song_markers['title'])
            self.songtext_widget.markers = self.markers
            self.songtext_widget.fade_in()

        try:
            with open(os.path.join(self.timings_path, "{}.json".format(self._song_number)), 'r') as f:
                timings = json.load(f)
                for m, t in zip(self.markers, timings):
                    m.progress = t
        except FileNotFoundError:
            pass

        self.slider.markers = self.markers

    def _language_changed(self, _):
        available_song_numbers = self.available_song_numbers
        self.song_select_widget.reset(available_song_numbers)
        if self._song_number in available_song_numbers:
            self._load_lyrics()

    # def open(self):
    #     fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
    #     self.addToPlaylist(fileNames)
    #
    # def addToPlaylist(self, fileNames):
    #     for name in fileNames:
    #         fileInfo = QFileInfo(name)
    #         if fileInfo.exists():
    #             url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
    #             if fileInfo.suffix().lower() == 'm3u':
    #                 self.playlist.load(url)
    #             else:
    #                 self.playlist.addMedia(QMediaContent(url))
    #         else:
    #             url = QUrl(name)
    #             if url.isValid():
    #                 self.playlist.addMedia(QMediaContent(url))

    def durationChanged(self, duration):
        duration /= 1000

        self.duration = duration
        self.slider.setMaximum(duration)

        if self._loading_audio:
            self._loading_audio = False

            line_total = 0
            for marker in self.markers:
                line_total += marker.linecount - 1

            silence_ratio = 5.0 / self.duration
            offset = 1.8 / line_total

            linecount = 0
            for marker in self.markers:
                if marker.progress == 0.0:
                    marker.progress = offset + (1 - offset) * (1 - silence_ratio) * linecount / line_total
                linecount += marker.linecount - 1

            self.player.pause()

    @property
    def _should_fade_out(self):
        return self.player.position() / 1000 >= self.duration - 5

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.updateDurationInfo(progress)

        if self.duration > 0:
            # if self.player.state() == QMediaPlayer.PlayingState:
            self.songtext_widget.progress = progress / self.duration

            if self._should_fade_out:
                self._fade_out_lyrics()

    def _fade_out_lyrics(self):
        if not self._lyrics_fading:
            self._lyrics_fading = True
            self.songtext_widget.fade_out()

    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo("%s - %s" % (
                self.player.metaData(QMediaMetaData.AlbumArtist),
                self.player.metaData(QMediaMetaData.Title)))

    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)

    def setState(self, status):

        if status == QMediaPlayer.StoppedState:
            self._finished_song = True

        elif status == QMediaPlayer.PlayingState:
            if self._finished_song or (self._lyrics_fading and not self._should_fade_out):
                self._finished_song = False
                self._lyrics_fading = False
                self.songtext_widget.fade_in()

    def stop_clicked(self):
        self.player.stop()
        self._fade_out_lyrics()

    def statusChanged(self, status):
        self.handleCursor(status)

        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")

    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()

    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)

    def videoAvailableChanged(self, available):
        if available:
            self.fullScreenButton.clicked.connect(
                self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.connect(
                self.fullScreenButton.setChecked)

            if self.fullScreenButton.isChecked():
                self.videoWidget.setFullScreen(True)
        else:
            self.fullScreenButton.clicked.disconnect(
                self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.disconnect(
                self.fullScreenButton.setChecked)

            self.videoWidget.setFullScreen(False)

        self.colorButton.setEnabled(available)

    def setTrackInfo(self, info):
        self.trackInfo = info

        # if self.statusInfo != "":
        #     self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        # else:
        #     self.setWindowTitle(self.trackInfo)

    def setStatusInfo(self, info):
        self.statusInfo = info

        # if self.statusInfo != "":
        #     self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        # else:
        #     self.setWindowTitle(self.trackInfo)

    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())

    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60,
                                currentInfo % 60, (currentInfo * 1000) % 1000)
            totalTime = QTime((duration / 3600) % 60, (duration / 60) % 60,
                              duration % 60, (duration * 1000) % 1000);

            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(format)
        else:
            tStr = ""

        self.labelDuration.setText(tStr)

    def showColorDialog(self):
        if self.colorDialog is None:
            brightnessSlider = QSlider(Qt.Horizontal)
            brightnessSlider.setRange(-100, 100)
            brightnessSlider.setValue(self.videoWidget.brightness())
            brightnessSlider.sliderMoved.connect(
                self.videoWidget.setBrightness)
            self.videoWidget.brightnessChanged.connect(
                brightnessSlider.setValue)

            contrastSlider = QSlider(Qt.Horizontal)
            contrastSlider.setRange(-100, 100)
            contrastSlider.setValue(self.videoWidget.contrast())
            contrastSlider.sliderMoved.connect(self.videoWidget.setContrast)
            self.videoWidget.contrastChanged.connect(contrastSlider.setValue)

            hueSlider = QSlider(Qt.Horizontal)
            hueSlider.setRange(-100, 100)
            hueSlider.setValue(self.videoWidget.hue())
            hueSlider.sliderMoved.connect(self.videoWidget.setHue)
            self.videoWidget.hueChanged.connect(hueSlider.setValue)

            saturationSlider = QSlider(Qt.Horizontal)
            saturationSlider.setRange(-100, 100)
            saturationSlider.setValue(self.videoWidget.saturation())
            saturationSlider.sliderMoved.connect(
                self.videoWidget.setSaturation)
            self.videoWidget.saturationChanged.connect(
                saturationSlider.setValue)

            layout = QFormLayout()
            layout.addRow("Brightness", brightnessSlider)
            layout.addRow("Contrast", contrastSlider)
            layout.addRow("Hue", hueSlider)
            layout.addRow("Saturation", saturationSlider)

            button = QPushButton("Close")
            layout.addRow(button)

            self.colorDialog = QDialog(self)
            self.colorDialog.setWindowTitle("Color Options")
            self.colorDialog.setLayout(layout)

            button.clicked.connect(self.colorDialog.close)

        self.colorDialog.show()

    def closeEvent(self, close_event):
        self._save_timings()
        self._save_settings()
        self.songtext_widget.close()
        self.settings_widget.close()

    def keyPressEvent(self, key_event):
        if key_event.key() == Qt.Key_Space:
            key_event.accept()
            if self.player.state() == QMediaPlayer.PlayingState:
                self.player.pause()
            elif self.player.state() in [QMediaPlayer.PausedState, QMediaPlayer.StoppedState]:
                self.player.play()
        elif key_event.key() == Qt.Key_M:
            key_event.accept()
            self.slider.set_closest_marker_to_current_progress()

    def _save_timings(self):
        if self.slider.dirty:
            with open(os.path.join(self.timings_path, "{}.json".format(self._song_number)), 'w') as f:
                json.dump([marker.progress for marker in self.markers], f, indent=2)

    def _save_settings(self):
        # TODO : refactor and use QSettings directly

        # with open(self.settings_path, 'w') as f:
        self.settings.update({
            'lyrics_screen': QApplication.desktop().screenNumber(self.songtext_widget),
            'control_window_position': self.pos(),
        })

        # json.dump(self.settings, f, indent=2)

        settings = QSettings("Maccesch", "SongScreen")

        for key, value in self.settings.items():
            settings.setValue(key, value)

    def _load_settings(self):
        # try:
        #     with open(self.settings_path, 'r') as f:
        #         settings = json.load(f)
        settings = QSettings("Maccesch", "SongScreen")

        if settings.contains('lyrics_screen'):
            self.display_lyrics_on_screen(settings.value('lyrics_screen'))

        if settings.contains('control_window_position'):
            self.move(settings.value('control_window_position'))

        for key in settings.allKeys():
            self.settings[key] = settings.value(key)

        # self.settings.update(settings)

        self.songtext_widget.set_font_size(self.settings['font_size'])
        self.songtext_widget.set_line_increment(self.settings['line_increment'])

        # except (FileNotFoundError, ValueError):
        #     pass

        if not os.path.exists(self.lyrics_language_path) or not self.settings['lyrics_language']:
            languages = list(
                filter(lambda p: os.path.isdir(os.path.join(self.lyrics_path, p)) and p != "timings",
                       os.listdir(self.lyrics_path))
            )
            self.settings['lyrics_language'] = languages[0] if languages else ""
Beispiel #28
0
class App(QMainWindow):

    def __init__(self):
        super().__init__()
        self.player = QMediaPlayer() # 播放器
        self.playlist = QMediaPlaylist() # 播放列表
        self.title = '音乐播放器'
        self.volumeHint = QLabel('音量: 99%')
        self.mInfo = {
            'cover': './default_cover.jpg', 
            'music': '', 
            'singer': '',
            'duration': 0
        }
        self.aboutWin = AboutWindow()
        self.cover = QLabel()
        self.listWid = QListWidget()

        # 设置主窗口位置
        self.left = 200
        self.top = 100
        self.width = 500
        self.height = 430

        self.font = QFont('SansSerif', 10.5)
        self.color = 1  # 0 - 黑色界面, 1 - 白色界面
        self.userAction = 0  # 0 - 停止中, 1 - 播放中 2 - 暂停中
        self.initUI()

    def initUI(self):
        # 添加文件菜单
        menubar = self.menuBar()
        menubar.setNativeMenuBar(False) # 不使用本地菜单栏以获得全平台统一的效果
        filemenu = menubar.addMenu('文件')
        windowmenu = menubar.addMenu('窗口')

        fileAct = QAction('打开文件', self)
        folderAct = QAction('打开文件夹', self)
        themeAct = QAction('切换[亮/暗]主题', self)
        aboutAct = QAction('关于', self)

        fileAct.setShortcut('Ctrl+O')
        folderAct.setShortcut('Ctrl+D')
        themeAct.setShortcut('Ctrl+T')
        aboutAct.setShortcut('Ctrl+H')

        filemenu.addAction(fileAct)
        filemenu.addAction(folderAct)
        windowmenu.addAction(themeAct)
        windowmenu.addAction(aboutAct)

        fileAct.triggered.connect(self.openFile)
        folderAct.triggered.connect(self.addFiles)
        themeAct.triggered.connect(self.toggleColors)
        aboutAct.triggered.connect(self.viewAbout)
        self.listWid.itemDoubleClicked.connect(self.quickplayhandler)

        self.listWid.setFont(self.font)
        self.playlist.setPlaybackMode(2)
        self.setLayout()
        self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint) # 禁用窗口最大化按钮
        self.setFont(self.font)
        self.setWindowTitle(self.title)
        self.setWindowIcon(QIcon('icon.ico'))
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setFixedSize(self.width, self.height)
        self.toggleColors()
        self.show()

    def setLayout(self):
        wid = QWidget(self)
        self.setCentralWidget(wid)

        # 添加音量控制
        volumeslider = QSlider(Qt.Horizontal, self)
        volumeslider.setFocusPolicy(Qt.NoFocus)
        volumeslider.valueChanged[int].connect(self.changeVolume)
        volumeslider.setValue(100)

        # 添加歌曲播放控制
        playBtn = QPushButton('播放')  # 播放
        pauseBtn = QPushButton('暂停')  # 暂停
        stopBtn = QPushButton('清空列表')  # 停止
        prevBtn = QPushButton('上一首') # 上一首
        playback = QComboBox() # 回放模式
        nextBtn = QPushButton('下一首') # 下一首

        playback.addItem('      单曲播放')
        playback.addItem('      单曲循环')
        playback.addItem('      列表播放')
        playback.addItem('      列表循环')
        playback.addItem('      列表随机')

        playback.setCurrentIndex(2)

        # 添加封面
        jpg = QPixmap(self.mInfo['cover']).scaled(300, 300)
        self.cover.setPixmap(jpg)

        # 添加布局
        Area = QVBoxLayout()  # centralWidget
        controls = QHBoxLayout()
        showLayout = QHBoxLayout()
        playlistCtrlLayout = QHBoxLayout()

        # 歌曲播放控制布局
        controls.addWidget(playBtn)
        controls.addWidget(pauseBtn)
        controls.addWidget(stopBtn)

        # 播放列表控制布局
        playlistCtrlLayout.addWidget(prevBtn)
        playlistCtrlLayout.addWidget(playback)
        playlistCtrlLayout.addWidget(nextBtn)

        # 显示布局
        showLayout.addWidget(self.cover)
        showLayout.addWidget(self.listWid)

        # 竖直排列
        Area.addStretch(1)
        Area.addLayout(showLayout)
        Area.addWidget(self.volumeHint)
        Area.addWidget(volumeslider)
        Area.addLayout(controls)
        Area.addLayout(playlistCtrlLayout)
        wid.setLayout(Area)

        # 事件绑定
        playBtn.clicked.connect(self.playhandler)
        pauseBtn.clicked.connect(self.pausehandler)
        playback.currentIndexChanged.connect(self.playbackhandler)
        stopBtn.clicked.connect(self.stophandler)

        prevBtn.clicked.connect(self.prevSong)
        nextBtn.clicked.connect(self.nextSong)

        self.statusBar().showMessage('文件-打开文件(夹)-选择-开始播放')
        self.playlist.currentMediaChanged.connect(self.songChanged)

    def openFile(self):
        print("点击了文件按钮")
        song = QFileDialog.getOpenFileName(self, "打开音频", "github-lkxed", "音频文件 (*.mp3 *.ogg *.wav *.m4a)")

        if song[0] != '':
            url = QUrl.fromLocalFile(song[0])
            if self.playlist.mediaCount() == 0:
                self.playlist.addMedia(QMediaContent(url))
                self.player.setPlaylist(self.playlist)
                self.player.play()
                self.userAction = 1
                self.listWid.addItem(song[0].split('/')[-1].split('.')[0])
                print(self.playlist.mediaCount())
            else:
                self.playlist.addMedia(QMediaContent(url))
                print(self.playlist.mediaCount())

    def addFiles(self):
        print("点击了文件夹按钮")
        if self.playlist.mediaCount() != 0:
            self.folderIterator()
            print(self.playlist.mediaCount())
        else:
            self.folderIterator()
            self.player.setPlaylist(self.playlist)
            self.player.playlist().setCurrentIndex(0)
            self.player.play()
            print(self.playlist.mediaCount())
            self.userAction = 1
    
    def folderIterator(self):
        folderChosen = QFileDialog.getExistingDirectory(self, '打开音频文件夹', '.')
        if folderChosen != None:
            it = QDirIterator(folderChosen)
            it.next()
            while it.hasNext():
                if it.fileInfo().isDir() == False and it.filePath() != '.':
                    fInfo = it.fileInfo()
                    print(it.filePath(), fInfo.suffix())
                    if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'):
                        print('added file', fInfo.fileName())
                        self.listWid.addItem(fInfo.fileName())
                        self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath())))
                it.next()
            if it.fileInfo().isDir() == False and it.filePath() != '.':
                fInfo = it.fileInfo()
                print(it.filePath(), fInfo.suffix())
                if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'):
                    print('added file', fInfo.fileName())
                    self.listWid.addItem(fInfo.fileName())
                    self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath())))

            # 设置ListItem高度
            for x in range(self.listWid.count()):
                self.listWid.item(x).setSizeHint(QSize(100, 30))

    # 处理双击播放事件
    def quickplayhandler(self, item):
        # 若播放列表没有音频了就跳出打开文件对话框
        if self.playlist.mediaCount() == 0:
            self.openFile()
        # 若播放列表不为空则播放
        elif self.playlist.mediaCount() != 0:
            index = self.listWid.currentRow()
            self.player.playlist().setCurrentIndex(index)
            self.player.play()
            self.userAction = 1

    # 处理按钮播放事件
    def playhandler(self):
        if self.userAction == 2:
            self.player.play()
        elif self.userAction == 0:
            # 若播放列表没有音频了就跳出打开文件对话框
            if self.playlist.mediaCount() == 0:
                self.openFile()
            # 若播放列表不为空则播放
            elif self.playlist.mediaCount() != 0:
                index = self.listWid.currentRow()
                self.player.playlist().setCurrentIndex(index)
                self.player.play()
                self.userAction = 1
        else:
            self.statusBar().showMessage('已经在播放中!')

    # 处理暂停事件
    def pausehandler(self):
        self.userAction = 2
        self.player.pause()

    # 处理清空列表事件
    def stophandler(self):
        self.userAction = 0
        self.player.stop()
        self.playlist.clear()
        self.listWid.clear()
        self.mInfo['cover'] = 'default_cover.jpg'
        jpg = QPixmap(self.mInfo['cover']).scaled(300, 300)
        self.cover.setPixmap(jpg)
        print("Playlist cleared!")
        self.statusBar().showMessage("列表已清空")

    def changeVolume(self, value):
        text = '音量: ' + str(value) + '%'
        self.volumeHint.setText(text)
        self.player.setVolume(value)

    # 上一首事件
    def prevSong(self):
        if self.playlist.currentIndex() == 0:
            self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
        else:
            self.player.playlist().previous()
    
    # 随机播放事件
    def playbackhandler(self, index):
        self.playlist.setPlaybackMode(index)
        print(self.playlist.playbackMode())

    # 下一首事件
    def nextSong(self):
        if self.playlist.mediaCount() == self.playlist.currentIndex()+1:
            self.playlist.setCurrentIndex(0)
        else:
            self.player.playlist().next()
    
    # 音频切换事件
    def songChanged(self, media):
        if not media.isNull():
            url = media.canonicalUrl()
            self.showInfo(url)
            self.statusBar().showMessage(url.fileName())
            index = self.player.playlist().currentIndex()
            self.listWid.setCurrentRow(index)

    def showInfo(self, url):
        filepath = url.path()[1:]
        filename = url.fileName()[:-4]
        print(filename)
        if filepath[-3:] == 'm4a':
            file = mutagen.MP4(filepath)
            try:
                img = file.tags['covr'][0]
                self.mInfo['cover'] = './cover/'+filename+'.jpg'
                if not os.path.exists('./cover'):
                    os.mkdir('./cover')
                if not os.path.exists(self.mInfo['cover']):
                    with open(self.mInfo['cover'], 'wb') as f:
                        f.write(img)
            except:
                print('找不到封面')
                self.mInfo['cover'] = './default_cover.jpg'

        elif filepath[-3:] == 'mp3':
            file = mutagen.File(filepath)
            try:
                img = file.tags['APIC:'].data
                self.mInfo['cover'] = './cover/'+filename+'.jpg'
                if not os.path.exists('./cover'):
                    os.mkdir('./cover')
                if not os.path.exists(self.mInfo['cover']):
                    with open(self.mInfo['cover'], 'wb') as f:
                        f.write(img)
            except:
                print('找不到封面')
                self.mInfo['cover'] = './default_cover.jpg'
        else:
            print('音频文件不支持提取封面')
            self.mInfo['cover'] = './default_cover.jpg'

        jpg = QPixmap(self.mInfo['cover']).scaled(300, 300)
        self.cover.setPixmap(jpg)


    # 主题切换事件
    def toggleColors(self):

        app.setStyle("Fusion")
        palette = QPalette()

        # 明亮主题
        if self.color == 0:
            palette.setColor(QPalette.Window, QColor(53, 53, 53))
            palette.setColor(QPalette.WindowText, Qt.white)
            palette.setColor(QPalette.Base, QColor(25, 25, 25))
            palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
            palette.setColor(QPalette.ToolTipBase, Qt.white)
            palette.setColor(QPalette.ToolTipText, Qt.white)
            palette.setColor(QPalette.Text, Qt.white)
            palette.setColor(QPalette.Button, QColor(53, 53, 53))
            palette.setColor(QPalette.ButtonText, Qt.white)
            palette.setColor(QPalette.BrightText, Qt.red)
            palette.setColor(QPalette.Link, QColor(235, 101, 54))
            palette.setColor(QPalette.Highlight, QColor(235, 101, 54))
            palette.setColor(QPalette.HighlightedText, Qt.black)
            app.setPalette(palette)
            self.color = 1

        # 黑暗主题
        elif self.color == 1:
            palette.setColor(QPalette.Window, Qt.white)
            palette.setColor(QPalette.WindowText, Qt.black)
            palette.setColor(QPalette.Base, QColor(240, 240, 240))
            palette.setColor(QPalette.AlternateBase, Qt.white)
            palette.setColor(QPalette.ToolTipBase, Qt.white)
            palette.setColor(QPalette.ToolTipText, Qt.white)
            palette.setColor(QPalette.Text, Qt.black)
            palette.setColor(QPalette.Button, Qt.white)
            palette.setColor(QPalette.ButtonText, Qt.black)
            palette.setColor(QPalette.BrightText, Qt.red)
            palette.setColor(QPalette.Link, QColor(66, 155, 248))
            palette.setColor(QPalette.Highlight, QColor(66, 155, 248))
            palette.setColor(QPalette.HighlightedText, Qt.black)
            app.setPalette(palette)
            self.color = 0

    def viewAbout(self):
        self.aboutWin.show()
class Start(QMainWindow):
    def __init__(self):
        super(Start, self).__init__()
        self.titles = "Media Player"
        self.left = 500
        self.top = 300
        self.width = 400
        self.height = 200
        self.window_main()
        self.adding_menus()

    def openMultipleFile(self):
        dialogs = QFileDialog(self)
        self.fnames, _ = dialogs.getOpenFileNames(
            self, 'Open Media Files', QDir.homePath(),
            "Videos (*.mp4 *.mkv *.3pg)")
        if self.fnames != '':
            self.playlist = QMediaPlaylist(self)
            self.fnamelist = []
            for playlst in self.fnames:
                self.fnamelist.append(
                    QMediaContent(QUrl.fromLocalFile(playlst)))
            self.playlist.addMedia(self.fnamelist)
            self.playlist.setCurrentIndex(1)
            self.videoWidget = QVideoWidget(self)

            self.mediaPlayer.setVideoOutput(self.videoWidget)
            #        self.videoWidget.setAspectRatioMode(60, 60,Qt.KeepAspectRatioByExpanding)

            self.mediaPlayer.setPlaylist(self.playlist)
            self.playlist.currentIndexChanged.connect(self.mediaNameChange)
            self.mediaPlayer.play()
            self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
            self.play.setEnabled(True)
            self.stop.setEnabled(True)
            self.loop.setEnabled(True)
            if (len(self.fnamelist) > 1):
                self.forw.setEnabled(True)
                self.shuffl.setEnabled(True)
            self.l1.setText("00:00")
            mediaName = self.fnames[0].rsplit('/', 1)[-1]
            self.fulltitle = mediaName + " - " + self.titles
            self.setWindowTitle(self.fulltitle)
            self.mediaPlayer.durationChanged.connect(self.sliderDuration)

    def openFile(self):
        self.fname, _ = QFileDialog.getOpenFileName(
            self, 'Open Media Files', QDir.homePath(),
            "Videos (*.mp4 *.mkv *.3pg)")

        if self.fname != '':
            mediaName = self.fname.rsplit('/', 1)[-1]
            self.fulltitle = mediaName + " - " + self.titles
            self.setWindowTitle(self.fulltitle)
            self.playlist = QMediaPlaylist(self)
            self.playlist.addMedia(
                QMediaContent(QUrl.fromLocalFile(self.fname)))
            self.playlist.setCurrentIndex(1)
            self.mediaPlayer.setPlaylist(self.playlist)
            self.playlist.currentIndexChanged.connect(self.mediaNameChange)
            self.mediaPlayer.play()
            self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
            self.play.setEnabled(True)
            self.stop.setEnabled(True)
            self.loop.setEnabled(True)
            self.l1.setText("00:00")
            self.mediaPlayer.durationChanged.connect(self.sliderDuration)

    def window_main(self):
        self.setWindowTitle(self.titles)
        qw = QWidget()
        self.setGeometry(self.left, self.top, qw.maximumWidth(),
                         qw.maximumHeight())
        self.setMinimumSize(540, 0)
        self.setWindowIcon(QIcon("mediaplayer.png"))
        self.video()
        self.show()

    def sliderChanged(self, position):
        pos = position * 1000
        self.mediaPlayer.setPosition(pos)
        self.slider.setValue(position)

    def adding_menus(self):
        menu = Allmenu(self)

    def volumeChange(self, vol):
        self.mediaPlayer.setVolume(vol)

    def sliderDuration(self, duratn):
        milisec = self.mediaPlayer.duration()
        sec = int(milisec / 1000)
        hour = int(sec / 3600)
        min = int((sec / 60) - (hour * 60))
        secs = int(sec - (min * 60) - (hour * 60 * 60))
        self.l2.setText(str(hour) + ":" + str(min) + ":" + str(secs))
        self.slider.setMaximum(sec)

    def sliderDuration2(self, duratn):
        second = int(duratn / 1000)
        self.slider.setValue(second)
        hour = int(second / 3600)
        min = int((second / 60) - (hour * 60))
        secs = int(second - (min * 60) - (hour * 60 * 60))
        if (min < 10):
            min = "0" + str(min)
        else:
            min = str(min)

        if (secs < 10):
            secs = "0" + str(secs)
        else:
            secs = str(secs)

        if (hour == 0):
            self.l1.setText(min + ":" + secs)
        else:
            self.l1.setText(str(hour) + ":" + min + ":" + secs)

    def mediaNameChange(self, index):
        mediaName = self.fnames[index].rsplit('/', 1)[-1]
        self.fulltitle = mediaName + " - " + self.titles
        self.setWindowTitle(self.fulltitle)
        if (self.playlist.playbackMode() == 4):
            self.forw.setEnabled(True)
            self.back.setEnabled(True)
        else:
            if ((index + 1) == self.playlist.mediaCount()):
                self.forw.setEnabled(False)
                self.back.setEnabled(True)
            else:
                self.back.setEnabled(True)

    def video(self):
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.mediaPlayer.positionChanged.connect(self.sliderDuration2)
        self.mediaPlayer.setVolume(10)

        videoWidget = QVideoWidget()
        layout = QVBoxLayout()

        wid = QWidget(self)
        self.play = QPushButton()
        self.play.setEnabled(False)
        self.play.setFixedWidth(40)
        self.play.setFixedHeight(30)
        self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.play.setIconSize(QSize(20, 20))
        self.play.clicked.connect(self.playAction)
        self.play.setShortcut(QKeySequence("Space"))

        self.back = QPushButton()
        self.back.setEnabled(False)
        self.back.setFixedWidth(40)
        self.back.setFixedHeight(25)
        self.back.setStyleSheet("margin-left: 10px")
        self.back.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSeekBackward))
        self.back.setIconSize(QSize(14, 14))
        self.back.clicked.connect(self.prevAction)

        self.back.setShortcut(QKeySequence("Ctrl+b"))

        self.stop = QPushButton()
        self.stop.setEnabled(False)
        self.stop.setFixedWidth(40)
        self.stop.setFixedHeight(25)
        self.stop.setStyleSheet("margin-left: 0px")
        self.stop.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.stop.setIconSize(QSize(14, 14))
        self.stop.clicked.connect(self.stopAction)
        self.stop.setShortcut(QKeySequence("s"))

        self.forw = QPushButton()
        self.forw.setEnabled(False)
        self.forw.setFixedWidth(40)
        self.forw.setFixedHeight(25)
        self.forw.setStyleSheet("margin-left: 0px")
        self.forw.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSeekForward))
        self.forw.setIconSize(QSize(14, 14))
        self.forw.clicked.connect(self.forwAction)
        self.forw.setShortcut(QKeySequence("Ctrl+f"))

        self.loop = QPushButton()
        self.loop.setEnabled(False)
        self.loop.setFixedWidth(40)
        self.loop.setFixedHeight(25)
        self.loop.setStyleSheet("margin-left: 10px")
        self.loop.setIcon(QIcon(QPixmap("loop.svg")))
        self.loop.setIconSize(QSize(14, 14))
        self.loop.clicked.connect(self.loopAction)
        self.loop.setShortcut(QKeySequence("Ctrl+l"))

        self.shuffl = QPushButton()
        self.shuffl.setEnabled(False)
        self.shuffl.setFixedHeight(25)
        self.shuffl.setStyleSheet("margin-left: 0px")
        self.shuffl.setFixedWidth(40)
        self.shuffl.setFixedHeight(25)
        self.shuffl.setStyleSheet("margin-left: 0px")
        self.shuffl.setIcon(QIcon(QPixmap("shuffl.svg")))
        self.shuffl.setIconSize(QSize(14, 14))
        self.shuffl.clicked.connect(self.shufflAction)
        self.shuffl.setShortcut(QKeySequence("Ctrl+shift+s"))

        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)

        self.volume = QDial()
        self.volume.setFixedWidth(40)
        self.volume.setFixedHeight(40)
        self.volume.setMaximum(100)
        self.volume.setMinimum(0)
        self.volume.setToolTip("Volume")
        self.volume.valueChanged.connect(self.volumeChange)

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.play)
        hlayout.addWidget(self.back)
        hlayout.addWidget(self.stop)
        hlayout.addWidget(self.forw)
        hlayout.addWidget(self.loop)
        hlayout.addWidget(self.shuffl)
        hlayout.addItem(spacer)
        hlayout.addWidget(self.volume)

        hslayout = QHBoxLayout()
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(0)
        self.l1 = QLabel()
        self.l1.setText("--:--:--")
        self.l2 = QLabel()
        self.l2.setText("--:--:--")
        self.slider.sliderMoved.connect(self.sliderChanged)
        hslayout.addWidget(self.l1)
        hslayout.addWidget(self.slider)
        hslayout.addWidget(self.l2)

        layout.addWidget(videoWidget)

        layout.addLayout(hslayout)
        layout.addLayout(hlayout)
        wid.setLayout(layout)

        self.setCentralWidget(wid)
        self.mediaPlayer.setVideoOutput(videoWidget)

    def playAction(self):
        if (self.mediaPlayer.state() == 1):
            self.mediaPlayer.pause()
            self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        elif (self.mediaPlayer.state() == 2):
            self.mediaPlayer.play()
            self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))

        else:
            self.back.setEnabled(False)
            self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))

    def stopAction(self):
        self.mediaPlayer.stop()
        self.play.setEnabled(False)
        self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.setWindowTitle(self.titles)
        self.l1.setText("--:--:--")
        self.l2.setText("--:--:--")

    def forwAction(self):
        if (self.playlist.playbackMode() == 4):
            self.forw.setEnabled(True)
            self.back.setEnabled(True)
            indexes = random.randint(0, (self.playlist.mediaCount() - 1))
            self.playlist.setCurrentIndex(indexes)
        elif (self.playlist.playbackMode() == 1):
            self.playlist.next()
        else:
            print(self.playlist.currentIndex())
            if ((self.playlist.currentIndex() +
                 2) == self.playlist.mediaCount()):
                self.forw.setEnabled(False)
                self.playlist.next()
                self.back.setEnabled(True)
            else:
                self.playlist.next()
                self.back.setEnabled(True)

    def prevAction(self):
        if (self.playlist.playbackMode() == 4):
            self.forw.setEnabled(True)
            self.back.setEnabled(True)
            indexes = random.randint(0, (self.playlist.mediaCount() - 1))
            self.playlist.setCurrentIndex(indexes)
        elif (self.playlist.playbackMode() == 1):
            self.playlist.previous()
        else:
            if (self.playlist.currentIndex() == 1):
                self.forw.setEnabled(True)
                self.playlist.previous()
                self.back.setEnabled(False)
            else:
                self.playlist.previous()
                self.forw.setEnabled(True)

    def loopAction(self):
        if (self.playlist.playbackMode() != 1):
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            self.loop.setIcon(QIcon(QPixmap("greenloop.svg")))
            self.shuffl.setIcon(QIcon(QPixmap("shuffl.svg")))
        else:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            self.loop.setIcon(QIcon(QPixmap("loop.svg")))

    def shufflAction(self):
        if (self.playlist.playbackMode() != 4):
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
            self.shuffl.setIcon(QIcon(QPixmap("greenshuffl.svg")))
            self.loop.setIcon(QIcon(QPixmap("loop.svg")))
        else:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            self.shuffl.setIcon(QIcon(QPixmap("shuffl.svg")))

    def close(self):
        sys.exit(1)
Beispiel #30
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        ##      self.setWindowTitle("Demo10_1,音乐播放器")
        self.player = QMediaPlayer(self)
        self.playlist = QMediaPlaylist(self)
        self.player.setPlaylist(self.playlist)
        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)  #循环模式

        self.__duration = ""  #文件总时间长度
        self.__curPos = ""  #当前播放到位置

        self.player.stateChanged.connect(self.do_stateChanged)

        self.player.positionChanged.connect(self.do_positionChanged)

        self.player.durationChanged.connect(self.do_durationChanged)

        self.playlist.currentIndexChanged.connect(self.do_currentChanged)

##  ==============自定义功能函数============

##  ===============event 处理函数==========

    def closeEvent(self, event):  ##窗体关闭时
        ##  窗口关闭时不能自动停止播放,需手动停止
        if (self.player.state() == QMediaPlayer.PlayingState):
            self.player.stop()

##  ==========由connectSlotsByName() 自动连接的槽函数==================
#  播放列表管理

    @pyqtSlot()  ##添加文件
    def on_btnAdd_clicked(self):
        ##      curPath=os.getcwd()     #获取系统当前目录
        ##      curPath=QDir.homePath()
        curPath = QDir.currentPath()
        dlgTitle = "选择音频文件"
        filt = "音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)"
        fileList, flt = QFileDialog.getOpenFileNames(self, dlgTitle, curPath,
                                                     filt)
        count = len(fileList)
        if count < 1:
            return

        filename = fileList[0]
        fileInfo = QFileInfo(filename)  #文件信息
        QDir.setCurrent(fileInfo.absolutePath())  #重设当前路径

        for i in range(count):
            filename = fileList[i]
            fileInfo.setFile(filename)
            song = QMediaContent(QUrl.fromLocalFile(filename))
            self.playlist.addMedia(song)  #添加播放媒体
            ##         basename=os.path.basename(filename)    #文件名和后缀
            basename = fileInfo.baseName()
            self.ui.listWidget.addItem(basename)  #添加到界面文件列表

        if (self.player.state() != QMediaPlayer.PlayingState):
            self.playlist.setCurrentIndex(0)
            self.player.play()

    @pyqtSlot()  ##移除一个文件
    def on_btnRemove_clicked(self):
        pos = self.ui.listWidget.currentRow()
        item = self.ui.listWidget.takeItem(pos)  #python会自动删除

        if (self.playlist.currentIndex() == pos):  #是当前播放的曲目
            nextPos = 0
            if pos >= 1:
                nextPos = pos - 1

            self.playlist.removeMedia(pos)  #从播放列表里移除
            if self.ui.listWidget.count() > 0:  #剩余个数
                self.playlist.setCurrentIndex(nextPos)
                self.do_currentChanged(nextPos)  #当前曲目变化
            else:
                self.player.stop()
                self.ui.LabCurMedia.setText("无曲目")
        else:
            self.playlist.removeMedia(pos)

    @pyqtSlot()  ##清空播放列表
    def on_btnClear_clicked(self):
        self.playlist.clear()  #清空播放列表
        self.ui.listWidget.clear()
        self.player.stop()  #停止播放

    ##   @pyqtSlot()    ##双击时切换播放文件
    def on_listWidget_doubleClicked(self, index):
        rowNo = index.row()  #行号
        self.playlist.setCurrentIndex(rowNo)
        self.player.play()

#  播放控制

    @pyqtSlot()  ##播放
    def on_btnPlay_clicked(self):
        if (self.playlist.currentIndex() < 0):
            self.playlist.setCurrentIndex(0)
        self.player.play()

    @pyqtSlot()  ##暂停
    def on_btnPause_clicked(self):
        self.player.pause()

    @pyqtSlot()  ##停止
    def on_btnStop_clicked(self):
        self.player.stop()

    @pyqtSlot()  ##上一曲目
    def on_btnPrevious_clicked(self):
        self.playlist.previous()

    @pyqtSlot()  ##下一曲目
    def on_btnNext_clicked(self):
        self.playlist.next()

    @pyqtSlot()  ##静音控制
    def on_btnSound_clicked(self):
        mute = self.player.isMuted()
        self.player.setMuted(not mute)
        if mute:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp"))
        else:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp"))

    @pyqtSlot(int)  ##调节音量
    def on_sliderVolumn_valueChanged(self, value):
        self.player.setVolume(value)

    @pyqtSlot(int)  ##文件进度调控
    def on_sliderPosition_valueChanged(self, value):
        self.player.setPosition(value)

##  =============自定义槽函数===============================

    def do_stateChanged(self, state):  ##播放器状态变化
        self.ui.btnPlay.setEnabled(state != QMediaPlayer.PlayingState)
        self.ui.btnPause.setEnabled(state == QMediaPlayer.PlayingState)
        self.ui.btnStop.setEnabled(state == QMediaPlayer.PlayingState)

    def do_positionChanged(self, position):  ##当前文件播放位置变化,更新进度显示
        if (self.ui.sliderPosition.isSliderDown()):  #在拖动滑块调整进度
            return
        self.ui.sliderPosition.setSliderPosition(position)
        secs = position / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__curPos = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)

    def do_durationChanged(self, duration):  ##文件时长变化
        self.ui.sliderPosition.setMaximum(duration)

        secs = duration / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__duration = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)

    def do_currentChanged(self, position):  ##playlist当前曲目变化
        self.ui.listWidget.setCurrentRow(position)
        item = self.ui.listWidget.currentItem()  #QListWidgetItem
        if (item != None):
            self.ui.LabCurMedia.setText(item.text())
Beispiel #31
0
class Reproductor(Genesis, QMainWindow):

    """ Instalar MatroskaSplitter y LAVFilters(Codecs), para que pueda reproducir videos y audio

    LAVFilters
    https://github.com/Nevcairiel/LAVFilters/releases
    
    MatroskaSplitter
    https://haali.su/mkv/  
    """
    
    def __init__(self, *args, **kwargs):
        super(Reproductor, self).__init__()

        self.transcurso = 0
        
        # Centramos la ventana principal
        self.centrar()

        # Inicializamos el modulo QMediaPlayer
        self.media = QMediaPlayer()
        self.media.setVolume(5)
        self.reproducir.setEnabled(False)

        # Setup the playlist.
        self.lista_repro = QMediaPlaylist()
        self.media.setPlaylist(self.lista_repro)

        self.modelo = ListaModelo(self.lista_repro)
        self.lista.setModel(self.modelo)

        self.lista_repro.currentIndexChanged.connect(self.cambio_lista_repro)

        modelo_seleccion = self.lista.selectionModel()
        modelo_seleccion.selectionChanged.connect(self.seleccion_lista_repro)


# **********  Inicializamos el modulo QVideoWidget *******
        self.video = QVideoWidget()

        # Agregamos el modulo QVideoWidget al grid donde se mostrara el video
        self.reproductor.addWidget(self.video)

        # Tambien lo agregamos al modulo QMediaPlayer
        self.media.setVideoOutput(self.video)

        # Conectamos el boton de reproducir con su metodo correspondiente
        self.reproducir.clicked.connect(self.play_video)

        # Conectamos el Skider del tiempo con su metodo correspondiente
        self.tiempo.sliderMoved.connect(self.posicion_establecida)
    

# ******  Conectamos los estados del modulo QMediaPlayer con sus correspondientes metodos  *****
        self.media.stateChanged.connect(self.cambios_video)
        self.media.positionChanged.connect(self.posicion_video)
        self.media.durationChanged.connect(self.duracion_video)
        self.total_duracion = 0

        self.cargar.clicked.connect(self.abrir_archivo)
        #self.marco.origen.connect(self.arrastrar_soltar)

        self.parar.pressed.connect(self.media.stop)
        self.atras.pressed.connect(self.lista_repro.previous)
        self.adelante.pressed.connect(self.lista_repro.next)
        self.volumen.valueChanged.connect(self.media.setVolume)
        self.logo_volumen.clicked.connect(self.silenciar)
        self.lista.doubleClicked.connect(self.play_video)
        self.video.keyPressEvent = self.keyPressEvent

#         ****** Boton de menu ******
        self.lista.setMinimumSize(QSize(0, 0))
        self.lista_visible = True
        self.menu.clicked.connect(self.boton_menu)

        self.setAcceptDrops(True)

        self.primera_reproduccion = True
        self.show()

# ---------------- Inicio de Metodos --------------------------- #

    # Detectamos una tecla presionada
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_F11 or event.key() == Qt.Key_Escape and self.video.isFullScreen():
            self.fullscreen_change()
        elif event.key() == Qt.Key_Space:
            self.play_video()

    #Pantalla completa
    def fullscreen_change(self):
        if self.video.isFullScreen():
            self.video.setFullScreen(False)
            self.lista.setMinimumSize(QSize(300, 16777215))
        else:
            self.video.setFullScreen(True)


    # Ocultar y mostrar la lista de reproduccion
    def boton_menu(self):
        if self.lista_visible:
            self.lista.setVisible(False)
            size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            self.marco.setSizePolicy(size_policy)
            self.lista_visible = False
        else:
            self.lista.setVisible(True)
            self.lista_visible = True

    # Metodos para arrastrar y soltar en la lista de reproduccion
    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.acceptProposedAction()

    # Metodos para arrastrar y soltar en la lista de reproduccion
    def dropEvent(self, e):
        for url in e.mimeData().urls():
            self.lista_repro.addMedia(QMediaContent(url))
        
        self.lista_repro.setPlaybackMode(QMediaPlaylist.Loop)

        self.media.setPlaylist(self.lista_repro)
        self.reproducir.setEnabled(True)
        self.reproductor.removeWidget(self.logo)

        self.media.play()

        self.modelo.layoutChanged.emit()

        """

        # If not playing, seeking to first of newly added + play.
        if self.media.state() != QMediaPlayer.PlayingState:
            #i = self.lista_repro.mediaCount() - len(e.mimeData().urls())
            #print(i)
            #self.lista_repro.setCurrentIndex(i)            
            self.reproducir.setEnabled(True)
            self.reproductor.removeWidget(self.logo)
            #self.media.setPlaylist(playlist)
            self.media.play() """

    # Metodo para cargar el video en cuestion
    def abrir_archivo(self):
        archivo, _ = QFileDialog.getOpenFileName(self, '   Abrir Archivo !!!', 'C:/Users/Duque/Videos', 'Solo Video (*.mp4 *.mov *.flv *.mkv *.ts *.mts *.avi);; Solo Audio (*.mp3 *.flac *.m4a *.wav)')

        if archivo != '':
            self.reproductor.removeWidget(self.logo)
            self.primera_reproduccion = False
            self.lista_repro.addMedia(QMediaContent(QUrl.fromLocalFile(archivo)))
            self.reproducir.setEnabled(True)

        self.modelo.layoutChanged.emit()

    # Metodo para el cambio en la lista de reproduccion
    def cambio_lista_repro(self, i):
        if i > -1:
            ix = self.modelo.index(i)
            self.lista.setCurrentIndex(ix)

    # Metodo para la seleccion en la lista de reproduccion
    def seleccion_lista_repro(self, ix):
        i = ix.indexes()[0].row()
        self.lista_repro.setCurrentIndex(i)

    # Metodo para silenciar el audio o video
    def silenciar(self):
        if self.media.isMuted():
            self.media.setMuted(False)
            icon = QIcon()
            icon.addPixmap(QPixmap(":/img/altavoz3.png"), QIcon.Normal, QIcon.Off)
            self.logo_volumen.setIcon(icon)
            self.logo_volumen.setToolTip(' Silenciar ')
        else:
            self.media.setMuted(True)
            icon = QIcon()
            icon.addPixmap(QPixmap(":/img/altavoz4.png"), QIcon.Normal, QIcon.Off)
            self.logo_volumen.setIcon(icon)
            self.logo_volumen.setToolTip(' Restablecer Sonido ')



    @pyqtSlot(str)
    def arrastrar_soltar(self, archivo):
        if archivo != '':
            self.media.setMedia(QMediaContent(QUrl.fromLocalFile(archivo)))
            self.reproducir.setEnabled(True)
            self.lista_repro.addMedia(QMediaContent(QUrl.fromLocalFile(archivo)))
            self.modelo.layoutChanged.emit()

    # Metodo para reproducir el video en cuestion
    def play_video(self):
        if self.primera_reproduccion:
            self.reproductor.removeWidget(self.logo)
            self.primera_reproduccion = False
        if self.media.state() == QMediaPlayer.PlayingState:
            self.media.pause()
        else:
            self.media.play()

    # Metodo que detecta el estado de cambio del boton reproducir de play a pausa y viceversa
    def cambios_video(self, state):
        if self.media.state() == QMediaPlayer.PlayingState:
            icon = QIcon()
            icon.addPixmap(QPixmap(":/img/pausa.png"), QIcon.Normal, QIcon.Off)
            self.reproducir.setIcon(icon)
            self.reproducir.setToolTip(' Pausar Video o Audio ')
            QToolTip.setFont(QFont('Cascadia Code PL', 18))   
        else:
            icon = QIcon()
            icon.addPixmap(QPixmap(":/img/play.svg"), QIcon.Normal, QIcon.Off)
            self.reproducir.setIcon(icon)
            self.reproducir.setToolTip(' Reproducir Video o Audio ')
            QToolTip.setFont(QFont('Cascadia Code PL', 18))


    def duracion_video(self, duracion):
        """
        # Detecta la duración del vídeo en el slider.
        """
        self.tiempo.setMaximum(duracion)
        self.total_duracion = duracion

    # Metodo que detecta la posiscion del video en el slider
    def posicion_video(self, posicion):

        if posicion >= 0:
            reproduccion = f'{detalle_tiempo(posicion)} || {detalle_tiempo(self.total_duracion)}'
            self.datos.setText(reproduccion)

        self.tiempo.blockSignals(True)
        self.tiempo.setValue(posicion)
        self.tiempo.blockSignals(False)


    # Metodo que detecta la posiscion establecida del modulo QMediaPlayer   
    def posicion_establecida(self, position):
        self.media.setPosition(position)

    def errores(self):
        self.reproducir.setEnabled(False)
        # self.lbl.setText("Error: " + self.media.errorString())

    # Metodo para centrar la ventana principal
    def centrar(self):
        ventana = self.frameGeometry()
        centro = QDesktopWidget().availableGeometry().center()
        # print(centro)
        ventana.moveCenter(centro)
        self.move(ventana.topLeft())
Beispiel #32
0
class Control:
    """A class that handles the logic behind the program by manipulating the GUI classes
    and calling their methods in response to received signals."""

    MAGIC = b"\x01\xff"

    def __init__(self, screens: list) -> None:
        self.player = QMediaPlayer()
        self.player.setAudioRole(QAudio.MusicRole)
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)
        self.mainWindow = MainWindow(self, screens)
        self.mainArea = self.mainWindow.centralWidget().upperBox.mainArea
        self.songList = self.mainWindow.centralWidget().upperBox.songList
        self.mediaControlArea = self.mainWindow.centralWidget(
        ).mediaControlArea
        self.mainWindow.show()
        self.library = None
        self.currentSong = None
        self.playing = False
        self.random = False
        self.repeat = 0
        self.volume = 50

        self.volumeChange(self.volume)
        self.mediaControlArea.volumeControl.setValue(self.volume)

        self.mainTimer = QTimer()
        self.mainTimer.setInterval(100)
        self.mainTimer.timeout.connect(self.updateSongProgress)
        self.mainTimer.start()

        self.libraryUpdateTimer = QTimer()
        self.libraryUpdateTimer.setInterval(15_000)
        self.libraryUpdateTimer.timeout.connect(self.updateLibrary)
        self.libraryUpdateTimer.start()

        self._connection = None
        self.connections()

        self.displayedType = None
        self.displayedName = None
        self.types = None
        self.songListWidth = None
        values = self.load()
        if values:
            self.mainWindow.setGeometry(*values)
            self.volumeChange(self.volume)
            self.mediaControlArea.volumeControl.setValue(self.volume)

        self.setUpTimer = QTimer()
        self.setUpTimer.setInterval(20)
        self.setUpTimer.setSingleShot(True)
        self.setUpTimer.timeout.connect(self.setAreas)
        self.setUpTimer.start()

    def connections(self):
        self.player.currentMediaChanged.connect(self.updateCurrentSong)
        self.player.durationChanged.connect(self.updateSongProgressRange)
        self.player.stateChanged.connect(self.playerStatusChanged)
        self.mediaControlArea.previousButton.click.connect(
            self.playlist.previous)
        self.mediaControlArea.repeatButton.click.connect(
            self.repeatButtonClick)
        self.mediaControlArea.stopButton.click.connect(self.stopButtonClick)
        self.mediaControlArea.playButton.click.connect(self.playButtonClick)
        self.mediaControlArea.randomButton.click.connect(
            self.randomButtonClick)
        self.mediaControlArea.nextButton.click.connect(self.playlist.next)
        self.mediaControlArea.muteButton.click.connect(self.mute)
        self.mediaControlArea.songProgress.sliderMoved.connect(
            self.songProgressMove)
        self.mediaControlArea.volumeControl.sliderMoved.connect(
            self.volumeChange)

    def setAreas(self) -> None:
        """Called after the GUI is created to provide user with a feedback
        that the program is running in case a larger amount of songs will be added
        when the Library class is initialized."""
        # TODO add a tooltip that will notify the user larger amount of songs is being loaded
        #  (freezes the program as the execution moves to the Library class.)
        self.library = library.Library()
        self.types = {
            "artist": self.library.getSongsForArtist,
            "album": self.library.getSongsForAlbum,
            "playlist": self.library.getSongsForPlaylist
        }
        self.mainArea.setAreas(self.library)
        self.setUpTimer.deleteLater()
        self.setUpTimer = None
        self.getSongs(self.displayedType, self.displayedName)
        if self.songListWidth is not None:
            songListGeometry = self.songList.geometry()
            self.songList.preferredWidth = songListGeometry.width(
            ) - self.songListWidth
            self.mainWindow.centralWidget().upperBox.line.resizeWidgets(
                songListGeometry.width() - self.songListWidth)

    def updateLibrary(self) -> None:
        self.library.update()
        self.mainArea.updateView(self.library)

    def updateCurrentSong(self) -> None:
        """Update all areas that may display information about the currently
        playing song - SongList, Now Playing tab, BottomBox"""
        media = self.player.currentMedia()
        self.currentSong = media.request().url().toLocalFile().replace(
            "/", "\\")
        if self.currentSong in self.library.library:
            self.songList.updateActiveSong(self.currentSong)
            self.mainArea.updateActiveSong(self.playlist.currentIndex())
            songEntry = self.library.library[self.currentSong]
            self.mediaControlArea.updateSongInfo(
                f"{songEntry[ARTIST]} - {songEntry[NAME]}")

    def updateSongProgressRange(self) -> None:
        """Updates the range of the slider that represents the song position."""
        self.mediaControlArea.updateSongProgressRange(self.player.duration())

    def playerStatusChanged(self) -> None:
        """Used to properly update the player look after the current playlist has finished."""
        index = self.playlist.currentIndex()
        if index == -1:
            self.stopButtonClick()

    def getSongs(self, isType: str, name: str) -> None:
        """Retrieves the songs for a given artist, album or playlist based on type
        and passes the resulting list to the SongList class."""
        if isType is None:
            isType = self.displayedType
        if name is None:
            name = self.displayedName
        orderBy = self.songList.buttonOrderBy.text()
        reverse = True if self.songList.buttonOrderReverse.text() == chr(
            0x25bc) else False
        listForType = self.types[isType](name, orderBy, reverse)
        playlist = None
        if isType == "playlist":
            playlist = name
        if len(listForType) == 0:
            artists = self.library.artists
            if len(artists):
                listForType = self.library.getSongsForArtist(artists[0])
        self.songList.updateSongList(listForType, self.library.library,
                                     self.currentSong, playlist, isType)
        self.displayedType = isType
        self.displayedName = name

    def playSongList(self, song: str = None) -> None:
        """Called when user double-clicks on an artist/album/playlist widget or a song
        in right-hand side panel."""
        self.playlist.clear()
        index = 0
        loopIndex = 0
        for songPath in self.songList.garbageProtector:
            if song == songPath:
                index = loopIndex
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath)))
            loopIndex += 1
        if self.playlist.isEmpty():
            return
        self.player.play()
        if index > 0:
            self.playlist.setCurrentIndex(index)
        self.playing = True
        self.mediaControlArea.playButton.updatePictures(
            bottom.pausePixmap, bottom.pauseHoverPixmap, False)
        self.mainArea.setNowPlayingArea(self.library)
        self.mainArea.updateActiveSong(self.playlist.currentIndex())

    def playSongWidget(self,
                       songPath: str,
                       afterCurrent: bool = False) -> None:
        if afterCurrent:
            index = self.playlist.currentIndex() + 1
            self.playlist.insertMedia(
                index, QMediaContent(QUrl.fromLocalFile(songPath)))
        else:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath)))
        self.mainArea.setNowPlayingArea(self.library)
        self.mainArea.updateActiveSong(self.playlist.currentIndex())
        self.playing = True

    def removeFromNowPlaying(self, widget) -> None:
        if self.playlist.mediaCount() > 1:
            for row in range(self.mainArea.nowPlayingLayout.rowCount()):
                for column in range(
                        self.mainArea.nowPlayingLayout.columnCount()):
                    if self.mainArea.nowPlayingLayout.itemAtPosition(
                            row, column).widget() is widget:
                        self.playlist.removeMedia(row - 1)
                        break
                else:
                    continue
                break
        else:
            self.stopButtonClick()
            self.playlist.clear()
        self.mainArea.setNowPlayingArea(self.library)
        if self.playing:
            self.mainArea.updateActiveSong(self.playlist.currentIndex())

    def playMediaWidget(self, isType: str, target: str, startOver: bool,
                        afterCurrent: bool) -> None:
        """Called from MediaWidget - plays all songs for MediaWidget's type and name."""
        if startOver:
            self.playlist.clear()
        if afterCurrent:
            index = self.playlist.currentIndex() + 1
            for songPath in self.types[isType](target):
                self.playlist.insertMedia(
                    index, QMediaContent(QUrl.fromLocalFile(songPath)))
                index += 1
        else:
            for songPath in self.types[isType](target):
                self.playlist.addMedia(
                    QMediaContent(QUrl.fromLocalFile(songPath)))
        if startOver:
            self.player.play()
            self.playing = True
            self.mediaControlArea.playButton.updatePictures(
                bottom.pausePixmap, bottom.pauseHoverPixmap, False)
        self.mainArea.setNowPlayingArea(self.library)
        self.mainArea.updateActiveSong(self.playlist.currentIndex())

    def playFromNowPlaying(self, song: str) -> None:
        """Called when user double-clicks on a song in the Now Playing tab."""
        for n in range(self.playlist.mediaCount()):
            media = self.playlist.media(n)
            if song == media.request().url().toLocalFile().replace("/", "\\"):
                self.playlist.setCurrentIndex(n)
                if not self.playing:
                    self.player.play()
                    self.playing = True
                return

    def createPlaylist(self, playlistName: str) -> None:
        self.library.createPlaylist(playlistName)
        self.mainArea.setMainAreaPlaylists(self.library)

    def addToExistingPlaylist(self, playlist: str, songOrWidget: str,
                              isType: str) -> None:
        if isType in self.types:
            for song in self.types[isType](songOrWidget):
                self.library.addToPlaylist(playlist, song)
        else:
            self.library.addToPlaylist(playlist, songOrWidget)
        self.library.update()

    def removeFromPlaylist(self, playlist: str, song: str) -> None:
        self.library.deleteFromPlaylist(playlist, song)
        self.mainArea.setMainAreaPlaylists(self.library)
        self.library.update()
        self.getSongs("playlist", playlist)

    def renamePlaylist(self, playlistName: str, newPlaylistName: str) -> None:
        self.library.renamePlaylist(playlistName, newPlaylistName)
        self.mainArea.setMainAreaPlaylists(self.library)
        self.library.update()

    def deletePlaylist(self, playlistName: str) -> None:
        self.library.deletePlaylist(playlistName)
        self.mainArea.setMainAreaPlaylists(self.library)
        self.library.update()

    def addWatchedFolder(self, folder: str) -> None:
        """Adds a folder to the Library class. all mp3 files within the folder
        and its sub-folders will be added to the library and accessible to the player."""
        self.library.addFolder(folder.replace("/", "\\"))
        self.mainArea.updateView(self.library)

    def removeWatchedFolder(self, folder: str) -> None:
        """Removes folder from the library, updates view and stops playback if
        the current song was in the now-removed folder."""
        self.library.deleteFolder(folder)
        self.mainArea.updateView(self.library)
        if self.currentSong not in self.library.library:
            self.songList.updateSongList([], [], "", "")
            self.player.stop()
            self.playlist.clear()
            self.mediaControlArea.updateSongInfo("")
            self.songList.nowPlayingSong = None
            self.mainArea.nowPlayingSong = None
            self.playing = False
            self.mediaControlArea.updatePlayButton(self.playing, False)

    def playButtonClick(self, passMove: bool = True) -> None:
        if not self.playing:
            if self.playlist.isEmpty():
                self.playSongList()
                return
            self.playing = True
            self.player.play()
            self.mainArea.updateActiveSong(self.playlist.currentIndex())
            self.songList.updateActiveSong(self.currentSong)
        else:
            self.playing = False
            self.player.pause()
        self.mediaControlArea.updatePlayButton(self.playing, passMove)

    def repeatButtonClick(self) -> None:
        if self.repeat == 0:
            self.repeat = 1
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
        elif self.repeat == 1:
            self.repeat = 2
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
        elif self.repeat == 2:
            self.repeat = 0
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
        self.mediaControlArea.updateRepeatButton(self.repeat)

    def randomButtonClick(self) -> None:
        if not self.random:
            self.random = True
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
        else:
            self.random = False
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
        self.mediaControlArea.updateRandomButton(self.random)

    def stopButtonClick(self) -> None:
        self.playing = False
        self.player.stop()
        if self.songList.nowPlayingSong is not None:
            self.songList.nowPlayingSong.clear()
        if self.mainArea.nowPlayingSong is not None:
            self.mainArea.nowPlayingSong.clear()
        self.mediaControlArea.updatePlayButton(self.playing, False)

    def mute(self) -> None:
        if not self.player.isMuted():
            self.player.setMuted(True)
            self.mediaControlArea.showMute()
        else:
            self.player.setMuted(False)
            self.volumeChange(self.volume)

    def volumeChange(self, volume: int) -> None:
        logVolume = QAudio.convertVolume(volume / 100,
                                         QAudio.LogarithmicVolumeScale,
                                         QAudio.LinearVolumeScale) * 100
        self.player.setVolume(logVolume)
        self.volume = volume
        self.mediaControlArea.updateVolumeBar(volume)

    def songProgressMove(self, position: int) -> None:
        self.player.setPosition(position)

    def updateSongProgress(self) -> None:
        position = self.player.position()
        if 0 <= position < 2_000_000_000:
            if self.player.state() > 0:
                self.mediaControlArea.updateSongProgress(position)
                if self.playing:
                    self.songList.activeSongPixmap()
                    self.mainArea.activeSongPixmap()
            else:
                self.mediaControlArea.updateSongProgress(0)

    def disconnect(self):
        self.player.currentMediaChanged.disconnect()
        self.player.durationChanged.disconnect()
        self.player.stateChanged.disconnect()
        self.mediaControlArea.previousButton.click.disconnect()
        self.mediaControlArea.repeatButton.click.disconnect()
        self.mediaControlArea.stopButton.click.disconnect()
        self.mediaControlArea.playButton.click.disconnect()
        self.mediaControlArea.randomButton.click.disconnect()
        self.mediaControlArea.nextButton.click.disconnect()
        self.mediaControlArea.muteButton.click.disconnect()
        self.mediaControlArea.songProgress.sliderMoved.disconnect()
        self.mediaControlArea.volumeControl.sliderMoved.disconnect()

    def close(self) -> None:
        self.disconnect()
        self.player.stop()
        self.mainTimer.stop()
        self.save()

    def save(self) -> None:
        """Called on exit, saves current view, geometry and volume."""
        with gzip.open(r"musicplayer\mpdata", "wb") as fh:
            fh.write(self.MAGIC)
            toBeWritten = struct.pack(f"<h{len(self.displayedType.encode())}s",
                                      len(self.displayedType.encode()),
                                      self.displayedType.encode())
            fh.write(toBeWritten)
            fh.write(self.MAGIC)
            toBeWritten = struct.pack(f"<h{len(self.displayedName.encode())}s",
                                      len(self.displayedName.encode()),
                                      self.displayedName.encode())
            fh.write(toBeWritten)
            fh.write(self.MAGIC)
            geo = self.mainWindow.geometry()
            toBeWritten = struct.pack("<4h", geo.x(), geo.y(), geo.width(),
                                      geo.height())
            fh.write(toBeWritten)
            toBeWritten = struct.pack("<h", self.volume)
            fh.write(toBeWritten)
            toBeWritten = struct.pack("<h", self.songList.width())
            fh.write(toBeWritten)

    def load(self) -> [bool, tuple]:
        """Called on startup, loads view, geometry and volume saved on previous run."""
        try:
            with gzip.open(r"musicplayer\mpdata", "rb") as fh:
                if not fh.read(2) == self.MAGIC:
                    return False
                length = fh.read(2)
                length = struct.unpack("<h", length)[0]
                displayedType = fh.read(length)
                displayedType = struct.unpack(f"<{length}s",
                                              displayedType)[0].decode("utf8")
                if displayedType in ["artist", "album", "playlist"]:
                    self.displayedType = displayedType
                if not fh.read(2) == self.MAGIC:
                    return False
                length = fh.read(2)
                length = struct.unpack("<h", length)[0]
                displayedName = fh.read(length)
                displayedName = struct.unpack(f"<{length}s",
                                              displayedName)[0].decode("utf8")
                if not fh.read(2) == self.MAGIC:
                    return False
                self.displayedName = displayedName
                variables = []
                for n in range(6):
                    var = fh.read(2)
                    var = struct.unpack("<h", var)[0]
                    variables.append(var)
                x, y, width, height, volume, songListWidth = variables
                self.volume = volume
                self.songListWidth = songListWidth
                return x, y, width, height
        except Exception:
            return False
Beispiel #33
0
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        # load config
        self.data = yaml_loader()

        # load ui
        self.setupUi(self)

        # load icons
        self.setWindowTitle("Sputofy")
        self.setWindowIcon(QIcon(os.path.join(RES_PATH, "logo.svg")))

        loopIcon = QIcon()
        loopIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "loopIconOFF.svg")))
        self.loopBtn.setIcon(loopIcon)
        prevIcon = QIcon()
        prevIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "backwardIcon.svg")))
        self.prevBtn.setIcon(prevIcon)
        playIcon = QIcon()
        playIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "playIcon.svg")))
        self.playBtn.setIcon(playIcon)
        nextIcon = QIcon()
        nextIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "forwardIcon.svg")))
        self.nextBtn.setIcon(nextIcon)
        randomIcon = QIcon()
        randomIcon.addPixmap(
            QPixmap(os.path.join(RES_PATH, "randomIconOFF.svg")))
        self.randomBtn.setIcon(randomIcon)
        volumeIcon = QIcon()
        volumeIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "volumeIcon.svg")))
        self.volumeBtn.setIcon(volumeIcon)

        # window's settings
        self.xCor = self.data['last_position']['xPos']
        self.yCor = self.data['last_position']['yPos']
        self.widthSize = self.data['last_window_size']['width']
        self.heightSize = self.data['last_window_size']['height']

        self.setGeometry(self.xCor, self.yCor, self.widthSize, self.heightSize)

        # load YouTubeToMP3
        self.YouTubeToMP3 = YouTubeToMP3Window()

        # open YouTubeToMP3 using button
        self.actionYT_MP3.triggered.connect(self.YouTubeToMP3.show_window)

        # info action
        self.actionInfo.triggered.connect(self.info_handle)

        #===========================  mediaplayer  ==============================

        # create media player object
        self.mediaPlayer = QMediaPlayer(None)

        # open button
        self.actionOpen_Song.triggered.connect(self.open_song)
        self.actionOpen_Folder.triggered.connect(self.open_folder)

        # play button
        self.playBtn.setEnabled(False)
        self.playBtn.clicked.connect(
            self.play_video
        )  # when btn is pressed: if it is playing it pause, if it is paused it plays
        # QShortcut(QKeySequence("Space"), self).activated.connect(self.play_video)metodo da ricordare in caso di problemi #TODO

        # duration slider
        self.durationSlider.setEnabled(False)
        self.durationSliderMaxValue = 0
        self.durationSlider.valueChanged.connect(
            self.mediaPlayer.setPosition
        )  # set mediaPlayer position using the value took from the slider
        QShortcut('Right', self, lambda: self.durationSlider.setValue(
            self.durationSlider.value() + 10000))  # 1s = 1000ms
        QShortcut('Left', self, lambda: self.durationSlider.setValue(
            self.durationSlider.value() - 10000))  # 1s = 1000ms
        QShortcut('Shift+Right', self, lambda: self.durationSlider.setValue(
            self.durationSliderMaxValue - 1000))  # jump to the end-1s of song
        QShortcut('Shift+Left', self,
                  lambda: self.durationSlider.setValue(0))  # restart song

        # volumeSlider
        self.volumeSlider.setProperty("value", 100)
        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setValue(
            self.data['volume']
            if self.data['volume'] != 0 else self.data['volume'] + 1
        )  # set slider value | if saved volume is equal to 0 load with volume = 1 else load the saved volume
        self.mediaPlayer.setVolume(
            self.data['volume']
            if self.data['volume'] != 0 else self.data['volume'] + 1
        )  # set mediaPlayer volume | if saved volume is equal to 0 load with volume = 1 else load the saved volume
        self.volumeLabel.setText(
            f"{self.data['volume']}%"
            if self.data['volume'] != 0 else f"{self.data['volume']+1}%"
        )  # set volume label text | if saved volume is equal to 0 load with volume = 1 else load the saved volume
        self.volumeSlider.valueChanged.connect(
            self.mediaPlayer.setVolume
        )  # set mediaPlayer volume using the value took from the slider

        QShortcut('Up', self, lambda: self.volumeSlider.setValue(
            self.volumeSlider.value() + 1))  # volume + 1
        QShortcut('Down', self, lambda: self.volumeSlider.setValue(
            self.volumeSlider.value() - 1))  # volume - 1

        QShortcut(
            'Shift+Up', self,
            lambda: self.volumeSlider.setValue(100))  # set maximum volume
        QShortcut(
            'Shift+Down', self,
            lambda: self.volumeSlider.setValue(0))  # set minimun volume(mute)

        # volumeBtn
        self.volumeBtn.clicked.connect(
            self.volume_toggle)  # mute/unmute volume pressing btn
        self.isMuted = False  # starting with a non-muted volume
        self.previousVolume = self.data[
            'volume']  # loading last registered volume

        # media player signals
        self.mediaPlayer.durationChanged.connect(
            self.duration_changed)  # set range of duration slider
        self.mediaPlayer.positionChanged.connect(
            self.position_changed)  # duration slider progress
        self.mediaPlayer.stateChanged.connect(
            self.player_state)  # see when it's playing or in pause
        self.mediaPlayer.volumeChanged.connect(
            self.volume_icon)  # change volumebtn icon

        #===========================  playlist  ==============================

        # create the playlist
        self.playlist = QMediaPlaylist()
        self.playlist.setPlaybackMode(2)
        self.mediaPlayer.setPlaylist(self.playlist)

        # clear the playlist
        self.playlistIsEmpty = True

        # playlistList model
        self.model = PlaylistModel(self.playlist)
        self.playlistView.setModel(self.model)
        self.playlist.currentIndexChanged.connect(
            self.playlist_position_changed)
        selection_model = self.playlistView.selectionModel()
        selection_model.selectionChanged.connect(
            self.playlist_selection_changed)

        #===========================  playlist function  ==============================

        self.mediaList = []  # array of loaded songs
        self.currentPlaylist = ""  # current loaded playlist name
        self.isCustomPlaylist = False

        # add song name on title
        self.playlist.currentMediaChanged.connect(self.set_title)

        # playlist buttons
        self.nextBtn.clicked.connect(self.next_song)  # seek track forward

        self.prevBtn.clicked.connect(self.prev_song)  # seek track backward

        self.mediaPlayer.mediaStatusChanged.connect(
            self.auto_next_track
        )  # once song is ended seek track forward and play it

        self.actionLoopIt.triggered.connect(
            self.loop_song)  # (1) loop the same song

        self.actionShuffle.triggered.connect(
            self.shuffle_playlist)  # change song's order

        self.loopBtn.clicked.connect(self.loop)  # (3) loop the playlist

        self.randomBtn.clicked.connect(
            self.random)  # (4) play random song without end

        # create new playlist
        self.actionCreatePlaylist.triggered.connect(self.custom_playlist)

        # delete current playlist
        self.actionDeletePlaylist.triggered.connect(self.delete_playlist)

        # remove all songs
        self.actionClearQueue.triggered.connect(self.clear_queue)

        # load playlist
        self.actionDict = {}  # dictionary of action Objects

        for action in self.data['playlistList']:
            self.actionDict[action] = self.menuPlaylist.addAction(
                action, partial(self.load_playlist, action))

        if len(self.data['playlistList']) == 0:
            self.menuPlaylist.menuAction().setVisible(False)

#================== Songs opening ==================#

    def open_folder(self):
        foldername = QFileDialog.getExistingDirectory(self, "Open folder",
                                                      "c:\\")

        if foldername:
            self.playlist.clear()
            self.mediaList.clear()

            for song in os.listdir(foldername):
                media = f"{foldername}/{song}"
                self.playlist.addMedia(QMediaContent(QUrl(media)))
                self.mediaList.append(media)

            self.playlist.setCurrentIndex(0)

            self.playBtn.setEnabled(True)
            self.durationSlider.setEnabled(True)

            self.playlistIsEmpty = False
            self.isCustomPlaylist = False

            self.model.layoutChanged.emit()  # load songs in list view
            self.set_title()

            self.mediaPlayer.pause()  # adjust play/pause icon

    def open_song(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Open Song", "c:\\")

        if filename:
            if self.playlistIsEmpty == False:
                self.playlist.clear()
                self.mediaList.clear()
                self.playlistIsEmpty = True

            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(filename)))
            self.mediaList.append(filename)

            self.playBtn.setEnabled(True)
            self.durationSlider.setEnabled(True)

            self.isCustomPlaylist = False

            self.model.layoutChanged.emit()  # load song in list view
            self.set_title()

            # adjust play/pause icon
            if self.playlist.mediaCount(
            ) == 1:  # if there is 1 song and you add another
                self.playlist.setCurrentIndex(0)
                self.mediaPlayer.pause()

    def load_playlist(self, playlistName):
        self.playlist.clear()
        self.mediaList.clear()

        # reload config
        self.data = yaml_loader()

        for song in self.data['playlistList'][playlistName]:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(song)))
            self.mediaList.append(song)

        self.playlist.setCurrentIndex(0)

        self.playBtn.setEnabled(True)
        self.durationSlider.setEnabled(True)

        self.playlistIsEmpty = False
        self.isCustomPlaylist = True

        self.model.layoutChanged.emit()  # load songs in list view

        self.currentPlaylist = playlistName  # name of current loaded playlist
        self.set_title()

        self.statusbar.showMessage(f'Playlist "{playlistName}" loaded', 4000)
        self.menuPlaylist.menuAction().setVisible(True)

        # adjust play/pause icon
        self.mediaPlayer.pause()

    def set_title(self):
        if self.playlist.mediaCount() == 0:
            self.setWindowTitle("Sputofy")

        else:
            if self.isCustomPlaylist == False:
                self.setWindowTitle(
                    f"Sputofy - {os.path.splitext(self.playlist.currentMedia().canonicalUrl().fileName())[0]} - {self.playlist.currentIndex()+1}/{self.playlist.mediaCount()}"
                )
            else:
                self.setWindowTitle(
                    f"Sputofy - {self.currentPlaylist} - {os.path.splitext(self.playlist.currentMedia().canonicalUrl().fileName())[0]} - {self.playlist.currentIndex()+1}/{self.playlist.mediaCount()}"
                )

#=======================================================#

#================== Player Functions ==================#

    def play_video(self):
        if self.durationSlider.isEnabled():  # if slider was enabled
            if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
                self.mediaPlayer.pause()
            else:
                self.mediaPlayer.play()

    def duration_changed(self, duration):
        self.durationSlider.setRange(0, duration)

        if duration > 0:
            self.totalTime_Label.setText(time_format(round(
                duration / 1000)))  # duration is in ms
        self.durationSliderMaxValue = duration

    def position_changed(self, position):
        if position >= 0:
            self.elapsedTime_Label.setText(time_format(
                (position / 1000)))  # position is in ms

        # Disable the events to prevent updating triggering a setPosition event (can cause stuttering).
        self.durationSlider.blockSignals(True)
        self.durationSlider.setValue(position)
        self.durationSlider.blockSignals(False)

#=======================================================#

#================== Playlist Settings ==================#
#TODO Work in progress

    def playlist_array(self):
        index = self.playlist.mediaCount()
        mediaList = []
        for i in range(index):
            # songPath = (self.playlist.media(path).canonicalUrl().path())#.split("/",1)[1]
            # mediaList.append(songPath)
            # print(self.playlist.media(i).canonicalUrl().path())
            mediaList.append(self.playlist.media(i).canonicalUrl().fileName())
        return mediaList

    def custom_playlist(self):
        if not self.playlist.mediaCount() == 0:
            name, is_notEmpty = QInputDialog.getText(self, "playlist",
                                                     "save playlist as:")

            if name:

                if name in self.data['playlistList']:
                    self.statusbar.showMessage(
                        "playlist not created (name is already used)", 4000)
                else:
                    self.data['playlistList'][name] = self.mediaList
                    yaml_dump(self.data)

                    # add new action Object to dictionary
                    self.actionDict[name] = self.menuPlaylist.addAction(
                        name, partial(self.load_playlist, name))

                    self.load_playlist(
                        name)  # instantly loading the new playlist
            else:
                self.statusbar.showMessage(
                    "playlist not created (you should give a name to your baby :/)",
                    4000)
        else:
            self.statusbar.showMessage("there are no songs to playlist", 4000)

    def delete_playlist(self):
        if self.isCustomPlaylist:

            if len(self.data['playlistList']) == 1:
                self.menuPlaylist.menuAction().setVisible(False)

            self.data['playlistList'].pop(
                self.currentPlaylist)  # remove playlist from dictionary

            self.menuPlaylist.removeAction(self.actionDict[
                self.currentPlaylist])  # remove relative action
            self.actionDict.pop(
                self.currentPlaylist)  # remove relative action Object

            self.playlist.clear()
            self.model.layoutChanged.emit()
            self.setWindowTitle("Sputofy")

            yaml_dump(self.data)

            self.statusbar.showMessage(
                'succesfully deleted "' + self.currentPlaylist + '" playlist',
                4000)
        else:
            self.statusbar.showMessage("cannot delete a non custom playlist",
                                       4000)

    def clear_queue(self):
        self.playlist.clear()
        self.mediaList.clear()
        self.playBtn.setEnabled(False)
        self.model.layoutChanged.emit()

    def playlist_position_changed(self, i):
        if i > -1:
            ix = self.model.index(i)
            self.playlistView.setCurrentIndex(ix)

    def playlist_selection_changed(self, ix):
        # We receive a QItemSelection from selectionChanged.
        i = ix.indexes()[0].row()
        self.posizione = i
        self.playlist.setCurrentIndex(i)
        self.mediaPlayer.play()

#=======================================================#

#================== Playback Settings ==================#

    def next_song(self):
        if self.playlist.currentIndex() == self.playlist.mediaCount() - 1:
            self.playlist.setCurrentIndex(0)
        else:
            self.playlist.next()

    def prev_song(self):
        if self.playlist.currentIndex() == 0:
            self.playlist.setCurrentIndex(self.playlist.mediaCount() - 1)
        else:
            self.playlist.previous()

    def loop_song(self):
        if self.playlist.playbackMode() != 1:

            self.playlist.setPlaybackMode(1)

            self.actionLoopIt.setText("Loop it: ON")
            self.loopBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "loopIconOFF.svg")))
            self.randomBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "randomIconOFF.svg")))
        else:
            self.playlist.setPlaybackMode(2)
            self.actionLoopIt.setText("Loop it: OFF")

    def shuffle_playlist(self):
        if self.playlist.mediaCount():
            self.playlist.shuffle()
            self.model.layoutChanged.emit()
        else:
            self.statusbar.showMessage("there are no songs to shuffle", 4000)

    def loop(self):
        if self.playlist.playbackMode() != 3:
            self.playlist.setPlaybackMode(3)

            self.loopBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "loopIconON.svg")))
            self.randomBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "randomIconOFF.svg")))
            self.actionLoopIt.setText("Loop it: OFF")

        else:
            self.playlist.setPlaybackMode(2)
            self.loopBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "loopIconOFF.svg")))

    def random(self):
        if self.playlist.playbackMode() != 4:
            self.playlist.setPlaybackMode(4)

            self.randomBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "randomIconON.svg")))
            self.loopBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "loopIconOFF.svg")))
            self.actionLoopIt.setText("Loop it: OFF")

        else:
            self.playlist.setPlaybackMode(2)
            self.randomBtn.setIcon(
                QIcon(os.path.join(RES_PATH, "randomIconOFF.svg")))

    def auto_next_track(self):

        if self.mediaPlayer.mediaStatus() == QMediaPlayer.EndOfMedia:
            if self.playlist.playbackMode() == 2:
                # index starts from 0       mediacount starts from 1
                if self.playlist.currentIndex(
                ) != self.playlist.mediaCount() - 1:
                    self.playlist.next()
                    self.mediaPlayer.play()
                else:  # if ended song was the last one set the index to the first one and pause
                    self.playlist.setCurrentIndex(0)
                    self.mediaPlayer.pause()

            # loop playlist
            elif self.playlist.playbackMode() == 3:
                self.playlist.next()
                self.mediaPlayer.play()

            # random song
            elif self.playlist.playbackMode() == 4:
                while self.playlist.previousIndex(
                ) == self.playlist.currentIndex(
                ):  # preventing repeating the same song
                    self.playlist.setCurrentIndex(
                        random.randint(0,
                                       self.playlist.mediaCount() - 1))

#=======================================================#

#================== Volume Settings ==================#

    def volume_icon(self, volume):

        self.volumeLabel.setText(f"{volume}%")

        if volume:
            volumeIcon = QIcon()
            volumeIcon.addPixmap(
                QPixmap(os.path.join(RES_PATH, "volumeIcon.svg")),
                QIcon.Normal, QIcon.Off)
            self.volumeBtn.setIcon(volumeIcon)
            self.previousVolume = self.volumeSlider.value()
            self.isMuted = False
        else:
            volumeMutedIcon = QIcon()
            volumeMutedIcon.addPixmap(
                QPixmap(os.path.join(RES_PATH, "volumeMutedIcon.svg")),
                QIcon.Normal, QIcon.Off)
            self.volumeBtn.setIcon(volumeMutedIcon)
            self.isMuted = True

    def volume_toggle(self):
        if self.isMuted == False:
            self.volumeSlider.setValue(0)
            self.isMuted = True

        elif self.isMuted == True:
            if self.previousVolume == 0:
                self.volumeSlider.setValue(10)
            else:
                self.volumeSlider.setValue(self.previousVolume)
            self.isMuted = False


#=======================================================#

    def mousePressEvent(self, event):
        ''' remove the border around the buttons created by using tab key '''

        focused_widget = QtWidgets.QApplication.focusWidget()
        try:
            focused_widget.clearFocus()
        except:
            pass
        QMainWindow.mousePressEvent(self, event)

    def player_state(self, event):
        ''' event handler that adjust the play/pause icon '''

        if event == QMediaPlayer.PlayingState:
            pauseIcon = QIcon()
            pauseIcon.addPixmap(
                QPixmap(os.path.join(RES_PATH, "pauseIcon.svg")), QIcon.Normal,
                QIcon.Off)
            self.playBtn.setIcon(pauseIcon)
        elif event == QMediaPlayer.PausedState:
            playIcon = QIcon()
            playIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "playIcon.svg")),
                               QIcon.Normal, QIcon.Off)
            self.playBtn.setIcon(playIcon)

    def closeEvent(self, event):
        ''' event handler that take window information and save it in config before the window close '''

        # retrieve position
        xAxis = self.geometry().x()
        yAxis = self.geometry().y()

        self.data['last_position']['xPos'] = xAxis
        self.data['last_position']['yPos'] = yAxis

        # retrieve size
        width = self.width()
        height = self.height()

        self.data['last_window_size']['width'] = width
        self.data['last_window_size']['height'] = height

        # retrieve volume
        self.data['volume'] = self.mediaPlayer.volume()

        # retrieve user
        user = os.getlogin()
        self.data[
            'default_folder'] = f"C:\\Users\\{user}\\Desktop\\sputofy_songs"

        yaml_dump(self.data)

    def info_handle(self):

        info = "Sputofy\n1.0.0\n©2020 "+\
        "Sputofy is a free audio player based on the converted youtube songs made by a_str0\n\n"+\
        "Sputofy is written using python 3.x and PyQt5 modules"

        msg = QMessageBox.about(self, "About", info)
Beispiel #34
0
class MainWindow(QMainWindow, Ui_GrilHappyQMW):


    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setupUi(self)
        self.setWindowTitle('Grils HappyToo!!!')
        self.setVisible(0)
        self.preloadDialog = QDialog()
        self.screen = QDesktopWidget().screenGeometry()

        """
        gif开场动画
        """
        self.movie=QMovie(":/girl/img/showheart.gif")

        self.movie.updated.connect(self.gifFinished)
        self.movie.destroyed.connect(self.showMainWindow)
        self.movie.setSpeed(1111)
        """
        开场dialog
        """


        self.preloadDialog.setWindowFlag(Qt.FramelessWindowHint)
        self.preloadDialog.setMask(QRegion(12,12,190,190))
        self.preloadDialog.move(( self.screen.width()-200) / 2, ( self.screen.height()-200) / 2)
        gifLayout=QHBoxLayout()
        gifLabel=QLabel()

        gifLabel.setMovie(self.movie)
        gifLayout.addWidget(gifLabel)

        self.preloadDialog.setLayout(gifLayout)


        self.preloadDialog.setVisible(1)
        self.movie.start()
    def showMainWindow(self):
        self.move((self.screen.width() - self.width()) / 2, (self.screen.height() - self.height()) / 2)
        self.meidaPlayer=QMediaPlayer()

        self.playlist=QMediaPlaylist()
        self.playlist.setCurrentIndex(1);
        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile("video/Radio-Digital-Scheme-Live-Wallpaper~1.mp4")))
        self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
        self.meidaPlayer.setPlaylist(self.playlist)

        videoWidget = QVideoWidget()

        videoWidget.setAspectRatioMode(Qt.IgnoreAspectRatio)
        videoWidget.setAutoFillBackground(True)
        videoWidget.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))
        # videoWidget.setMinimumSize(videoWidget.size())

        self.meidaPlayer.setVideoOutput(videoWidget)

        self.verticalLayout_2.insertWidget(0,videoWidget)
        self.meidaPlayer.play()
        self.setVisible(1)


    def codeRain(self):

        label=QLabel(parent=self)
        s=''.join([word+'\n' for word in list("我们的每一天,都无法重来,将管理学书籍读遍依旧管不了因你悸动的心。")])
        label.setText(s)
        label.raise_()
        label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))
        label.setMaximumWidth(12)
        label.setMaximumHeight(len(s)*10)
        label.setMinimumHeight(len(s)*10)
        label.setWordWrap(True)
        label.setAlignment(Qt.AlignTop)
        label.setStyleSheet("""
        font: 87 10pt "Arial";
        color: rgb(0, 49, 79);
        """)
        label.setAttribute(Qt.WA_TranslucentBackground)
        label.show()
        ani=QPropertyAnimation(label, b'pos', self)

        ani.setDuration(10000)
        xr=random.randint(0,self.label.width())
        yr=random.randint(0,self.height())
        ani.setStartValue(QPoint(xr,-self.width()))
        ani.setEndValue(QPoint(xr,self.height()))
        ani.finished.connect(label.deleteLater)
        ani.start()




    def gifFinished(self):
        if(self.movie.currentFrameNumber()==self.movie.frameCount()-1):
            self.preloadDialog.close()
            self.movie.stop()
            self.showPreload()

    def showPreload(self):
        self.preloadDialog = QDialog()
        self.preloadImage=QPixmap(':/girl/img/preload.png')
        size = self.preloadImage.size()
        self.move(( self.screen.width() - size.width()) / 2, ( self.screen.height() - size.height()) / 2)
        self.preloadDialog.setMinimumSize(size)

        layout=QHBoxLayout()
        label=QLabel()
        label.setPixmap(self.preloadImage)

        layout.addWidget(label)

        self.preloadDialog.setLayout(layout)
        self.preloadDialog.setMask(QRegion(QRect(self.preloadImage.rect().x()+15,self.preloadImage.rect().y()+15,self.preloadImage.rect().width()-20,self.preloadImage.rect().height()-35)))

        self.timer = QTimer()
        self.preloadDialog.show()
        self.timer.timeout.connect(self.faded)
        self.timer.start(3000)
        self.timer.setInterval(10)
        self.opacity = 100

    def faded(self):
        self.preloadDialog.setWindowOpacity(self.opacity / 100)
        if self.opacity <= 0:

            self.preloadDialog.close()
            """
            开启代码雨
            """
            self.showMainWindow()
            self.codeTimer=QTimer()
            self.codeTimer.timeout.connect(self.codeRain)
            self.codeTimer.start(1000)
            self.codeTimer.setInterval(5000)
            self.timer.stop()
        else:
            self.opacity -= 13


    def closeEvent(self, a0) -> None:
        self.codeTimer.stop()
        for i in range(100,0,-1):
            self.setWindowOpacity(i/100)
            time.sleep(0.002)
Beispiel #35
0
class Player(QWidget):

    fullScreenChanged = pyqtSignal(bool)

    def __init__(self, playlist, parent=None):
        super(Player, self).__init__(parent)

        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)

        self.videoWidget = VideoWidget()
        self.player.setVideoOutput(self.videoWidget)

        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))

        self.playlistView.activated.connect(self.jump)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)

        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)

        #        self.labelHistogram = QLabel()
        #        self.labelHistogram.setText("Histogram:")
        #        self.histogram = HistogramWidget()
        #        histogramLayout = QHBoxLayout()
        #        histogramLayout.addWidget(self.labelHistogram)
        #        histogramLayout.addWidget(self.histogram, 1)

        self.probe = QVideoProbe()
        #        self.probe.videoFrameProbed.connect(self.histogram.processFrame)
        self.probe.setSource(self.player)

        openButton = QPushButton("打开", clicked=self.open)

        controls = PlayerControls()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())

        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        controls.changeRate.connect(self.player.setPlaybackRate)
        controls.stop.connect(self.videoWidget.update)

        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)

        self.fullScreenButton = QPushButton("全屏")
        self.fullScreenButton.setCheckable(True)

        self.colorButton = QPushButton("颜色选项")
        self.colorButton.setEnabled(False)
        self.colorButton.clicked.connect(self.showColorDialog)

        displayLayout = QHBoxLayout()
        displayLayout.addWidget(self.videoWidget, 2)
        displayLayout.addWidget(self.playlistView)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addStretch(1)
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        controlLayout.addWidget(self.fullScreenButton)
        controlLayout.addWidget(self.colorButton)

        layout = QVBoxLayout()
        layout.addLayout(displayLayout)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)
        #        layout.addLayout(histogramLayout)

        self.setLayout(layout)

        if not self.player.isAvailable():
            QMessageBox.warning(
                self, "Service not available",
                "The QMediaPlayer object does not have a valid service.\n"
                "Please check the media service plugins are installed.")

            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            openButton.setEnabled(False)
            self.colorButton.setEnabled(False)
            self.fullScreenButton.setEnabled(False)

        self.metaDataChanged()

        self.addToPlaylist(playlist)

    def open(self):
        fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
        self.addToPlaylist(fileNames)

    def addToPlaylist(self, fileNames):
        for name in fileNames:
            fileInfo = QFileInfo(name)
            if fileInfo.exists():
                url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(QMediaContent(url))
            else:
                url = QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(QMediaContent(url))

    def durationChanged(self, duration):
        duration /= 1000

        self.duration = duration
        self.slider.setMaximum(duration)

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.updateDurationInfo(progress)

    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo(
                "%s - %s" % (self.player.metaData(QMediaMetaData.AlbumArtist),
                             self.player.metaData(QMediaMetaData.Title)))

    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(self.playlistModel.index(
            position, 0))

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)

    def statusChanged(self, status):
        self.handleCursor(status)

        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")

    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia,
                      QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()

    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)

    def videoAvailableChanged(self, available):
        if available:
            self.fullScreenButton.clicked.connect(
                self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.connect(
                self.fullScreenButton.setChecked)

            if self.fullScreenButton.isChecked():
                self.videoWidget.setFullScreen(True)
        else:
            self.fullScreenButton.clicked.disconnect(
                self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.disconnect(
                self.fullScreenButton.setChecked)

            self.videoWidget.setFullScreen(False)

        self.colorButton.setEnabled(available)

    def setTrackInfo(self, info):
        self.trackInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def setStatusInfo(self, info):
        self.statusInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())

    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo / 3600) % 60,
                                (currentInfo / 60) % 60, currentInfo % 60,
                                (currentInfo * 1000) % 1000)
            totalTime = QTime((duration / 3600) % 60, (duration / 60) % 60,
                              duration % 60, (duration * 1000) % 1000)

            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(
                format)
        else:
            tStr = ""

        self.labelDuration.setText(tStr)

    def showColorDialog(self):
        if self.colorDialog is None:
            brightnessSlider = QSlider(Qt.Horizontal)
            brightnessSlider.setRange(-100, 100)
            brightnessSlider.setValue(self.videoWidget.brightness())
            brightnessSlider.sliderMoved.connect(
                self.videoWidget.setBrightness)
            self.videoWidget.brightnessChanged.connect(
                brightnessSlider.setValue)

            contrastSlider = QSlider(Qt.Horizontal)
            contrastSlider.setRange(-100, 100)
            contrastSlider.setValue(self.videoWidget.contrast())
            contrastSlider.sliderMoved.connect(self.videoWidget.setContrast)
            self.videoWidget.contrastChanged.connect(contrastSlider.setValue)

            hueSlider = QSlider(Qt.Horizontal)
            hueSlider.setRange(-100, 100)
            hueSlider.setValue(self.videoWidget.hue())
            hueSlider.sliderMoved.connect(self.videoWidget.setHue)
            self.videoWidget.hueChanged.connect(hueSlider.setValue)

            saturationSlider = QSlider(Qt.Horizontal)
            saturationSlider.setRange(-100, 100)
            saturationSlider.setValue(self.videoWidget.saturation())
            saturationSlider.sliderMoved.connect(
                self.videoWidget.setSaturation)
            self.videoWidget.saturationChanged.connect(
                saturationSlider.setValue)

            layout = QFormLayout()
            layout.addRow("亮度", brightnessSlider)
            layout.addRow("对比度", contrastSlider)
            layout.addRow("色调", hueSlider)
            layout.addRow("饱和度", saturationSlider)

            button = QPushButton("关闭")
            layout.addRow(button)

            self.colorDialog = QDialog(self)
            self.colorDialog.setWindowTitle("颜色选项")
            self.colorDialog.setLayout(layout)

            button.clicked.connect(self.colorDialog.close)

        self.colorDialog.show()
Beispiel #36
0
class music_play(QtWidgets.QMainWindow, Ui_Form):
    #初始化一些操作
    def __init__(self):
        super(music_play, self).__init__()  #调用该类的父类的初始化函数,完成窗口布局操作
        self.setupUi(self)
        self.setWindowTitle("VIP音乐播放器")
        self.setWindowIcon(QIcon("format.ico"))
        #self.SaveData = db()
        self.m_filepath = 'E:/MusicMedia/MusicMedia/music/'
        self.player = QMediaPlayer()
        self.PlayList = QMediaPlaylist()
        self.player.setPlaylist(self.PlayList)

    #网络歌曲的搜索模块
    def start_search(self):
        music_name = self.SongName.text()
        musician_name = self.Musician.text()
        search = search_song(self.music_name, self.musician_name)
        search.song.connect(self.search_song2)
        search_song.start()

    def search_song2(self, music_data):
        #music_data = self.SaveData.get_data(musician_name,music_name)
        #在此处构建一个url实现在线播放
        print(music_data)
        file_url = music_data[2]
        file_name = "{} - {}".format(music_data[0], music_data[1])
        self.down_music(file_url, file_name)
        self.Internet.addItem(file_name)

    #当地歌曲的加载模块
    def Load_Song(self):
        self.PlayList.clear()  #便于网络歌曲加入
        self.Local.clear()  #刷新播放列表
        list = os.listdir(self.m_filepath)
        for cur_music in list:
            self.Local.addItem(cur_music)
            self.PlayList.addMedia(
                QMediaContent(QUrl.fromLocalFile(self.m_filepath + cur_music)))

    #在线歌曲下载模块
    def down_music(self, url, name):
        header = {
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36',
        }
        response = requests.get(url, headers=header)
        with open("{}/{}.mp3".format(self.m_filepath, name), "wb") as file:
            file.write(response.content)

    #用户自定义歌曲模块
    def custom_current_music(self):
        cur_music = self.Local.currentItem().text()
        self.CurMusic.setText(cur_music)
        item = self.Local.currentRow()
        self.PlayList.setCurrentIndex(item)
        self.player.stop()  #停止上一首歌
        self.player.play()  #开始播放当前指定的歌曲

    #设置音乐播放模式模块
    def music_Mode(self):
        self.PlayList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)  #单曲循环
        self.PlayList.setPlaybackMode(QMediaPlaylist.Random)  # 随机播放
        self.PlayList.setPlaybackMode(QMediaPlaylist.Sequential)  # 顺序播放

    #重写窗口paintEvent函数
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(self.rect(), QPixmap("image/background.jpg"))
Beispiel #37
0
class Player(QMediaPlayer):

    player = None  # 播放器
    playList = None  # 播放列表
    source = None  # 音频路径
    content = None  # 音频内容
    musicSource = []  # 音频路劲列表
    MUSIC_PATH = './BackgroundMusic'

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

        self.getMusicSource()
        self.initPlayer()
        self.createPlayList()
        self.player.play()

    def getMusicSource(self):
        """获取音乐文件路径"""
        for src in os.listdir(self.MUSIC_PATH):
            self.musicSource.append('{}/{}'.format(self.MUSIC_PATH, src))

    def initPlayer(self):
        """初始化播放器"""
        self.player = QMediaPlayer(self)  # 创建播放器
        self.playList = QMediaPlaylist(self.player)  # 播放列表
        self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)  # 播放模式
        """
        QMediaPlaylist.CurrentItemOnce       0->播放一次
        QMediaPlaylist.CurrentItemInLoop     1->单曲循环
        QMediaPlaylist.Sequential            2->顺序播放
        QMediaPlaylist.Loop                  3->列表循环
        QMediaPlaylist.Random                4->随机播放
        """

    def createPlayList(self):
        """创建播放列表"""
        self.playList.clear()
        for path in self.musicSource:
            self.content = QMediaContent(QUrl.fromLocalFile(path))
            self.playList.addMedia(self.content)
        self.player.setPlaylist(self.playList)  # 创建播放列表
        # print(self.player.currentMedia().canonicalUrl().path())  # 输出音乐文件路径

    def nextMusic(self):
        """播放下一首音乐"""
        if self.playList.currentIndex() == len(self.musicSource) - 1:
            index = 0
        else:
            index = self.playList.currentIndex() + 1

        self.playList.setCurrentIndex(index)
        self.player.play()

    def previousMusic(self):
        """播放前一首音乐"""
        if self.playList.currentIndex() == 0:
            index = len(self.musicSource) - 1
        else:
            index = self.playList.currentIndex() - 1

        self.playList.setCurrentIndex(index)
        self.player.play()

    def mute(self):
        """静音"""
        self.player.setMuted(True)

    def cancelMute(self):
        """取消静音"""
        self.player.setMuted(False)
Beispiel #38
0
class VKwindow(QWidget):

    def __init__(self, vkapi):
        super().__init__()
        self.vk = vkapi
        self.initUI()

    def initUI(self):
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        vbox = QVBoxLayout()
        hbox = QHBoxLayout()
        self.setGeometry(300, 300, 290, 150)
        self.slider = QSlider(Qt.Horizontal)
        self.playBtn = QPushButton('►')
        self.nextBtn = QPushButton('>')
        self.prevBtn = QPushButton('<')

        self.nextBtn.clicked.connect(self.nextSong)
        self.prevBtn.clicked.connect(self.prevSong)

        self.playBtn.clicked.connect(self.playSong)
        self.setWindowTitle('VK music')
        self.list = QListWidget(self)
        self.list.currentItemChanged.connect(self.selectSong)

        for track in self.vk.method('audio.get').get('items'):
            self.list.addItem(SongWidgetItem(track))
            self.playlist.addMedia(QMediaContent(QUrl(track['url'])))

        hbox.addWidget(self.prevBtn)
        hbox.addWidget(self.playBtn)
        hbox.addWidget(self.nextBtn)
        hbox.addWidget(self.slider)

        self.player.setPlaylist(self.playlist)
        self.player.positionChanged.connect(self.setPosition)
        vbox.addWidget(self.list)
        vbox.addLayout(hbox)
        self.setLayout(vbox)
        self.show()

    def selectSong(self, curr, prev):
        self.currentTrack = curr
        print(curr.getArtist())

    def playSong(self):
        print(self.currentTrack.getArtist())
        print(self.list.currentRow())
        if self.player.state() == QMediaPlayer.PlayingState and self.list.currentRow() == self.playlist.currentIndex():
            self.player.pause()
            return
        elif self.player.state() == QMediaPlayer.PausedState:
            self.player.play()
            return
        self.playlist.setCurrentIndex(self.list.currentRow())
        self.slider.setTickInterval(self.player.duration())
        self.player.play()

    def setPosition(self, pos):
        print(pos)
        self.slider.setTickPosition(pos)

    def nextSong(self):
        tmp = self.list.currentRow()
        size = self.list.count()
        tmp = (tmp + 1) % size
        self.list.setCurrentRow(tmp)
        self.playlist.setCurrentIndex(tmp)
        self.player.play()

    def prevSong(self):
        tmp = self.list.currentRow()
        size = self.list.count()
        tmp = (tmp - 1) % size
        self.list.setCurrentRow(tmp)
        self.playlist.setCurrentIndex(tmp)
        self.player.play()
Beispiel #39
-1
class Player(QWidget):

    fullScreenChanged = pyqtSignal(bool)

    def __init__(self, playlist, parent=None):
        super(Player, self).__init__(parent)

        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)

        self.videoWidget = VideoWidget()
        self.player.setVideoOutput(self.videoWidget)

        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(self.playlist.currentIndex(), 0))

        self.playlistView.activated.connect(self.jump)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)

        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)

        self.labelHistogram = QLabel()
        self.labelHistogram.setText("Histogram:")
        self.histogram = HistogramWidget()
        histogramLayout = QHBoxLayout()
        histogramLayout.addWidget(self.labelHistogram)
        histogramLayout.addWidget(self.histogram, 1)

        self.probe = QVideoProbe()
        self.probe.videoFrameProbed.connect(self.histogram.processFrame)
        self.probe.setSource(self.player)

        openButton = QPushButton("Open", clicked=self.open)

        controls = PlayerControls()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())

        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        controls.changeRate.connect(self.player.setPlaybackRate)
        controls.stop.connect(self.videoWidget.update)

        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)

        self.fullScreenButton = QPushButton("FullScreen")
        self.fullScreenButton.setCheckable(True)

        self.colorButton = QPushButton("Color Options...")
        self.colorButton.setEnabled(False)
        self.colorButton.clicked.connect(self.showColorDialog)

        displayLayout = QHBoxLayout()
        displayLayout.addWidget(self.videoWidget, 2)
        displayLayout.addWidget(self.playlistView)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addStretch(1)
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        controlLayout.addWidget(self.fullScreenButton)
        controlLayout.addWidget(self.colorButton)

        layout = QVBoxLayout()
        layout.addLayout(displayLayout)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)
        layout.addLayout(histogramLayout)

        self.setLayout(layout)

        if not self.player.isAvailable():
            QMessageBox.warning(self, "Service not available",
                    "The QMediaPlayer object does not have a valid service.\n"
                    "Please check the media service plugins are installed.")

            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            openButton.setEnabled(False)
            self.colorButton.setEnabled(False)
            self.fullScreenButton.setEnabled(False)

        self.metaDataChanged()

        self.addToPlaylist(playlist)

    def open(self):
        fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
        self.addToPlaylist(fileNames)

    def addToPlaylist(self, fileNames):
        for name in fileNames:
            fileInfo = QFileInfo(name)
            if fileInfo.exists():
                url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(QMediaContent(url))
            else:
                url = QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(QMediaContent(url))

    def durationChanged(self, duration):
        duration /= 1000

        self.duration = duration
        self.slider.setMaximum(duration)

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.updateDurationInfo(progress)

    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo("%s - %s" % (
                    self.player.metaData(QMediaMetaData.AlbumArtist),
                    self.player.metaData(QMediaMetaData.Title)))

    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(position, 0))

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)

    def statusChanged(self, status):
        self.handleCursor(status)

        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")

    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()

    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)

    def videoAvailableChanged(self, available):
        if available:
            self.fullScreenButton.clicked.connect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.connect(
                    self.fullScreenButton.setChecked)

            if self.fullScreenButton.isChecked():
                self.videoWidget.setFullScreen(True)
        else:
            self.fullScreenButton.clicked.disconnect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.disconnect(
                    self.fullScreenButton.setChecked)

            self.videoWidget.setFullScreen(False)

        self.colorButton.setEnabled(available)

    def setTrackInfo(self, info):
        self.trackInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def setStatusInfo(self, info):
        self.statusInfo = info

        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)

    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())

    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60,
                    currentInfo%60, (currentInfo*1000)%1000)
            totalTime = QTime((duration/3600)%60, (duration/60)%60,
                    duration%60, (duration*1000)%1000);

            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(format)
        else:
            tStr = ""

        self.labelDuration.setText(tStr)

    def showColorDialog(self):
        if self.colorDialog is None:
            brightnessSlider = QSlider(Qt.Horizontal)
            brightnessSlider.setRange(-100, 100)
            brightnessSlider.setValue(self.videoWidget.brightness())
            brightnessSlider.sliderMoved.connect(
                    self.videoWidget.setBrightness)
            self.videoWidget.brightnessChanged.connect(
                    brightnessSlider.setValue)

            contrastSlider = QSlider(Qt.Horizontal)
            contrastSlider.setRange(-100, 100)
            contrastSlider.setValue(self.videoWidget.contrast())
            contrastSlider.sliderMoved.connect(self.videoWidget.setContrast)
            self.videoWidget.contrastChanged.connect(contrastSlider.setValue)

            hueSlider = QSlider(Qt.Horizontal)
            hueSlider.setRange(-100, 100)
            hueSlider.setValue(self.videoWidget.hue())
            hueSlider.sliderMoved.connect(self.videoWidget.setHue)
            self.videoWidget.hueChanged.connect(hueSlider.setValue)

            saturationSlider = QSlider(Qt.Horizontal)
            saturationSlider.setRange(-100, 100)
            saturationSlider.setValue(self.videoWidget.saturation())
            saturationSlider.sliderMoved.connect(
                    self.videoWidget.setSaturation)
            self.videoWidget.saturationChanged.connect(
                    saturationSlider.setValue)

            layout = QFormLayout()
            layout.addRow("Brightness", brightnessSlider)
            layout.addRow("Contrast", contrastSlider)
            layout.addRow("Hue", hueSlider)
            layout.addRow("Saturation", saturationSlider)

            button = QPushButton("Close")
            layout.addRow(button)

            self.colorDialog = QDialog(self)
            self.colorDialog.setWindowTitle("Color Options")
            self.colorDialog.setLayout(layout)

            button.clicked.connect(self.colorDialog.close)

        self.colorDialog.show()