Skip to content

Commit

Permalink
Merge pull request #235 from knorth55/tweet-image-server
Browse files Browse the repository at this point in the history
  • Loading branch information
k-okada authored May 15, 2021
2 parents 7f2630e + e732d5a commit 5bb94e8
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 133 deletions.
24 changes: 21 additions & 3 deletions rostwitter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
cmake_minimum_required(VERSION 2.8.3)
project(rostwitter)

find_package(catkin REQUIRED COMPONENTS rospy mk)
find_package(catkin REQUIRED COMPONENTS
actionlib
actionlib_msgs
message_generation
rospy
std_msgs
mk
)

catkin_python_setup()

catkin_package()
add_action_files(
DIRECTORY action
FILES Tweet.action
)


generate_messages(
DEPENDENCIES actionlib_msgs std_msgs)

catkin_package(
CATKIN_DEPENDS message_runtime
)

install(PROGRAMS scripts/tweet.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
)
10 changes: 10 additions & 0 deletions rostwitter/action/Tweet.action
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
bool image
string image_topic_name
bool speak
string text
bool warning
uint8 warning_time
---
bool success
---
time stamp
5 changes: 5 additions & 0 deletions rostwitter/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@


<buildtool_depend>catkin</buildtool_depend>
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>mk</build_depend>
<build_depend>git</build_depend>

<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-requests-oauthlib</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-requests-oauthlib</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-requests</exec_depend>
Expand Down
2 changes: 2 additions & 0 deletions rostwitter/python/rostwitter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from rostwitter.twitter import Twitter # NOQA
from rostwitter.util import load_oauth_settings # NOQA
73 changes: 73 additions & 0 deletions rostwitter/python/rostwitter/twitter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# originally from https://raw.githubusercontent.com/bear/python-twitter/v1.1/twitter.py # NOQA

import json as simplejson
import requests
from requests_oauthlib import OAuth1
from StringIO import StringIO

import rospy


class Twitter(object):
def __init__(
self,
consumer_key=None,
consumer_secret=None,
access_token_key=None,
access_token_secret=None
):
self._consumer_key = consumer_key
self._consumer_secret = consumer_secret
self._access_token_key = access_token_key
self._access_token_secret = access_token_secret

self.__auth = OAuth1(self._consumer_key, self._consumer_secret,
self._access_token_key, self._access_token_secret)
self._requests_timeout = 60

def _request_url(self, url, verb, data=None):
if verb == 'POST':
if 'media' in data:
return requests.post(
url,
files=data,
auth=self.__auth,
timeout=self._requests_timeout
)
else:
return requests.post(
url,
data=data,
auth=self.__auth,
timeout=self._requests_timeout
)
if verb == 'GET':
url = self._BuildUrl(url, extra_params=data)
return requests.get(
url,
auth=self.__auth,
timeout=self._requests_timeout
)
return 0 # if not a POST or GET request

def post_update(self, status):
if len(status) > 140:
rospy.logwarn('tweet is too longer > 140 characters')
status = status[:140]
url = 'https://api.twitter.com/1.1/statuses/update.json'
data = {'status': StringIO(status)}
json = self._request_url(url, 'POST', data=data)
data = simplejson.loads(json.content)
return data

def post_media(self, status, media):
# 116 = 140 - len("http://t.co/ssssssssss")
if len(status) > 116:
rospy.logwarn('tweet wit media is too longer > 116 characters')
status = status[:116]
url = 'https://api.twitter.com/1.1/statuses/update_with_media.json'
data = {'status': StringIO(status)}
data['media'] = open(str(media), 'rb').read()
json = self._request_url(url, 'POST', data=data)
data = simplejson.loads(json.content)
return data
24 changes: 24 additions & 0 deletions rostwitter/python/rostwitter/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import yaml

import rospy


def load_oauth_settings(yaml_path):
if not os.path.exists(yaml_path):
rospy.logerr('"{}" not found'.format(yaml_path))
rospy.logerr("$ get access token from https://apps.twitter.com/")
rospy.logerr("cat {} <<EOF".format(yaml_path))
rospy.logerr("CKEY: xxx")
rospy.logerr("CSECRET: xxx")
rospy.logerr("AKEY: xxx")
rospy.logerr("ASECRET: xxx")
rospy.logerr("EOF")
return None, None, None, None
with open(yaml_path, 'r') as f:
key = yaml.load(f)
ckey = key['CKEY']
csecret = key['CSECRET']
akey = key['AKEY']
asecret = key['ASECRET']
return ckey, csecret, akey, asecret
Binary file added rostwitter/resource/camera.wav
Binary file not shown.
180 changes: 51 additions & 129 deletions rostwitter/scripts/tweet.py
Original file line number Diff line number Diff line change
@@ -1,139 +1,61 @@
#!/usr/bin/env python
import imp ## for rosbuild
import rospy
import yaml,sys
import re, os
from io import BytesIO
from StringIO import StringIO

from std_msgs.msg import String

global Api, CKEY, CSECRET, AKEY, ASECRET

import requests
from requests_oauthlib import OAuth1
import base64
import json as simplejson
#!/usr/bin/env python

# https://raw.githubusercontent.com/bear/python-twitter/v1.1/twitter.py
import os
import re
import sys

