Read mpg123 terminal command -k output

57 views Asked by At

Can control mpg123 from terminal:

$ mpg123 -C -q ~/Music/Oginsky\ -\ Gold\ Collection/05\ -\ Oginsky\ -\ Oginsky\ Polonaise\ Fmaj.mp3 
# 's' typed
Stopped.
# 'm' typed
MPEG 1.0 L III vbr 44100 j-s
# 'k' typed

[BOOKMARK] track 1 frame 97
# 's' typed
$

Half duplex Python control of mpg123 works too:

import os
import subprocess
import time
track = ('/home/vlz/Music/Oginsky - Gold Collection/'
         '05 - Oginsky - Oginsky Polonaise Fmaj.mp3')
master, slave = os.openpty()
p = subprocess.Popen(['mpg123', '-C', '-q', track], stdin=master)
time.sleep(3)
os.write(slave, b's')
os.write(slave, b'm')
time.sleep(3)
os.write(slave, b'k')
time.sleep(3)
os.write(slave, b's')
time.sleep(6)
os.write(slave, b'q')

(modified the code from pausing-mpg123-through-subprocess-in-python

I'd like to catch the output of 'k', 'm' commands too:

[m] print MPEG header info (again)
[k] print out current position in playlist and track, for the benefit of some external tool to store bookmarks

attemtps to read the descriptor 0 directly or via input() failed. I guess I interfered with the pty flow and the script above ceased to work (didn't finish).

I need the mpg123 command's output in 'real time' (right after the command was issued). In a simple Python mp3 player I'm trying to display how much time of the track being played is left ('k' command).

Using
Python 3.9.2
Debian GNU/Linux 11 (bullseye)

1

There are 1 answers

0
Vladimir Zolotykh On

Had spent quite a while searching for a solution with subprocess.Popen(). Looks that pexpect is a simpler way.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pexpect
import time
mp3 = ('/home/vlz/Music/Oginsky - Gold Collection/'
       '05 - Oginsky - Oginsky Polonaise Fmaj.mp3')
cmd = f'mpg123 -C -q "{mp3}"'


def main():
    p = pexpect.spawn(cmd)
    time.sleep(3)
    p.send('s')
    time.sleep(3)
    p.send('k')
    # [BOOKMARK] track 1 frame 97
    p.expect(r'frame (\d+)')
    pos = p.match.group(1)
    p.send('m')
    # MPEG 1.0 L III vbr 44100 j-s
    p.expect(r'vbr (\d+) ')
    len = p.match.group(1)
    p.send('s')
    time.sleep(3)
    p.send('q')
    print(f'{pos = }, {len = }')


if __name__ == '__main__':
    main()

Tested. It prints:

$ python mpg123_script.py
pos = b'125', len = b'44100'