Exemplo n.º 1
0
async def handle_callback(event):
    choice = event.data
    msg = await event.get_message()
    sender = await get_sender_info(event)
    message = await msg.get_reply_message()
    if choice == NORMAL:
        resize_func = normal_resize
    elif choice == SEAM_CARVING:
        resize_func = seam_carving_resize
    else:
        logger.warning(f'Get wrong resize func: {choice} from {sender!r}')
        return

    await event.edit('Request accepted, downloading...')

    with BytesIO() as in_f, BytesIO() as out_f:
        success = await client.download_media(message, file=in_f)
        await event.edit('File received, processing')
        if success is None:
            logger.info('Fail to download media')
            await event.edit('Fail to download media')
            return
        in_f.flush()
        in_f.seek(0)
        if not is_image(in_f):
            logger.debug("Media is not image")
            await event.edit('Media is not image')
            return
        in_f.seek(0)

        with ProcessPoolExecutor() as pool:
            new_img = await client.loop.run_in_executor(
                pool, resize_func, in_f)

        file_name, ext = splitext(get_media_filename(message.media))
        out_f.name = f'Resized_{file_name}.png'

        is_success, im_buf_arr = cv2.imencode('.png', new_img)
        if not is_success:
            logger.debug("OpenCV can't transform img to bytes")
            return
        out_f.write(im_buf_arr.tobytes())
        out_f.flush()
        out_f.seek(0)

        prompt = f'Sending Resized File:{out_f.name!r}'
        logger.debug(f'{prompt} to {sender!r}')
        await event.edit(text=prompt)
        await message.reply(file=out_f, force_document=True)
        await event.edit('Finished')
Exemplo n.º 2
0
def check_output_exists(data_dir,
                        ytid,
                        ts_start,
                        ts_end,
                        audio_only=False,
                        video_format='mp4',
                        audio_format='flac'):

    # Skip files that already have been downloaded
    media_filename = get_media_filename(ytid, ts_start, ts_end)
    video_filepath = os.path.join(data_dir, 'video',
                                  media_filename + '.' + video_format)
    audio_filepath = os.path.join(data_dir, 'audio',
                                  media_filename + '.' + audio_format)

    output_exists = False
    audio_exists = os.path.exists(audio_filepath)
    if audio_only:
        output_exists = audio_exists
    else:
        output_exists = audio_exists and os.path.exists(video_filepath)

    return output_exists
def download_subset_videos(subset_path, data_dir, ffmpeg_path, ffprobe_path,
                           num_workers, **ffmpeg_cfg):
    """
    Download subset segment file and videos

    Args:
        subset_path:   Path to subset segments file
                       (Type: str)

        data_dir:      Directory where dataset files will be saved
                       (Type: str)

        ffmpeg_path:   Path to ffmpeg executable
                       (Type: str)

        ffprobe_path:  Path to ffprobe executable
                       (Type: str)

        num_workers:   Number of multiprocessing workers used to download videos
                       (Type: int)

    Keyword Args:
        **ffmpeg_cfg:  Configuration for audio and video
                       downloading and decoding done by ffmpeg
                       (Type: dict[str, *])
    """
    subset_name = get_subset_name(subset_path)

    LOGGER.info('Starting download jobs for subset "{}"'.format(subset_name))
    with open(subset_path, 'r') as f:
        subset_data = csv.reader(f)

        # Set up multiprocessing pool
        pool = mp.Pool(num_workers)
        try:
            for row_idx, row in enumerate(subset_data):
                # Skip commented lines
                if row[0][0] == '#':
                    continue
                ytid, ts_start, ts_end = row[0], float(row[1]), float(row[2])

                # Skip files that already have been downloaded
                media_filename = get_media_filename(ytid, ts_start, ts_end)
                video_filepath = os.path.join(
                    data_dir, 'video', media_filename + '.' +
                    ffmpeg_cfg.get('video_format', 'mp4'))
                audio_filepath = os.path.join(
                    data_dir, 'audio', media_filename + '.' +
                    ffmpeg_cfg.get('audio_format', 'flac'))
                if os.path.exists(video_filepath) and os.path.exists(
                        audio_filepath):
                    info_msg = 'Already downloaded video {} ({} - {}). Skipping.'
                    LOGGER.info(info_msg.format(ytid, ts_start, ts_end))
                    continue

                # Skip files that are neither Applause nor Speech
                with open('filemove/both_id.txt', 'r+') as f:
                    if ytid in f.read():
                        print("downloaded sth meaningful!" + ytid)
                    else:
                        # print("skip" + ytid)
                        continue

                worker_args = [
                    ytid, ts_start, ts_end, data_dir, ffmpeg_path, ffprobe_path
                ]
                pool.apply_async(partial(segment_mp_worker, **ffmpeg_cfg),
                                 worker_args)
                # Run serially
                #segment_mp_worker(*worker_args, **ffmpeg_cfg)

        except csv.Error as e:
            err_msg = 'Encountered error in {} at line {}: {}'
            LOGGER.error(err_msg)
            sys.exit(err_msg.format(subset_path, row_idx + 1, e))
        except KeyboardInterrupt:
            LOGGER.info("Forcing exit.")
            exit()
        finally:
            try:
                pool.close()
                pool.join()
            except KeyboardInterrupt:
                LOGGER.info("Forcing exit.")
                exit()

    LOGGER.info('Finished download jobs for subset "{}"'.format(subset_name))