class twitter(object):
def __init__(self,
consumer_key=None,
consumer_secret=None,
access_token_key=None,
access_token_secret=None):
self._consumer_key = consumer_key
self._consumer_secret = consumer_secret
self._access_token_key = access_token_key
self._access_token_secret = access_token_secret

self.__auth = OAuth1(self._consumer_key, self._consumer_secret,
self._access_token_key, self._access_token_secret)
self._requests_timeout = 60
import rospy
from std_msgs.msg import String

def _RequestUrl(self, url, verb, data=None):
if verb == 'POST':
if data.has_key('media'):
return requests.post(
url,
files=data,
auth=self.__auth,
timeout=self._requests_timeout
)
from rostwitter.twitter import Twitter
from rostwitter.util import load_oauth_settings


class Tweet(object):
def __init__(self):
account_info = rospy.get_param(
'account_info', '/var/lib/robot/account.yaml')
ckey, csecret, akey, asecret = load_oauth_settings(account_info)
if not ckey or not csecret or not akey or not asecret:
sys.exit(1)

self.api = Twitter(
consumer_key=ckey,
consumer_secret=csecret,
access_token_key=akey,
access_token_secret=asecret)
self.sub = rospy.Subscriber("tweet", String, self.tweet_cb)

def tweet_cb(self, msg):
message = msg.data
rospy.loginfo(rospy.get_name() + " sending %s", message)

# search word start from / and end with {.jpeg,.jpg,.png,.gif}
m = re.search('/\S+\.(jpeg|jpg|png|gif)', message)
ret = None
if m:
filename = m.group(0)
message = re.sub(filename, "", message)
if os.path.exists(filename):
rospy.loginfo(
rospy.get_name() + " tweet %s with file %s",
message, filename)
# 140 - len("http://t.co/ssssssssss")
ret = self.api.post_media(message[0:116], filename)
if 'errors' in ret:
rospy.logerr('Failed to post: {}'.format(ret))
# ret = self.api.post_update(message)
else:
return requests.post(
url,
data=data,
auth=self.__auth,
timeout=self._requests_timeout
)
if verb == 'GET':
url = self._BuildUrl(url, extra_params=data)
return requests.get(
url,
auth=self.__auth,
timeout=self._requests_timeout
)
return 0 # if not a POST or GET request

def PostUpdate(self, status):
url = 'https://api.twitter.com/1.1/statuses/update.json'

data = {'status': StringIO(status)}
json = self._RequestUrl(url, 'POST', data=data)
data = simplejson.loads(json.content)
if 'error' in data:
raise Exception(data)
return data

def PostMedia(self, status, media):
url = 'https://api.twitter.com/1.1/statuses/update_with_media.json'

data = {'status': StringIO(status)}
data['media'] = open(str(media), 'rb').read()
json = self._RequestUrl(url, 'POST', data=data)
data = simplejson.loads(json.content)
if 'errors' in data:
raise Exception(data)
return data

def tweet(dat):
global Api
message = dat.data
rospy.loginfo(rospy.get_name() + " sending %s", message)

# search word start from / and end with {.jpeg,.jpg,.png,.gif}
m = re.search('/\S+\.(jpeg|jpg|png|gif)', message)
ret = None
if m:
filename = m.group(0)
message = re.sub(filename,"",message)
if os.path.exists(filename):
rospy.loginfo(rospy.get_name() + " tweet %s with file %s", message, filename)
ret = Api.PostMedia(message[0:116], filename) # 140 - len("http://t.co/ssssssssss")
#ret = Api.PostUpdate(message)
rospy.logerr(rospy.get_name() + " %s could not find", filename)
else:
rospy.logerr(rospy.get_name() + " %s could not find", filename)
else:
ret = Api.PostUpdate(message[0:140])
## seg faults if message is longer than 140 byte ???

rospy.loginfo(rospy.get_name() + " receiving %s", ret)
return

def load_oauth_settings():
global CKEY, CSECRET, AKEY, ASECRET
account_info = rospy.get_param('account_info', '/var/lib/robot/account.yaml')
ret = self.api.post_update(message[0:140])
if 'errors' in ret:
rospy.logerr('Failed to post: {}'.format(ret))
# seg faults if message is longer than 140 byte ???
rospy.loginfo(rospy.get_name() + " receiving %s", ret)

try:
key = yaml.load(open(account_info))
CKEY = key['CKEY']
CSECRET = key['CSECRET']
AKEY = key['AKEY']
ASECRET = key['ASECRET']
except IOError as e:
rospy.logerr('"%s" not found'%account_info)
rospy.logerr("$ get access token from https://apps.twitter.com/")
rospy.logerr("cat /var/lib/robot/%s <<EOF"%account_info)
rospy.logerr("CKEY: xxx")
rospy.logerr("CSECRET: xxx")
rospy.logerr("AKEY: xxx")
rospy.logerr("ASECRET: xxx")
rospy.logerr("EOF")
sys.exit(-1)

if __name__ == '__main__':
global Api
rospy.init_node('rostwitter', anonymous=True)
load_oauth_settings()
Api = twitter(consumer_key=CKEY,
consumer_secret=CSECRET,
access_token_key=AKEY,
access_token_secret=ASECRET)
rospy.Subscriber("tweet", String, tweet)
app = Tweet()
rospy.spin()




Loading

0 comments on commit 5bb94e8

Please sign in to comment.