0

I am running a python script which converts a video file to an audio clip using moviepy.

def convert(mp3_file,mp4_file):

    videoclip = VideoFileClip(mp4_file)
    audioclip = videoclip.audio
    audioclip.write_audiofile(mp3_file)
    audioclip.close()
    videoclip.close()

I found out that Moviepy uses a library called Proglog to print a command line progress bar.

command line progress bar

How do I get these process completion percentage values?

Ali Ent
  • 1,420
  • 6
  • 17
sokar
  • 1
  • 3
  • Have you tried the logger option of write_audiofile? https://zulko.github.io/moviepy/ref/AudioClip.html – SamBob Oct 03 '21 at 08:57
  • 1
    And to make your own compatible logger you could subclass ProgressBarLogger from proglog and override callback as documented here https://github.com/Edinburgh-Genome-Foundry/Proglog – SamBob Oct 03 '21 at 09:01
  • @SamBob thanks for replying! But overriding callback is not getting me the percentage completion values. – sokar Oct 03 '21 at 09:31
  • 1
    Ah, that would be `bars_callback`. I found an older question with the same issue and answered there: https://stackoverflow.com/a/69433896/1581658 – SamBob Oct 04 '21 at 09:44
  • @sambob there's activity on this question. perhaps you should turn your comments into an answer. – Christoph Rackwitz May 01 '23 at 10:04

3 Answers3

1

Thanks to SamBob comments there's a way to make your own logger for proglog and define the logger callback. For percentages values use bars_callback.

from proglog import ProgressBarLogger
from moviepy.editor import VideoFileClip

class MyBarLogger(ProgressBarLogger):
    
    def callback(self, **changes):
        # Every time the logger message is updated, this function is called with
        # the `changes` dictionary of the form `parameter: new value`.
        for (parameter, value) in changes.items():
            print ('Parameter %s is now %s' % (parameter, value))
    
    def bars_callback(self, bar, attr, value,old_value=None):
        # Every time the logger progress is updated, this function is called        
        percentage = (value / self.bars[bar]['total']) * 100
        print(bar,attr,percentage)

logger = MyBarLogger()

def convert(mp3_file,mp4_file):

    videoclip = VideoFileClip(mp4_file)
    audioclip = videoclip.audio
    audioclip.write_audiofile(mp3_file, logger=logger)
    audioclip.close()
    videoclip.close()

convert("audio.mp3", "bad_apple.mp4")
Ali Ent
  • 1,420
  • 6
  • 17
0

WARNING: Bruteforce ahead!

It is possible, however, moviepy has no official method to do this.

We can get the progress inside the source code of the module

we need to edit the module code and follow the steps. [This is for ubuntu linux]

Step 1 - go to the ffmpg_writter.py [usually in /home/anipr/.local/lib/python3.10/site-packages/moviepy/video/io/ffmpeg_writer.py]

Step 2 - go to line 221 and add calculate the percentage based on duration - get_the_persentage_of_progress = (t/clip.duration)*100

reference image

Step - 3 do anything with the variable get_the_persentage_of_progress however, getting the variable back to our original code is a bit tricky.

here are a few ideas -

  1. write it to a file.txt
  2. insert into database
  3. [let me know in comments if any better idea]
0

I've made a modified version of Ali Ent. That's helpful if you only want the percentage change for each second instead of every decimal change. I'm also only printing it when MoviePy is exporting the video

if 'Writing video' in self.last_message:

That was really helpful as I only want to update the front-end messages when this happens. Here is the code:

        class MyBarLogger(ProgressBarLogger):

        def __init__(self):
            super().__init__()
            self.last_message = ''
            self.previous_percentage = 0    
        
        def callback(self, **changes):
            # Every time the logger message is updated, this function is called with
            # the `changes` dictionary of the form `parameter: new value`.
            for (parameter, value) in changes.items():
                # print ('Parameter %s is now %s' % (parameter, value))
                self.last_message = value
        
        def bars_callback(self, bar, attr, value,old_value=None):
            # Every time the logger progress is updated, this function is called        
            if 'Writing video' in self.last_message:
                percentage = (value / self.bars[bar]['total']) * 100
                if percentage > 0 and percentage < 100:
                    if int(percentage) != self.previous_percentage:
                        self.previous_percentage = int(percentage)
                        print(self.previous_percentage)

    logger = MyBarLogger()

    video.write_videofile('name.mp4', logger=logger)