def download_yt_video(ytid,
                      ts_start,
                      ts_end,
                      output_dir,
                      ffmpeg_path,
                      ffprobe_path,
                      audio_codec='flac',
                      audio_format='flac',
                      audio_sample_rate=48000,
                      audio_bit_depth=16,
                      video_codec='h264',
                      video_format='mp4',
                      video_mode='bestvideoaudio',
                      video_frame_rate=30,
                      num_retries=10):
    """
    Download a Youtube video (with the audio and video separated).

    The audio will be saved in <output_dir>/audio and the video will be saved in
    <output_dir>/video.

    The output filename is of the format:
        <YouTube ID>_<start time in ms>_<end time in ms>.<extension>

    Args:
        ytid:          Youtube ID string
                       (Type: str)

        ts_start:      Segment start time (in seconds)
                       (Type: float)

        ts_start:      Segment end time (in seconds)
                       (Type: float)

        output_dir:    Output directory where video will be saved
                       (Type: str)

        ffmpeg_path:   Path to ffmpeg executable
                       (Type: str)

        ffprobe_path:  Path to ffprobe executable
                       (Type: str)

    Keyword Args:
        audio_codec:        Name of audio codec used by ffmpeg to encode
                            output audio
                            (Type: str)

        audio_format:       Name of audio container format used for output audio
                            (Type: str)

        audio_sample_rate:  Target audio sample rate (in Hz)
                            (Type: int)

        audio_bit_depth:    Target audio sample bit depth
                            (Type: int)

        video_codec:        Name of video codec used by ffmpeg to encode
                            output video
                            (Type: str)

        video_format:       Name of video container format used for output video
                            (Type: str)

        video_mode:         Name of the method in which video is downloaded.
                            'bestvideo' obtains the best quality video that does not
                            contain an audio stream. 'bestvideoaudio' obtains the
                            best quality video that contains an audio stream.
                            'bestvideowithaudio' obtains the best quality video
                            without an audio stream and merges it with audio stream.
                            (Type: bool)

        video_frame_rate:   Target video frame rate (in fps)
                            (Type: int)

        num_retries:        Number of attempts to download and process an audio
                            or video file with ffmpeg
                            (Type: int)


    Returns:
        video_filepath:  Filepath to video file
                         (Type: str)

        audio_filepath:  Filepath to audio file
                         (Type: str)
    """
    # Compute some things from the segment boundaries
    duration = ts_end - ts_start

    # Make the output format and video URL
    # Output format is in the format:
    #   <YouTube ID>_<start time in ms>_<end time in ms>.<extension>
    media_filename = get_media_filename(ytid, ts_start, ts_end)
    video_filepath = os.path.join(output_dir, 'video',
                                  media_filename + '.' + video_format)
    audio_filepath = os.path.join(output_dir, 'audio',
                                  media_filename + '.' + audio_format)
    video_page_url = 'https://www.youtube.com/watch?v={}'.format(ytid)

    # Get the direct URLs to the videos with best audio and with best video (with audio)

    video = pafy.new(video_page_url)
    video_duration = video.length
    end_past_video_end = False
    if ts_end > video_duration:
        warn_msg = "End time for segment ({} - {}) of video {} extends past end of video (length {} sec)"
        LOGGER.warning(warn_msg.format(ts_start, ts_end, ytid, video_duration))
        duration = video_duration - ts_start
        ts_end = ts_start + duration
        end_past_video_end = True

    if video_mode in ('bestvideo', 'bestvideowithaudio'):
        best_video = video.getbestvideo()
        # If there isn't a video only option, go with best video with audio
        if best_video is None:
            best_video = video.getbest()
    elif video_mode in ('bestvideoaudio', 'bestvideoaudionoaudio'):
        best_video = video.getbest()
    else:
        raise ValueError('Invalid video mode: {}'.format(video_mode))
    best_audio = video.getbestaudio()
    best_video_url = best_video.url
    best_audio_url = best_audio.url

    audio_info = {
        'sample_rate': audio_sample_rate,
        'channels': 2,
        'bitrate': audio_bit_depth,
        'encoding': audio_codec.upper(),
        'duration': duration
    }
    video_info = {
        "r_frame_rate": "{}/1".format(video_frame_rate),
        "avg_frame_rate": "{}/1".format(video_frame_rate),
        'codec_name': video_codec.lower(),
        'duration': duration
    }
    # Download the audio
    audio_input_args = ['-n', '-ss', str(ts_start)]
    audio_output_args = [
        '-t',
        str(duration), '-ar',
        str(audio_sample_rate), '-vn', '-ac',
        str(audio_info['channels']), '-sample_fmt',
        's{}'.format(audio_bit_depth), '-f', audio_format, '-acodec',
        audio_codec
    ]
    ffmpeg(ffmpeg_path,
           best_audio_url,
           audio_filepath,
           input_args=audio_input_args,
           output_args=audio_output_args,
           num_retries=num_retries,
           validation_callback=validate_audio,
           validation_args={
               'audio_info': audio_info,
               'end_past_video_end': end_past_video_end
           })

    if video_mode != 'bestvideowithaudio':
        # Download the video
        video_input_args = ['-n', '-ss', str(ts_start)]
        video_output_args = [
            '-t',
            str(duration), '-f', video_format, '-r',
            str(video_frame_rate), '-vcodec', video_codec
        ]
        # Suppress audio stream if we don't want to audio in the video
        if video_mode in ('bestvideo', 'bestvideoaudionoaudio'):
            video_output_args.append('-an')

        ffmpeg(ffmpeg_path,
               best_video_url,
               video_filepath,
               input_args=video_input_args,
               output_args=video_output_args,
               num_retries=num_retries,
               validation_callback=validate_video,
               validation_args={
                   'ffprobe_path': ffprobe_path,
                   'video_info': video_info,
                   'end_past_video_end': end_past_video_end
               })
    else:
        # Download the best quality video, in lossless encoding
        if video_codec != 'h264':
            error_msg = 'Not currently supporting merging of best quality video with video for codec: {}'
            raise NotImplementedError(error_msg.format(video_codec))
        video_input_args = ['-n', '-ss', str(ts_start)]
        video_output_args = [
            '-t',
            str(duration), '-f', video_format, '-crf', '0', '-preset',
            'medium', '-r',
            str(video_frame_rate), '-an', '-vcodec', video_codec
        ]

        ffmpeg(ffmpeg_path,
               best_video_url,
               video_filepath,
               input_args=video_input_args,
               output_args=video_output_args,
               num_retries=num_retries)

        # Merge the best lossless video with the lossless audio, and compress
        merge_video_filepath = os.path.splitext(video_filepath)[0] \
                               + '_merge.' + video_format
        video_input_args = ['-n']
        video_output_args = [
            '-f', video_format, '-r',
            str(video_frame_rate), '-vcodec', video_codec, '-acodec', 'aac',
            '-ar',
            str(audio_sample_rate), '-ac',
            str(audio_info['channels']), '-strict', 'experimental'
        ]

        ffmpeg(ffmpeg_path, [video_filepath, audio_filepath],
               merge_video_filepath,
               input_args=video_input_args,
               output_args=video_output_args,
               num_retries=num_retries,
               validation_callback=validate_video,
               validation_args={
                   'ffprobe_path': ffprobe_path,
                   'video_info': video_info,
                   'end_past_video_end': end_past_video_end
               })

        # Remove the original video file and replace with the merged version
        if os.path.exists(merge_video_filepath):
            os.remove(video_filepath)
            shutil.move(merge_video_filepath, video_filepath)
        else:
            error_msg = 'Cannot find merged video for {} ({} - {}) at {}'
            LOGGER.error(
                error_msg.format(ytid, ts_start, ts_end, merge_video_filepath))

    LOGGER.info('Downloaded video {} ({} - {})'.format(ytid, ts_start, ts_end))

    return video_filepath, audio_filepath
