"""
Colorful user's timeline stream
"""
-from multiprocessing import Process
-
import os
import os.path
import sys
import signal
import argparse
import time
+import threading
import requests
import webbrowser
from .config import *
from .consumer import *
from .interactive import *
-from .db import *
from .c_image import *
from .py3patch import *
# Global values
g = {}
-# Database
-db = RainbowDB()
+# Lock for streams
+StreamLock = threading.Lock()
# Commands
cmdset = [
'config',
'theme',
'h',
+ 'p',
+ 'r',
'c',
'q'
]
"""
Init function
"""
+ # Handle Ctrl C
+ ctrl_c_handler = lambda signum, frame: quit()
+ signal.signal(signal.SIGINT, ctrl_c_handler)
# Get name
t = Twitter(auth=authen())
name = '@' + t.account.verify_credentials()['screen_name']
files = os.listdir(os.path.dirname(__file__) + '/colorset')
themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
g['themes'] = themes
- db.theme_store(c['THEME'])
+ # Startup cmd
+ g['OSX_readline_bug'] = False
+ g['previous_cmd'] = ''
# Semaphore init
- db.semaphore_store(False)
+ c['lock'] = False
+ c['pause'] = False
+ # Init tweet dict and message dict
+ c['tweet_dict'] = []
+ c['message_dict'] = []
# Image on term
c['IMAGE_ON_TERM'] = args.image_on_term
keyword = g['stuff'].split()[1]
if keyword[0] == '#':
keyword = keyword[1:]
- # Kill old process
- os.kill(g['stream_pid'], signal.SIGKILL)
+ # Kill old thread
+ g['stream_stop'] = True
args.track_keywords = keyword
- # Start new process
- p = Process(
+ # Start new thread
+ th = threading.Thread(
target=stream,
args=(
c['PUBLIC_DOMAIN'],
args))
- p.start()
- g['stream_pid'] = p.pid
+ th.daemon = True
+ th.start()
# Personal stream
elif target == 'mine':
- # Kill old process
- os.kill(g['stream_pid'], signal.SIGKILL)
- # Start new process
- p = Process(
+ # Kill old thread
+ g['stream_stop'] = True
+ # Start new thread
+ th = threading.Thread(
target=stream,
args=(
c['USER_DOMAIN'],
args,
g['original_name']))
- p.start()
- g['stream_pid'] = p.pid
+ th.daemon = True
+ th.start()
printNicely('')
if args.filter:
printNicely(cyan('Only: ' + str(args.filter)))
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
tweet = t.statuses.show(id=tid)
screen_name = tweet['user']['screen_name']
text = tweet['text']
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
# Get display num if exist
try:
num = int(g['stuff'].split()[1])
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
t.favorites.create(_id=tid, include_entities=False)
printNicely(green('Favorited.'))
draw(t.statuses.show(id=tid))
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
user = t.statuses.show(id=tid)['user']['screen_name']
status = ' '.join(g['stuff'].split()[1:])
status = '@' + user + ' ' + status.decode('utf-8')
"""
t = Twitter(auth=authen())
try:
- rid = int(g['stuff'].split()[0])
+ id = int(g['stuff'].split()[0])
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
+ tid = c['tweet_dict'][id]
t.statuses.destroy(id=tid)
printNicely(green('Okay it\'s gone.'))
except:
printNicely(red('Sorry I can\'t understand.'))
return
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
t.favorites.destroy(_id=tid)
printNicely(green('Okay it\'s unfavorited.'))
draw(t.statuses.show(id=tid))
if target != 'image':
return
id = int(g['stuff'].split()[1])
- tid = db.rainbow_to_tweet_query(id)[0].tweet_id
+ tid = c['tweet_dict'][id]
tweet = t.statuses.show(id=tid)
media = tweet['entities']['media']
for m in media:
try:
if not g['stuff'].isdigit():
return
- tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id
+ tid = c['tweet_dict'][int(g['stuff'])]
tweet = t.statuses.show(id=tid)
link_ary = [
u for u in tweet['text'].split() if u.startswith('http://')]
"""
t = Twitter(auth=authen())
try:
- rid = int(g['stuff'].split()[0])
+ id = int(g['stuff'].split()[0])
except:
printNicely(red('Sorry I can\'t understand.'))
- mid = db.rainbow_to_message_query(rid)[0].message_id
+ mid = c['message_dict'][id]
t.direct_messages.destroy(id=mid)
printNicely(green('Message deleted.'))
slug=slug,
owner_screen_name=owner,
screen_name=user_name)
- printNicely(light_green('Added.'))
+ printNicely(green('Added.'))
except:
printNicely(light_magenta('I\'m sorry we can not add him/her.'))
slug=slug,
owner_screen_name=owner,
screen_name=user_name)
- printNicely(light_green('Gone.'))
+ printNicely(green('Gone.'))
except:
printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
t.lists.subscribers.create(
slug=slug,
owner_screen_name=owner)
- printNicely(light_green('Done.'))
+ printNicely(green('Done.'))
except:
printNicely(
light_magenta('I\'m sorry you can not subscribe to this list.'))
t.lists.subscribers.destroy(
slug=slug,
owner_screen_name=owner)
- printNicely(light_green('Done.'))
+ printNicely(green('Done.'))
except:
printNicely(
light_magenta('I\'m sorry you can not unsubscribe to this list.'))
name=name,
mode=mode,
description=description)
- printNicely(light_green(name + ' list is created.'))
+ printNicely(green(name + ' list is created.'))
except:
printNicely(red('Oops something is wrong with Twitter :('))
owner_screen_name=g['original_name'],
mode=mode,
description=description)
- printNicely(light_green(slug + ' list is updated.'))
+ printNicely(green(slug + ' list is updated.'))
except:
printNicely(red('Oops something is wrong with Twitter :('))
t.lists.destroy(
slug='-'.join(slug.split()),
owner_screen_name=g['original_name'])
- printNicely(light_green(slug + ' list is deleted.'))
+ printNicely(green(slug + ' list is deleted.'))
except:
printNicely(red('Oops something is wrong with Twitter :('))
if not g['stuff']:
for k in all_config:
line = ' ' * 2 + \
- light_green(k) + ': ' + light_yellow(str(all_config[k]))
+ green(k) + ': ' + light_yellow(str(all_config[k]))
printNicely(line)
guide = 'Detailed explanation can be found at ' + \
color_func(c['TWEET']['link'])(
if g['stuff'] in all_config:
k = g['stuff']
line = ' ' * 2 + \
- light_green(k) + ': ' + light_yellow(str(all_config[k]))
+ green(k) + ': ' + light_yellow(str(all_config[k]))
printNicely(line)
else:
printNicely(red('No such config key.'))
key = g['stuff'].split()[0]
try:
value = get_default_config(key)
- line = ' ' * 2 + light_green(key) + ': ' + light_magenta(value)
+ line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
printNicely(line)
except:
printNicely(
key = g['stuff'].split()[0]
try:
delete_config(key)
- printNicely(light_green('Config key is dropped.'))
+ printNicely(green('Config key is dropped.'))
except:
printNicely(red('No such config key.'))
# Set specific config
set_config(key, value)
# Apply theme immediately
if key == 'THEME':
- reload_theme(value)
+ c['THEME'] = reload_theme(value, c['THEME'])
g['decorated_name'] = lambda x: color_func(
c['DECORATED_NAME'])(
'[' + x + ']: ')
- printNicely(light_green('Updated successfully.'))
+ printNicely(green('Updated successfully.'))
except:
printNicely(light_magenta('Not valid value.'))
return
# Change theme
try:
# Load new theme
- reload_theme(g['stuff'])
+ c['THEME'] = reload_theme(g['stuff'], c['THEME'])
# Redefine decorated_name
g['decorated_name'] = lambda x: color_func(
c['DECORATED_NAME'])(
usage += '\n'
usage += s + grey(u'\u266A' + ' Screening \n')
usage += s * 2 + light_green('h') + ' will show this help again.\n'
+ usage += s * 2 + light_green('p') + ' will pause the stream.\n'
+ usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
usage += s * 2 + light_green('c') + ' will clear the screen.\n'
usage += s * 2 + light_green('q') + ' will quit.\n'
# End
'stream': help_stream,
}
if g['stuff']:
- d[g['stuff'].strip()]()
+ d.get(
+ g['stuff'].strip(),
+ lambda: printNicely(red('No such command.'))
+ )()
else:
printNicely(usage)
+def pause():
+ """
+ Pause stream display
+ """
+ c['pause'] = True
+ printNicely(green('Stream is paused'))
+
+
+def replay():
+ """
+ Replay stream
+ """
+ c['pause'] = False
+ printNicely(green('Stream is running back now'))
+
+
def clear():
"""
Clear screen
"""
Exit all
"""
- save_history()
- os.system('rm -rf rainbow.db')
- os.kill(g['stream_pid'], signal.SIGKILL)
+ try:
+ save_history()
+ printNicely(green('See you next time :)'))
+ except:
+ pass
sys.exit()
config,
theme,
help,
+ pause,
+ replay,
clear,
quit
]
'list',
'stream'
], # help
+ [], # pause
+ [], # reconnect
[], # clear
[], # quit
]
read_history()
reset()
while True:
+ # raw_input
if g['prefix']:
line = raw_input(g['decorated_name'](c['PREFIX']))
else:
line = raw_input()
+ # Save previous cmd in order to compare with readline buffer
+ g['previous_cmd'] = line.strip()
try:
cmd = line.split()[0]
except:
cmd = ''
+ # MacOSX readline bug (see "stream" function)
+ if g['OSX_readline_bug']:
+ cmd = cmd[1:]
+ g['OSX_readline_bug'] = False
g['cmd'] = cmd
try:
# Lock the semaphore
- db.semaphore_update(True)
+ c['lock'] = True
# Save cmd to global variable and call process
g['stuff'] = ' '.join(line.split()[1:])
# Process the command
else:
g['prefix'] = True
# Release the semaphore lock
- db.semaphore_update(False)
- except Exception as e:
- print e
+ c['lock'] = False
+ except Exception:
printNicely(red('OMG something is wrong with Twitter right now.'))
# These arguments are optional:
stream_args = dict(
timeout=args.timeout,
- block=not args.no_block,
+ block=False,
heartbeat_timeout=args.heartbeat_timeout)
# Track keyword
query_args = dict()
tweet_iter = stream.statuses.filter(**query_args)
else:
tweet_iter = stream.statuses.sample()
+ # Block new stream until other one exits
+ StreamLock.acquire()
+ g['stream_stop'] = False
for tweet in tweet_iter:
+ if(g['stream_stop']):
+ StreamLock.release()
+ break
if tweet is None:
- printNicely("-- None --")
+ pass
elif tweet is Timeout:
printNicely("-- Timeout --")
elif tweet is HeartbeatTimeout:
fil=args.filter,
ig=args.ignore,
)
+ # Current readline buffer
+ current_buffer = readline.get_line_buffer().strip()
+ # There is an unexpected behaviour in MacOSX readline:
+ # after completely delete a word after typing it,
+ # somehow readline buffer still contains
+ # the 1st character of that word
+ if g['previous_cmd'] != current_buffer:
+ if len(current_buffer) == 1:
+ current_buffer = ''
+ g['OSX_readline_bug'] = True
+ sys.stdout.write(
+ g['decorated_name'](c['PREFIX']) + current_buffer)
+ sys.stdout.flush()
elif tweet.get('direct_message'):
- print_message(tweet['direct_message'])
+ print_message(tweet['direct_message'], check_semaphore=True)
except TwitterHTTPError:
printNicely('')
printNicely(
except TwitterHTTPError:
printNicely('')
printNicely(
- magenta("Something wrong with Twitter Oauth right now :("))
- printNicely(
- magenta("Please delete ~/.rainbow_oauth and try again."))
+ magenta("We have maximum connection problem with twitter'stream API right now :("))
+ printNicely(magenta("Let's try again later."))
save_history()
- os.system('rm -rf rainbow.db')
sys.exit()
- # Spawn stream process
- p = Process(
+ # Spawn stream thread
+ th = threading.Thread(
target=stream,
args=(
c['USER_DOMAIN'],
args,
g['original_name']))
- p.start()
+ th.daemon = True
+ th.start()
# Start listen process
time.sleep(0.5)
g['reset'] = True
g['prefix'] = True
- g['stream_pid'] = p.pid
listen()