def test_skip_song(self): """Test to skip a playlist entry """ with self.get_instance() as (vlc_player, _, _): # mock the callbacks vlc_player.set_callback("started_transition", MagicMock()) vlc_player.set_callback("started_song", MagicMock()) vlc_player.set_callback("finished", MagicMock()) # pre assertions self.assertIsNone(vlc_player.playlist_entry) self.assertIsNone(vlc_player.player.get_media()) self.assertEqual(vlc_player.player.get_state(), vlc.State.NothingSpecial) # request initial playlist entry to play vlc_player.set_playlist_entry(self.playlist_entry1) # wait for the media to start self.wait_is_playing(vlc_player, "song") # post assertions for song self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) self.assertIsNotNone(vlc_player.playlist_entry) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, self.song1_path) # request first playlist entry to stop vlc_player.skip() # check the song is stopped accordingly self.assertIsNone(vlc_player.playlist_entry) vlc_player.callbacks["finished"].assert_called_with( self.playlist_entry1["id"]) # request second playlist entry to play vlc_player.set_playlist_entry(self.playlist_entry2) # wait for the media to start self.wait_is_playing(vlc_player, "song") # post assertions for song self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) self.assertIsNotNone(vlc_player.playlist_entry) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, self.song2_path)
def test_mrl_to_path_posix(self): """Test to convert MRL to path for POSIX """ path = mrl_to_path("file:///home/username/directory/file%20name.ext") self.assertEqual( path, Path("/home").normpath() / "username" / "directory" / "file name.ext")
def test_mrl_to_path_windows(self): """Test to convert MRL to path for Windows """ path = mrl_to_path( "file:///C:/Users/username/directory/file%20name.ext") self.assertEqual( path, Path("C:/Users").normpath() / "username" / "directory" / "file name.ext", )
def test_play_playlist_entry_instrumental_track_avi(self): """Test to play a playlist entry AVI file using instrumental track This type of file is known to have data in the key we use to store information in media. """ # request to use instrumental track self.playlist_entry3["use_instrumental"] = True with self.get_instance() as (vlc_player, _, _): # mock the callbacks vlc_player.set_callback("started_transition", MagicMock()) vlc_player.set_callback("started_song", MagicMock()) # pre assertions self.assertIsNone(vlc_player.playlist_entry) self.assertIsNone(vlc_player.player.get_media()) self.assertEqual(vlc_player.player.get_state(), vlc.State.NothingSpecial) # call the method vlc_player.set_playlist_entry(self.playlist_entry3) # wait for the song to start self.wait_is_playing(vlc_player, "song") # post assertions for song self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, self.song3_path) # check audio track track = vlc_player.player.audio_get_track() self.assertEqual(track, 2) # assert the started song callback has been called vlc_player.callbacks["started_song"].assert_called_with( self.playlist_entry3["id"])
def test_play_playlist_entry_instrumental_file(self): """Test to play a playlist entry using instrumental file """ # request to use instrumental file self.playlist_entry1["song"]["file_path"] = self.song2_path self.playlist_entry1["use_instrumental"] = True with self.get_instance() as (vlc_player, _, _): # mock the callbacks vlc_player.set_callback("started_transition", MagicMock()) vlc_player.set_callback("started_song", MagicMock()) # pre assertions self.assertIsNone(vlc_player.playlist_entry) self.assertIsNone(vlc_player.player.get_media()) self.assertEqual(vlc_player.player.get_state(), vlc.State.NothingSpecial) # call the method vlc_player.set_playlist_entry(self.playlist_entry1) # wait for the song to start self.wait_is_playing(vlc_player, "song") # post assertions for song self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, self.song2_path) # check audio track track = vlc_player.player.audio_get_track() self.assertEqual(track, 4) # assert the started song callback has been called vlc_player.callbacks["started_song"].assert_called_with( self.playlist_entry1["id"])
def handle_end_reached(self, event): """Callback called when a media ends. This happens when: - A transition screen ends, leading to playing the actual song; - A song ends normally, leading to calling the callback `callbacks["finished"]`; - An idle screen ends, leading to reloop it. A new thread is created in any case. Args: event (vlc.EventType): VLC event object. """ logger.debug("End reached callback called") # the transition screen has finished, request to play the song itself if self.is_playing_this("transition"): logger.debug("Will play '{}'".format( mrl_to_path(self.playlist_entry_data["song"].media.get_mrl()))) thread = self.create_thread(target=self.play, args=("song", )) thread.start() return # the media has finished, so call the according callback and clean memory if self.is_playing_this("song"): self.callbacks["finished"](self.playlist_entry["id"]) self.clear_playlist_entry() return # the idle screen has finished, simply restart it if self.is_playing_this("idle"): thread = self.create_thread(target=self.play, args=("idle", )) thread.start() return # if no state can be determined, raise an error raise InvalidStateError("End reached on an undeterminated state")
def test_play_idle(self): """Test to display the idle screen """ with self.get_instance() as (vlc_player, temp, _): # pre assertions self.assertIsNone(vlc_player.player.get_media()) self.assertEqual(vlc_player.player.get_state(), vlc.State.NothingSpecial) # call the method vlc_player.play("idle") # wait for the idle screen to start self.wait_is_playing(vlc_player, "idle") # post assertions self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) self.assertIsNotNone(vlc_player.player.get_media()) media = vlc_player.player.get_media() file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, temp / IDLE_BG_NAME)
def handle_encountered_error(self, event): """Callback called when error occurs There is no way to capture error message, so only a generic error message is provided. Call the callbacks `callbacks["finished"]` and `callbacks["error"]` Args: event (vlc.EventType): VLC event object. """ logger.debug("Error callback called") # the current song media has an error, skip the song, log the error and # call error callback if self.is_playing_this("song"): logger.error("Unable to play '%s'", mrl_to_path(self.player.get_media().get_mrl())) self.callbacks["error"](self.playlist_entry["id"], "Unable to play current song") self.skip() return
def test_play_playlist_entry(self): """Test to play a playlist entry First, the transition screen is played, then the song itself. """ with self.get_instance() as (vlc_player, temp, _): # mock the callbacks vlc_player.set_callback("started_transition", MagicMock()) vlc_player.set_callback("started_song", MagicMock()) # pre assertions self.assertIsNone(vlc_player.playlist_entry) self.assertIsNone(vlc_player.player.get_media()) self.assertEqual(vlc_player.player.get_state(), vlc.State.NothingSpecial) # call the method vlc_player.set_playlist_entry(self.playlist_entry1, autoplay=False) # check media did not started self.assertFalse( vlc_player.playlist_entry_data["transition"].started) self.assertFalse(vlc_player.playlist_entry_data["song"].started) # start playing vlc_player.play("transition") # wait for the transition screen to start self.wait_is_playing(vlc_player, "transition") # post assertions for transition screen self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) self.assertIsNotNone(vlc_player.playlist_entry) # check transition media only started self.assertTrue( vlc_player.playlist_entry_data["transition"].started) self.assertFalse(vlc_player.playlist_entry_data["song"].started) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, temp / TRANSITION_BG_NAME) # check there is no audio track track = vlc_player.player.audio_get_track() self.assertEqual(track, -1) # TODO check which subtitle file is read # seems impossible to do for now # assert the started transition callback has been called vlc_player.callbacks["started_transition"].assert_called_with( self.playlist_entry1["id"]) # wait for the media to start self.wait_is_playing(vlc_player, "song") # post assertions for song self.assertEqual(vlc_player.player.get_state(), vlc.State.Playing) # check song media also started self.assertTrue( vlc_player.playlist_entry_data["transition"].started) self.assertTrue(vlc_player.playlist_entry_data["song"].started) # check media exists media = vlc_player.player.get_media() self.assertIsNotNone(media) # check media path file_path = mrl_to_path(media.get_mrl()) self.assertEqual(file_path, self.song1_path) # check audio track track = vlc_player.player.audio_get_track() self.assertEqual(track, 1) # assert the started song callback has been called vlc_player.callbacks["started_song"].assert_called_with( self.playlist_entry1["id"])
def handle_playing(self, event): """Callback called when playing has started. This happens when: - The player resumes from pause; - A transition screen starts; - A song starts, leading to set the requested audio track to play; - An idle screen starts. Args: event (vlc.EventType): VLC event object. """ logger.debug("Playing callback called") # the media or the transition is resuming from pause # it is pretty hard to detect this case, as we do not have a previous # state in memory # we rely on a specific flag stored in `playlist_entry_data` Media # objects which is set to True when the corresponding media starts if (self.is_playing_this("transition") and self.playlist_entry_data["transition"].started or self.is_playing_this("song") and self.playlist_entry_data["song"].started): self.callbacks["resumed"](self.playlist_entry["id"], self.get_timing()) logger.debug("Resumed play") return # the transition screen starts to play if self.is_playing_this("transition"): self.callbacks["started_transition"](self.playlist_entry["id"]) self.playlist_entry_data["transition"].started = True logger.info("Playing transition for '%s'", self.playlist_entry["song"]["title"]) return # the song starts to play if self.is_playing_this("song"): self.callbacks["started_song"](self.playlist_entry["id"]) # set instrumental track if necessary audio_track_id = self.playlist_entry_data["song"].audio_track_id if audio_track_id is not None: logger.debug("Requesting to play audio track %i", audio_track_id) self.player.audio_set_track(audio_track_id) self.playlist_entry_data["song"].started = True logger.info( "Now playing '%s' ('%s')", self.playlist_entry["song"]["title"], mrl_to_path(self.player.get_media().get_mrl()), ) return # the idle screen starts to play if self.is_playing_this("idle"): logger.debug("Playing idle screen") return raise InvalidStateError("Playing on an undeterminated state")