Пример #1
0
 def test_get_track_path_raises_value_error_if_root_directory_unknown(
         self, example_group):
     """
     If the `file` attribute of a `Track` is not the link to a YouTube video, return the file path. The file path
     consists of the root directory combined with the filename. If there is no root directory, raise a `ValueError`.
     """
     example_group.directory = None
     track_list = example_group.track_lists[0]
     track_list.directory = None
     track = track_list.tracks[0]
     track.file = "file.mp3"
     with pytest.raises(ValueError):
         utils.get_track_path(example_group, track_list, track)
Пример #2
0
 def test_get_track_path_raises_value_error_if_path_is_not_existing_file(
         self, example_group, monkeypatch):
     """
     If the `file` attribute of a `Track` is not the link to a YouTube video, return the file path. But if the file
     path does not refer to an existing file, raise a `ValueError`.
     """
     track_list = example_group.track_lists[0]
     track = track_list.tracks[0]
     track.file = "file.mp3"
     monkeypatch.setattr(
         "src.music.utils.get_track_list_root_directory",
         MagicMock(return_value="root/dir/"))  # non-existing dir
     with pytest.raises(ValueError):
         utils.get_track_path(example_group, track_list, track)
Пример #3
0
 def check_tracks_do_exist(self, groups: Iterable[MusicGroup], default_dir):
     """
     Iterates through every track and attempts to get its path. Logs any error and re-raises any exception.
     """
     logger.info("Checking that tracks point to valid paths...")
     for group, track_list, track in utils.music_tuple_generator(groups):
         try:
             utils.get_track_path(group,
                                  track_list,
                                  track,
                                  default_dir=default_dir)
         except Exception as ex:
             logger.error(
                 f"Track '{track.file}' does not point to a valid path.")
             raise ex
     logger.info("Success! All tracks point to valid paths.")
Пример #4
0
 async def _play_track(self, group: MusicGroup, track_list: TrackList, track: Track):
     """
     Plays the given track from the given track list and group.
     """
     try:
         path = utils.get_track_path(group, track_list, track, default_dir=self.directory)
     except ValueError:
         logger.error(f"Failed to play '{track.file}'.")
         raise asyncio.CancelledError()
     self._current_player = vlc.MediaPlayer(vlc.Instance("--novideo"), path)
     self._current_player.audio_set_volume(0)
     success = self._current_player.play()
     if success == -1:
         logger.error(f"Failed to play {path}")
         raise asyncio.CancelledError
     if track.start_at is not None:
         self._current_player.set_time(track.start_at)
     logger.info(f"Now Playing: {track.file}")
     await self._wait_for_current_player_to_be_playing()
     await self._set_master_volume(self.volume, set_global=False)
     while self._current_player.is_playing():
         try:
             if track.end_at is not None and self._current_player.get_time() >= track.end_at:
                 self._current_player.stop()
             await asyncio.sleep(self.SLEEP_TIME)
         except asyncio.CancelledError:
             logger.debug(f"Received cancellation request for {track.file}")
             await self._set_master_volume(0, set_global=False)
             raise
     logger.info(f"Finished playing: {track.file}")