Exemplo n.º 5
0
def download_yt_video(ytid,
                      ts_start,
                      ts_end,
                      output_dir,
                      ffmpeg_path,
                      ffprobe_path,
                      audio_codec='flac',
                      audio_format='flac',
                      audio_sample_rate=48000,
                      audio_bit_depth=16,
                      video_codec='h264',
                      video_format='mp4',
                      video_mode='bestvideoaudio',
                      video_frame_rate=30,
                      num_retries=10):
    """
    Download a Youtube video (with the audio and video separated).

    The audio will be saved in <output_dir>/audio and the video will be saved in
    <output_dir>/video.

    The output filename is of the format:
        <YouTube ID>_<start time in ms>_<end time in ms>.<extension>

    Args:
        ytid:          Youtube ID string
                       (Type: str)

        ts_start:      Segment start time (in seconds)
                       (Type: float)

        ts_start:      Segment end time (in seconds)
                       (Type: float)

        output_dir:    Output directory where video will be saved
                       (Type: str)

        ffmpeg_path:   Path to ffmpeg executable
                       (Type: str)

        ffprobe_path:  Path to ffprobe executable
                       (Type: str)

    Keyword Args:
        audio_codec:        Name of audio codec used by ffmpeg to encode
                            output audio
                            (Type: str)

        audio_format:       Name of audio container format used for output audio
                            (Type: str)

        audio_sample_rate:  Target audio sample rate (in Hz)
                            (Type: int)

        audio_bit_depth:    Target audio sample bit depth
                            (Type: int)

        video_codec:        Name of video codec used by ffmpeg to encode
                            output video
                            (Type: str)

        video_format:       Name of video container format used for output video
                            (Type: str)

        video_mode:         Name of the method in which video is downloaded.
                            'bestvideo' obtains the best quality video that does not
                            contain an audio stream. 'bestvideoaudio' obtains the
                            best quality video that contains an audio stream.
                            'bestvideowithaudio' obtains the best quality video
                            without an audio stream and merges it with audio stream.
                            (Type: bool)

        video_frame_rate:   Target video frame rate (in fps)
                            (Type: int)

        num_retries:        Number of attempts to download and process an audio
                            or video file with ffmpeg
                            (Type: int)


    Returns:
        video_filepath:  Filepath to video file
                         (Type: str)

        audio_filepath:  Filepath to audio file
                         (Type: str)
    """
    # Compute some things from the segment boundaries
    duration = ts_end - ts_start

    # Make the output format and video URL
    # Output format is in the format:
    #   <YouTube ID>_<start time in ms>_<end time in ms>.<extension>
    media_filename = get_media_filename(ytid, ts_start, ts_end)
    video_filepath = os.path.join(output_dir, 'video',
                                  media_filename + '.' + video_format)
    audio_filepath = os.path.join(output_dir, 'audio',
                                  media_filename + '.' + audio_format)
    video_page_url = 'https://www.youtube.com/watch?v={}'.format(ytid)

    # Get the direct URLs to the videos with best audio and with best video (with audio)

    video = YouTube(video_page_url)
    video_duration = video.length

    end_past_video_end = True
    if ts_end > video_duration:
        warn_msg = "End time for segment ({} - {}) of video {} extends past end of video (length {} sec)"
        LOGGER.warning(warn_msg.format(ts_start, ts_end, ytid, video_duration))
        duration = video_duration - ts_start
        ts_end = ts_start + duration
        end_past_video_end = True

    if video_mode in ('bestvideo', 'bestvideowithaudio'):
        best_video = video.streams.get_highest_resolution()
    elif video_mode == 'audioonly':
        best_video = video.streams.get_audio_only()
    else:
        best_video = video.streams.get_first()

    audio_info = {
        'sample_rate': audio_sample_rate,
        'channels': 2,
        'duration': duration
    }
    video_info = {
        "r_frame_rate": "{}/1".format(video_frame_rate),
        "avg_frame_rate": "{}/1".format(video_frame_rate),
        'codec_name': video_codec.lower(),
        'duration': duration
    }

    # Download the audio
    download_tmp_file = f"audio_{ytid}.mp4"
    downloaded_file_path = best_video.download(filename=download_tmp_file)

    audio_input_args = ['-n', '-ss', str(ts_start)]

    audio_output_args = [
        '-t',
        str(duration),
        '-ar',
        str(audio_sample_rate),
        '-vn',
        '-ac',
        str(audio_info['channels']),
        #'-sample_fmt', 's{}'.format(audio_bit_depth),
        '-f',
        audio_format
    ]  #,
    #'-acodec', audio_codec]

    ffmpeg(ffmpeg_path,
           downloaded_file_path,
           audio_filepath,
           input_args=audio_input_args,
           output_args=audio_output_args,
           num_retries=num_retries,
           validation_callback=validate_audio,
           validation_args={
               'audio_info': audio_info,
               'end_past_video_end': end_past_video_end
           })

    # Remove the original file, probably bulkier, we really just want our cropped-down MP3
    if os.path.exists(downloaded_file_path):
        os.remove(downloaded_file_path)
    else:
        error_msg = f'Cannot find original download file for {ytid} ({ts_start} - {ts_start}) at {downloaded_file_path}'
        LOGGER.error(
            error_msg.format(ytid, ts_start, ts_end, downloaded_file_path))

    LOGGER.info('Downloaded video {} ({} - {})'.format(ytid, ts_start, ts_end))

    return audio_filepath
