vlcframe.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import time
  2. from collections import deque
  3. import vlc
  4. from PyQt5 import QtWidgets, QtGui, QtCore
  5. from PyQt5.QtCore import pyqtSignal
  6. from PyQt5.QtGui import QIcon
  7. from ui.qt.widgets.vlcframe_ui import Ui_VlcFrame
  8. class VlcFrame(QtWidgets.QFrame):
  9. DEFAULT_VOLUME = 50
  10. trackStarted = pyqtSignal(object)
  11. trackEnded = pyqtSignal(object)
  12. playlistStarted = pyqtSignal(object)
  13. playlistEnded = pyqtSignal(object)
  14. def __init__(self, parent=None):
  15. super().__init__(parent)
  16. self._media = None
  17. self._is_paused = True
  18. self.is_muted = False
  19. self.volume = self.DEFAULT_VOLUME
  20. self.playlist = None
  21. self.tracks = deque()
  22. self.current_index = None
  23. # Create a basic vlc instance
  24. self._instance = vlc.Instance()
  25. # Create an empty vlc media player
  26. self._mediaplayer = self._instance.media_player_new()
  27. self.createWidgets()
  28. def createWidgets(self):
  29. self.ui = Ui_VlcFrame()
  30. self.ui.setupUi(self)
  31. self.ui.progressionSlider.sliderMoved.connect(self.set_position)
  32. self.ui.progressionSlider.sliderPressed.connect(self.set_position)
  33. self.ui.progressionSlider.positionClicked.connect(self.set_position)
  34. self.ui.btnPlayPause.clicked.connect(self.play_pause)
  35. self.ui.volumeSlider.setValue(self.volume)
  36. self._mediaplayer.audio_set_volume(self.volume)
  37. self.ui.volumeSlider.valueChanged.connect(self.set_volume)
  38. self.ui.volumeSlider.positionClicked.connect(self.set_volume)
  39. self.ui.btnMute.clicked.connect(self.toggle_muted)
  40. self.ui.btnPrevious.clicked.connect(self.go_to_previous_track)
  41. self.ui.btnNext.clicked.connect(self.go_to_next_track)
  42. self.timer = QtCore.QTimer(self)
  43. self.timer.setInterval(100)
  44. self.timer.timeout.connect(self.update_ui)
  45. self.setEnabled(False)
  46. def load_playlist(self, playlist, tracks, start_at=0):
  47. self.tracks = deque(tracks)
  48. self.current_index = start_at
  49. self.playlist = playlist
  50. def load_track(self, track):
  51. self.tracks = deque([track])
  52. self.current_index = 0
  53. self.playlist = None
  54. @property
  55. def currentTrack(self):
  56. if self.current_index is None:
  57. return None
  58. return self.tracks[self.current_index]
  59. def play(self):
  60. track = self.currentTrack
  61. self._media = self._instance.media_new(track.path)
  62. # Put the media in the media player
  63. self._mediaplayer.set_media(self._media)
  64. # Parse the metadata of the file
  65. self._media.parse()
  66. self.play_pause()
  67. self.setEnabled(True)
  68. if self.playlist:
  69. self.playlistStarted.emit(self.playlist)
  70. self.trackStarted.emit(self.currentTrack)
  71. self.refresh_ui()
  72. def refresh_ui(self):
  73. self.ui.btnPrevious.setEnabled(
  74. len(self.tracks) > 0 and self.current_index > 0
  75. )
  76. self.ui.btnNext.setEnabled(
  77. len(self.tracks) > 0 and self.current_index < (len(self.tracks) - 1)
  78. )
  79. # Set the title of the track
  80. self.ui.lblTrack.setText(f"{self.currentTrack.artist or '(artiste inconnu)'} - {self.currentTrack.title}")
  81. self.ui.lblDuration.setText(self.currentTrack.literal_duration())
  82. def play_pause(self):
  83. """Toggle play/pause status
  84. """
  85. if self._mediaplayer.is_playing():
  86. self._mediaplayer.pause()
  87. self.ui.btnPlayPause.setIcon(QIcon(":/img/rsc/play.png"))
  88. self._is_paused = True
  89. self.timer.stop()
  90. else:
  91. if self._mediaplayer.play() == -1:
  92. return
  93. self._mediaplayer.play()
  94. self.ui.btnPlayPause.setIcon(QIcon(":/img/rsc/pause.png"))
  95. self.timer.start()
  96. self._is_paused = False
  97. def stop(self):
  98. """Stop player
  99. """
  100. self._mediaplayer.stop()
  101. self.ui.btnPlayPause.setIcon(QIcon(":/img/rsc/play.png"))
  102. self.ui.progressionSlider.setSliderPosition(0)
  103. if self.playlist:
  104. self.playlistEnded.emit(self.playlist)
  105. self.trackEnded.emit(self.currentTrack)
  106. if len(self.tracks) > 0 and self.current_index < (len(self.tracks) - 1):
  107. self.current_index += 1
  108. self.play()
  109. else:
  110. self.current_index = None
  111. def go_to_previous_track(self):
  112. if not len(self.tracks) > 0 or self.current_index == 0:
  113. return
  114. self.current_index -= 1
  115. self.play()
  116. def go_to_next_track(self):
  117. if not len(self.tracks) > 0 or self.current_index == (len(self.tracks) - 1):
  118. return
  119. self.current_index += 1
  120. self.play()
  121. def update_ui(self):
  122. """Updates the user interface"""
  123. # Set the slider's position to its corresponding media position
  124. # Note that the setValue function only takes values of type int,
  125. # so we must first convert the corresponding media position.
  126. media_pos = int(self._mediaplayer.get_position() * 1000)
  127. self.ui.progressionSlider.setValue(media_pos)
  128. if self.currentTrack:
  129. time_pos = media_pos * self.currentTrack.duration // 1000
  130. self.ui.lblPosition.setText(time.strftime("%M:%S", time.gmtime(time_pos)))
  131. # No need to call this function if nothing is played
  132. if not self._mediaplayer.is_playing():
  133. self.timer.stop()
  134. # After the video finished, the play button stills shows "Pause",
  135. # which is not the desired behavior of a media player.
  136. # This fixes that "bug".
  137. if not self._is_paused:
  138. self.stop()
  139. def set_volume(self, volume):
  140. """Set the volume
  141. """
  142. # if muted: unmute
  143. if self.is_muted:
  144. self.toggle_muted()
  145. self._mediaplayer.audio_set_volume(volume)
  146. self.volume = volume
  147. self.ui.volumeSlider.setValue(volume)
  148. def set_position(self, position=None):
  149. """Set the movie position according to the position slider.
  150. """
  151. # The vlc MediaPlayer needs a float value between 0 and 1, Qt uses
  152. # integer variables, so you need a factor; the higher the factor, the
  153. # more precise are the results (1000 should suffice).
  154. # if paused: resume
  155. if self._is_paused:
  156. self.play_pause()
  157. # Set the media position to where the slider was dragged
  158. self.timer.stop()
  159. pos = self.ui.progressionSlider.value()
  160. self._mediaplayer.set_position(pos / 1000.0)
  161. self.timer.start()
  162. def toggle_muted(self):
  163. if not self.is_muted:
  164. self._mediaplayer.audio_set_volume(0)
  165. self.ui.btnMute.setIcon(QIcon(":/img/rsc/mute.png"))
  166. self.is_muted = True
  167. else:
  168. self._mediaplayer.audio_set_volume(self.volume)
  169. self.ui.btnMute.setIcon(QIcon(":/img/rsc/volume.png"))
  170. self.is_muted = False
  171. def current(self):
  172. return self.currentTrack