Пример #1
0
    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),
        )
Пример #2
0
    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),
        )
Пример #3
0
    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"),
            ),
        )
Пример #4
0
    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)
Пример #5
0
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