Exemplo n.º 6
0
def download_yt_video(ytid,
                      ts_start,
                      ts_end,
                      output_dir,
                      ffmpeg_path,
                      ffprobe_path,
                      audio_codec='flac',
                      audio_format='flac',
                      audio_sample_rate=48000,
                      audio_bit_depth=16,
                      num_retries=10):
    """
    Download a Youtube video (with the audio and video separated).

    The audio will be saved in <output_dir>/audio and the video will be saved in
    <output_dir>/video.

    The output filename is of the format:
        <YouTube ID>_<start time in ms>_<end time in ms>.<extension>

    Args:
        ytid:          Youtube ID string
                       (Type: str)

        ts_start:      Segment start time (in seconds)
                       (Type: float)

        ts_start:      Segment end time (in seconds)
                       (Type: float)

        output_dir:    Output directory where video will be saved
                       (Type: str)

        ffmpeg_path:   Path to ffmpeg executable
                       (Type: str)

        ffprobe_path:  Path to ffprobe executable
                       (Type: str)

    Keyword Args:
        audio_codec:        Name of audio codec used by ffmpeg to encode
                            output audio
                            (Type: str)

        audio_format:       Name of audio container format used for output audio
                            (Type: str)

        audio_sample_rate:  Target audio sample rate (in Hz)
                            (Type: int)

        audio_bit_depth:    Target audio sample bit depth
                            (Type: int)

        video_codec:        Name of video codec used by ffmpeg to encode
                            output video
                            (Type: str)

        video_format:       Name of video container format used for output video
                            (Type: str)

        video_mode:         Name of the method in which video is downloaded.
                            'bestvideo' obtains the best quality video that does not
                            contain an audio stream. 'bestvideoaudio' obtains the
                            best quality video that contains an audio stream.
                            'bestvideowithaudio' obtains the best quality video
                            without an audio stream and merges it with audio stream.
                            (Type: bool)

        video_frame_rate:   Target video frame rate (in fps)
                            (Type: int)

        num_retries:        Number of attempts to download and process an audio
                            or video file with ffmpeg
                            (Type: int)


    Returns:
        video_filepath:  Filepath to video file
                         (Type: str)

        audio_filepath:  Filepath to audio file
                         (Type: str)
    """
    # Compute some things from the segment boundaries
    duration = ts_end - ts_start

    # Make the output format and video URL
    # Output format is in the format:
    #   <YouTube ID>_<start time in ms>_<end time in ms>.<extension>
    media_filename = get_media_filename(ytid, ts_start, ts_end)
    audio_filepath = os.path.join(output_dir,
                                  media_filename + '.' + audio_format)
    video_page_url = 'https://www.youtube.com/watch?v={}'.format(ytid)

    # Get the direct URLs to the videos with best audio and with best video (with audio)

    video = pafy.new(video_page_url)
    video_duration = video.length
    end_past_video_end = False
    if ts_end > video_duration:
        warn_msg = "End time for segment ({} - {}) of video {} extends past end of video (length {} sec)"
        LOGGER.warning(warn_msg.format(ts_start, ts_end, ytid, video_duration))
        duration = video_duration - ts_start
        ts_end = ts_start + duration
        end_past_video_end = True

    best_audio = video.getbestaudio()
    best_audio_url = best_audio.url

    audio_info = {
        'sample_rate': audio_sample_rate,
        'channels': 2,
        'bitrate': audio_bit_depth,
        'encoding': audio_codec.upper(),
        'duration': duration
    }
    # Download the audio
    audio_input_args = ['-n', '-ss', str(ts_start)]
    audio_output_args = [
        '-t',
        str(duration), '-ar',
        str(audio_sample_rate), '-vn', '-ac',
        str(audio_info['channels']), '-sample_fmt',
        's{}'.format(audio_bit_depth), '-f', audio_format, '-acodec',
        audio_codec
    ]
    ffmpeg(ffmpeg_path,
           best_audio_url,
           audio_filepath,
           input_args=audio_input_args,
           output_args=audio_output_args,
           num_retries=num_retries,
           validation_callback=validate_audio,
           validation_args={
               'audio_info': audio_info,
               'end_past_video_end': end_past_video_end
           })

    LOGGER.info('Downloaded audio {} ({} - {})'.format(ytid, ts_start, ts_end))

    return audio_filepath