Search code examples
pythonapitwittertweepytwitterapi-python

Problem extracting tweet info with runcmd


I'm trying to get this code to pull the media from any tweet that mentions my twitter handle, convert it using ffmpeg via the subprocess module, then send the converted media back to the person as a reply.

import tweepy
from tweepy import Stream
from tweepy.streaming import StreamListener
from datetime import datetime
import time
import subprocess

stdout = subprocess.PIPE
def runcmd(cmd):
    x = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    return x.communicate(stdout)

import json
import random

class StdOutListener(StreamListener):
    def on_data(self, data):
        clean_data = json.loads(data)
        tweetId = clean_data['id']
        tweet_name = clean_data['user']['screen_name']
        tweet_media = clean_data['entities']['media'][0]['media_url']
        print(tweet_media)
        tweet_photo = runcmd('ffmpeg -i', tweet_media, 'output.jpg')
        tweet = 'Here ya go'
        now = datetime.now()
        dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
        print(' Reply sent to @'+tweet_name, 'on', dt_string, '\n' ' Message:', tweet, '\n')
        respondToTweet(tweet_media, tweet, tweetId)

But I always end up getting this error:

Exception has occurred: TypeError
runcmd() takes 1 positional argument but 3 were given
   tweet_photo = runcmd('ffmpeg -i', tweet_media, 'output.jpg')

So obviously, I can't put tweet_media in between ffmpeg -i and output.jpg so how would I go about converting tweet_media without errors?


Solution

  • Based on this answer, you need something like this if you want to keep the call as it is:

    def runcmd(*cmd):
        x = subprocess.Popen([*cmd], stdout=subprocess.PIPE)
        return x.communicate(stdout)
    

    Also see the official documentation on Arbitrary Argument Lists.

    Further notes: Popen() takes the command to run as a list of words. So, there are two Python features to be employed.

    1. def runcmd(*cmd): This says the function takes an arbitrary list of arguments, and stores them in cmd as a tuple, so calling runcmd('ffmpeg', '-i', tweet_media, 'output.jpg') results in cmd equalling ('ffmpeg', '-i', tweet_media, 'output.jpg').

    2. Popen takes as the first argument a list of strings representing the command to run. So, first *cmd unwraps the tuple into the elements, and then [*cmd] makes the elements into a list, so we get the desired call ['ffmpeg', '-i', tweet_media, 'output.jpg'].

    NOTE: Specifying 'ffmpeg -i' as the first element of the list makes Popen search for an executable called ffmpeg<SPACE>-i, which most likely won't exist, so you should use 'ffmpeg', '-i' instead.