Exemple #1
0
    async def _delete_files(self, podcast: Podcast, episodes: List[Episode]):
        podcast_file_names = {episode.file_name for episode in episodes}
        same_file_episodes = await self.request.app.objects.execute(
            Episode.select().where(
                Episode.podcast_id != podcast.id,
                Episode.file_name.in_(podcast_file_names),
            ))
        exist_file_names = {
            episode.file_name
            for episode in same_file_episodes or []
        }

        files_to_remove = podcast_file_names - exist_file_names
        files_to_skip = exist_file_names & podcast_file_names
        if files_to_skip:
            self.logger.warning(
                "There are another episodes with files %s. Skip this files removing.",
                files_to_skip,
            )

        storage = StorageS3()
        await storage.delete_files_async(list(files_to_remove))
        await storage.delete_files_async(
            [f"{podcast.publish_id}.xml"],
            remote_path=settings.S3_BUCKET_RSS_PATH)
Exemple #2
0
def test_download_sound__episode_downloaded__file_correct__ignore_downloading__ok(
    generate_rss_mock,
    db_objects,
    podcast,
    episode_data,
    mocked_youtube: MockYoutube,
    mocked_s3: MockS3Client,
):
    new_episode_data = {
        **episode_data,
        **{
            "status": "published",
            "source_id": mocked_youtube.video_id,
            "watch_url": mocked_youtube.watch_url,
            "file_size": 1024,
        },
    }
    episode: Episode = Episode.create(**new_episode_data)
    mocked_s3.get_file_size.return_value = episode.file_size
    generate_rss_mock.return_value = f"file_{episode.source_id}.mp3"
    result = download_episode(episode.watch_url, episode.id)

    with db_objects.allow_sync():
        updated_episode: Episode = Episode.select().where(
            Episode.id == episode.id).first()

    generate_rss_mock.assert_called_with(episode.podcast_id)
    assert result == EPISODE_DOWNLOADING_IGNORED
    assert not mocked_youtube.download.called
    assert updated_episode.status == "published"
    assert updated_episode.published_at == updated_episode.created_at
Exemple #3
0
def test_download_sound__youtube_exception__download_rollback(
    download_audio_mock,
    db_objects,
    podcast,
    episode_data,
    mocked_youtube: MockYoutube,
    mocked_s3: MockS3Client,
):
    new_episode_data = {
        **episode_data,
        **{
            "status": "new",
            "source_id": mocked_youtube.video_id,
            "watch_url": mocked_youtube.watch_url,
            "file_size": 1024,
        },
    }
    episode: Episode = Episode.create(**new_episode_data)

    download_audio_mock.side_effect = YoutubeException(
        "Youtube video is not available")
    result = download_episode(episode.watch_url, episode.id)

    with db_objects.allow_sync():
        updated_episode: Episode = Episode.select().where(
            Episode.id == episode.id).first()

    download_audio_mock.assert_called_with(episode.watch_url,
                                           episode.file_name)

    assert result == EPISODE_DOWNLOADING_ERROR
    assert updated_episode.status == "new"
    assert updated_episode.published_at is None
Exemple #4
0
def _update_all_rss(source_id: str):
    """ Allows to regenerate rss for all podcasts with requested episode (by source_id) """

    logger.info(
        "Episodes with source #%s: updating rss for all podcasts included for",
        source_id,
    )

    affected_episodes = list(
        Episode.select(Episode.podcast).where(Episode.source_id == source_id))
    podcast_ids = [episode.podcast_id for episode in affected_episodes]
    logger.info("Found podcasts for rss updates: %s", podcast_ids)

    for podcast_id in podcast_ids:
        generate_rss(podcast_id)
