Python Forum

Full Version: How to parse a live feed in Python?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I am using the subprocess.run() to run handbrakecli to compress a media folder. Whenever I run the command I get a live data feed every 1/2 second in my output. Is there a way to capture the live stdout to get the ETA, Progress value, etc. to create a progress bar? I know how to pase a string to get that data, its just getting those lines from the live output and getting them fast enough to be useful is the hardest part.

Here's an example of what the live feed looks like when you run the code below.

from time import sleep
for feed in range(0,101,20):
    p = f'''
    Progress: {{
        "State":"WORKING",
        "Working":{{
            "ETASeconds":265,
            "Hours":0,
            "Minutes":4,
            "Pass":1,
            "PassCount":1,
            "PassID":0,
            "Paused":0,
            "Progress":{feed}.00000000000000000,
            "Rate":110.10037994384766,
            "RateAvg":124.60877227783203,
            "Seconds":{feed/10},
            "SequenceID":1
        }}
    }}
    '''
    sleep(.5)
    print(p)
You're not showing how you're calling subprocess. subprocess.run is the easy way, but waits for the process to exit. If you want to read from stdout before it exits, you'll have to use subprocess.Popen directly.

If I change your program above to have it print with flush=True and call it "sender.py", then the following program will display the progress. You can do what you need with the data.

Note that this one should work okay because you're constantly getting output and you shouldn't need to do anything between the progress updates. The readline() is going to block until you get more data. If you had to do work while waiting for output, you'd need a different method.

import subprocess

cmd = ["python3", "sender.py"]

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)

while (line := p.stdout.readline()) != "":
    line = line.rstrip()
    if '"Progress"' in line:
        progress = float(line.split(":")[1].rstrip(","))
        print(f"Progress: {progress:.2f}")

print(f"End of output.  Return code: {p.wait()}")
Output:
Progress: 0.00 Progress: 20.00 Progress: 40.00 Progress: 60.00 Progress: 80.00 Progress: 100.00 End of output. Return code: 0
(Jan-18-2022, 05:26 AM)bowlofred Wrote: [ -> ]You're not showing how you're calling subprocess. subprocess.run is the easy way, but waits for the process to exit. If you want to read from stdout before it exits, you'll have to use subprocess.Popen directly.

If I change your program above to have it print with flush=True and call it "sender.py", then the following program will display the progress. You can do what you need with the data.

Note that this one should work okay because you're constantly getting output and you shouldn't need to do anything between the progress updates. The readline() is going to block until you get more data. If you had to do work while waiting for output, you'd need a different method.

import subprocess

cmd = ["python3", "sender.py"]

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)

while (line := p.stdout.readline()) != "":
    line = line.rstrip()
    if '"Progress"' in line:
        progress = float(line.split(":")[1].rstrip(","))
        print(f"Progress: {progress:.2f}")

print(f"End of output.  Return code: {p.wait()}")
Output:
Progress: 0.00 Progress: 20.00 Progress: 40.00 Progress: 60.00 Progress: 80.00 Progress: 100.00 End of output. Return code: 0

That will work perfectly! Thank you for the help!

I hadn't responded for a while since I'm a bit of an issue with my Python interpreters, but I'll fix that later.