Пример #5
0
 async def _play_track(self, discord_context, request, group, track_list,
                       tracks_to_play):
     """
     Plays the given track from the given track list and group.
     """
     if self.is_cancelled:
         self._currently_playing = None
         self.is_cancelled = False
         logger.info(f"Cancelled '{track_list.name}'")
         await self.callback_handler(action=MusicActions.STOP,
                                     request=request,
                                     state=self.currently_playing)
         return
     if len(tracks_to_play) == 0:
         if not track_list.loop:
             self._currently_playing = None
             logger.info(f"Finished '{track_list.name}'")
             await self.callback_handler(action=MusicActions.FINISH,
                                         request=request,
                                         state=self.currently_playing)
             if track_list.next is None:
                 return
             next_group_index, next_track_list_index = self._get_track_list_index_from_name(
                 track_list.next)
             if next_group_index is None or next_track_list_index is None:
                 logger.error(
                     f"Could not find a track list named '{track_list.next}'"
                 )
                 return
             await self.play_track_list(discord_context, request,
                                        next_group_index,
                                        next_track_list_index)
             return
         tracks_to_play = track_list.tracks
     track = tracks_to_play.pop(0)
     path = utils.get_track_path(group,
                                 track_list,
                                 track,
                                 default_dir=self.directory)
     ffmpeg_before_options = ""
     if track.start_at is not None:
         ffmpeg_before_options += f" -ss {track.start_at}ms"
     if track.end_at is not None:
         ffmpeg_before_options += f" -to {track.end_at}ms"
     logger.info(f"Now Playing: {track.file}")
     source = discord.PCMVolumeTransformer(
         discord.FFmpegPCMAudio(path, before_options=ffmpeg_before_options))
     volume = (self.volume * track_list.volume) // 100
     source.volume = volume / 100
     discord_context.voice_client.play(
         source,
         after=lambda e: logger.error(f"Player error: {e}")
         if e else asyncio.run_coroutine_threadsafe(
             self._play_track(discord_context, request, group, track_list,
                              tracks_to_play), self.event_loop),
     )
Пример #6
0
 def test_get_track_path_returns_file_path_if_track_is_file(
         self, example_group, monkeypatch):
     """
     If the `file` attribute of a `Track` is not the link to a YouTube video, return the file path.
     """
     monkeypatch.setattr("src.music.utils.get_track_list_root_directory",
                         MagicMock(return_value="root/dir/"))
     monkeypatch.setattr("src.music.utils.os.path.isfile", lambda x: True)
     track_list = example_group.track_lists[0]
     track = track_list.tracks[0]
     track.file = "file.mp3"
     path = utils.get_track_path(example_group, track_list, track)
     assert path == "root/dir/file.mp3"
Пример #7
0
 def test_get_track_path_returns_audio_url_if_track_is_youtube_link(
         self, example_group, monkeypatch):
     """
     If the `file` attribute of a `Track` is the link to a YouTube video, return the url of its audio stream.
     """
     track_list = example_group.track_lists[0]
     track = track_list.tracks[0]
     track.file = "https://www.youtube.com/watch?v=jIxas0a-KgM"
     get_audio_stream_mock = MagicMock(return_value="some-url")
     monkeypatch.setattr("src.music.utils.get_audio_stream",
                         get_audio_stream_mock)
     path = utils.get_track_path(example_group, track_list, track)
     assert path == "some-url"
Пример #8
0
 def check_tracks_do_exist(self, groups: Iterable[MusicGroup], default_dir):
     """
     Iterates through every track and attempts to get its path. Logs any error and re-raises any exception.
     """
     logger.info("Checking that tracks point to valid paths...")
     valid_youtube_tracks = collections.deque(cache.load_list(self.VALID_YOUTUBE_TRACKS_CACHE), maxlen=100)
     for group, track_list, track in utils.music_tuple_generator(groups):
         try:
             if not track.is_youtube_link:
                 utils.get_track_path(group, track_list, track, default_dir=default_dir)
             else:  # This is much faster to check if the link is a YouTube video
                 if track.file in valid_youtube_tracks:
                     continue
                 url = f"https://www.youtube.com/oembed?url={track.file}"
                 result = requests.get(url)
                 if result.status_code != 200:
                     raise RuntimeError(f"The url '{track.file}' is not a valid YouTube video.")
                 valid_youtube_tracks.append(track.file)
         except Exception as ex:
             logger.error(f"Track '{track.file}' does not point to a valid path.")
             raise ex
     cache.save_list(list(valid_youtube_tracks), self.VALID_YOUTUBE_TRACKS_CACHE)
     logger.info("Success! All tracks point to valid paths.")