Exemple #5
0
    async def _delete_file(self, episode: Episode):
        """ Removing file associated with requested episode """

        same_file_episodes = await self.request.app.objects.execute(
            Episode.select().where(
                Episode.source_id == episode.source_id,
                Episode.status != Episode.STATUS_NEW,
                Episode.id != episode.id,
            ))
        if same_file_episodes:
            episode_ids = ",".join(
                [f"#{episode.id}" for episode in same_file_episodes])
            self.logger.warning(
                f"There are another episodes for file {episode.file_name}: {episode_ids}. "
                f"Skip file removing.")
            return

        return await StorageS3().delete_files_async([episode.file_name])
Exemple #6
0
def test_download_sound__episode_new__correct_downloading(
    download_audio_mock,
    generate_rss_mock,
    db_objects,
    podcast,
    episode_data,
    mocked_youtube: MockYoutube,
    mocked_s3: MockS3Client,
    mocked_ffmpeg: Mock,
):
    new_episode_data = {
        **episode_data,
        **{
            "status": "new",
            "source_id": mocked_youtube.video_id,
            "watch_url": mocked_youtube.watch_url,
            "file_size": 1024,
        },
    }
    episode: Episode = Episode.create(**new_episode_data)

    download_audio_mock.return_value = episode.file_name
    generate_rss_mock.return_value = f"file_{episode.source_id}.mp3"
    result = download_episode(episode.watch_url, episode.id)

    with db_objects.allow_sync():
        updated_episode: Episode = Episode.select().where(
            Episode.id == episode.id).first()

    generate_rss_mock.assert_called_with(episode.podcast_id)
    download_audio_mock.assert_called_with(episode.watch_url,
                                           episode.file_name)
    mocked_ffmpeg.assert_called_with(episode.file_name)

    assert result == EPISODE_DOWNLOADING_OK
    assert updated_episode.status == "published"
    assert updated_episode.published_at == updated_episode.created_at
Exemple #7
0
    async def post(self):
        podcast_id = int(self.request.match_info.get("podcast_id"))
        podcast: Podcast = await self._get_object()
        cleaned_data = await self._validate()
        youtube_link = cleaned_data["youtube_link"].strip()

        video_id = get_video_id(youtube_link)
        if not video_id:
            add_message(self.request,
                        f"YouTube link is not correct: {youtube_link}")
            return redirect(self.request,
                            "podcast_details",
                            podcast_id=podcast_id)

        same_episodes: Iterable[
            Episode] = await self.request.app.objects.execute(
                Episode.select().where(Episode.source_id == video_id).order_by(
                    Episode.created_at.desc()))
        episode_in_podcast, last_same_episode = None, None
        for episode in same_episodes:
            last_same_episode = last_same_episode or episode
            if episode.podcast_id == podcast_id:
                episode_in_podcast = episode
                break

        if episode_in_podcast:
            self.logger.info(
                f"Episode for video [{video_id}] already exists for current "
                f"podcast {podcast_id}. Redirecting to {episode_in_podcast}..."
            )
            add_message(self.request, "Episode already exists in podcast.")
            return redirect(
                self.request,
                "episode_details",
                podcast_id=podcast_id,
                episode_id=episode_in_podcast.id,
            )

        try:
            episode_data = await self._get_episode_data(
                same_episode=last_same_episode,
                podcast_id=podcast_id,
                video_id=video_id,
                youtube_link=youtube_link,
            )
        except YoutubeFetchError:
            return redirect(self.request,
                            "podcast_details",
                            podcast_id=podcast_id)

        episode = await self.request.app.objects.create(
            Episode, **episode_data)

        if podcast.download_automatically:
            episode.status = Episode.STATUS_DOWNLOADING
            await self.request.app.objects.update(episode)
            await self._enqueue_task(
                tasks.download_episode,
                youtube_link=episode.watch_url,
                episode_id=episode.id,
            )
            add_message(
                self.request,
                f"Downloading for youtube {episode.source_id} was started.",
            )

        if is_mobile_app(self.request):
            return redirect(self.request, "progress")

        return redirect(
            self.request,
            "episode_details",
            podcast_id=podcast_id,
            episode_id=str(episode.id),
        )