def test_episode_prepare__ffmpeg_error__fail(self, mocked_process_hook, mocked_run): mocked_run.side_effect = subprocess.CalledProcessError( 1, [], stderr=b"FFMPEG oops") with pytest.raises(FFMPegPreparationError) as err: ffmpeg_preparation(self.filename) assert not os.path.exists( self.tmp_filename), f"File wasn't removed: {self.tmp_filename}" assert err.value.details == ( "FFMPEG failed with errors: " "Command '[]' returned non-zero exit status 1.") self.assert_hooks_calls( mocked_process_hook, finish_call=dict(status=EpisodeStatus.ERROR, filename=self.filename), )
def test_episode_prepare__io_error__fail(self, mocked_process_hook, mocked_run): mocked_run.return_value = CompletedProcess([], returncode=0, stdout=b"Success") os.remove(self.tmp_filename) with pytest.raises(FFMPegPreparationError) as err: ffmpeg_preparation(self.filename) assert err.value.details == ( f"Failed to rename/remove tmp file: Prepared file {self.tmp_filename} wasn't created" ) self.assert_hooks_calls( mocked_process_hook, finish_call=dict(status=EpisodeStatus.ERROR, filename=self.filename), )
def test_episode_prepare__ok(self, mocked_process_hook, mocked_run, mocked_process): mocked_run.return_value = CompletedProcess([], returncode=0, stdout=b"Success") ffmpeg_preparation(self.filename) self.assert_called_with( mocked_run, [ "ffmpeg", "-y", "-i", self.src_path, "-vn", "-acodec", "libmp3lame", "-q:a", "5", self.tmp_filename, ], check=True, timeout=settings.FFMPEG_TIMEOUT, ) mocked_process.target_class.__init__.assert_called_with( mocked_process.target_obj, target=post_processing_process_hook, kwargs={ "filename": self.filename, "target_path": self.tmp_filename, "total_bytes": 4 }, ) assert not os.path.exists( self.tmp_filename), f"File wasn't removed: {self.tmp_filename}" self.assert_hooks_calls( mocked_process_hook, finish_call=dict( status=EpisodeStatus.DL_EPISODE_POSTPROCESSING, filename=self.filename, total_bytes=len(b"data"), processed_bytes=len(b"data"), ), )
async def _process_file(episode: Episode, result_filename: str): """ Postprocessing for downloaded audio file """ logger.info("=== [%s] POST PROCESSING === ", episode.source_id) youtube_utils.ffmpeg_preparation(result_filename) logger.info("=== [%s] POST PROCESSING was done === ", episode.source_id)
def download_episode(youtube_link: str, episode_id: int): """ Allows to download youtube video and recreate specific rss (by requested episode_id) """ episode = Episode.get_by_id(episode_id) logger.info( "=== [%s] START downloading process URL: %s FILENAME: %s ===", episode.source_id, youtube_link, episode.file_name, ) stored_file_size = StorageS3().get_file_size(episode.file_name) if stored_file_size and stored_file_size == episode.file_size: logger.info( "[%s] Episode already downloaded and file correct. Downloading will be ignored.", episode.source_id, ) _update_episodes(episode.source_id, stored_file_size) _update_all_rss(episode.source_id) return EPISODE_DOWNLOADING_IGNORED elif episode.status not in (Episode.STATUS_NEW, Episode.STATUS_DOWNLOADING): logger.error( "[%s] Episode is %s but file-size seems not correct. " "Removing not-correct file %s and reloading it from youtube.", episode.source_id, episode.status, episode.file_name, ) StorageS3().delete_file(episode.file_name) logger.info( "[%s] Mark all episodes with source_id [%s] as downloading.", episode.source_id, episode.source_id, ) query = Episode.update(status=Episode.STATUS_DOWNLOADING).where( Episode.source_id == episode.source_id, Episode.status != Episode.STATUS_ARCHIVED, ) query.execute() try: result_filename = youtube_utils.download_audio(youtube_link, episode.file_name) except YoutubeException as error: logger.exception( "=== [%s] Downloading FAILED: Could not download track: %s. " "All episodes will be rolled back to NEW state", episode.source_id, error, ) Episode.update(status=Episode.STATUS_NEW).where( Episode.source_id == episode.source_id).execute() return EPISODE_DOWNLOADING_ERROR logger.info("=== [%s] DOWNLOADING was done ===", episode.source_id) youtube_utils.ffmpeg_preparation(result_filename) logger.info("=== [%s] POST PROCESSING was done === ", episode.source_id) # ----- uploading file to cloud ----- remote_url = podcast_utils.upload_episode(result_filename) if not remote_url: logger.warning("=== [%s] UPLOADING was broken === ") _update_episodes(episode.source_id, file_size=0, status=Episode.STATUS_ERROR) return EPISODE_DOWNLOADING_ERROR _update_episode_data(episode.source_id, { "file_name": result_filename, "remote_url": remote_url }) logger.info("=== [%s] UPLOADING was done === ", episode.source_id) # ----------------------------------- # ----- update episodes data ------- _update_episodes(episode.source_id, file_size=StorageS3().get_file_size(result_filename)) _update_all_rss(episode.source_id) podcast_utils.delete_file( os.path.join(settings.TMP_AUDIO_PATH, result_filename)) # ----------------------------------- logger.info("=== [%s] DOWNLOADING total finished ===", episode.source_id) return EPISODE_DOWNLOADING_OK