weetweet.py 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  1. #
  2. # Copyright (c) 2013 by DarkDefender <darkdefende (a) gmail.com>
  3. # File bugs here: https://github.com/DarkDefender/weetweet
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #
  17. import sys
  18. import ast
  19. import re
  20. import os
  21. import tempfile
  22. import time
  23. import calendar
  24. import socket
  25. # TODO:
  26. # Add desc for script options
  27. # This twitter plugin can be extended even more. Just look at the twitter api
  28. # doc here: https://dev.twitter.com/docs/api/1.1
  29. # Thanks to ttytter for interface ideas!
  30. # http://www.floodgap.com/software/ttytter/
  31. # I've borrowed some ideas, functions for ainmosni and his twitter plugin
  32. # https://github.com/ainmosni/weetwit
  33. weechat_call = True
  34. import_ok = True
  35. required_twitter_version = "1.14.1"
  36. try:
  37. import weechat
  38. except:
  39. #import html parser so we can convert html strings to plain text
  40. try:
  41. import html.parser
  42. except:
  43. print("You need to have python3 installed to run this script!")
  44. exit(0)
  45. weechat_call = False
  46. try:
  47. #Import python twitter lib
  48. from twitter import *
  49. except:
  50. import_ok = False
  51. try:
  52. #Import for version checking
  53. from pkg_resources import parse_version, get_distribution
  54. version = get_distribution("twitter").version
  55. if parse_version(required_twitter_version) > parse_version(version):
  56. import_ok = False
  57. except:
  58. if weechat_call:
  59. weechat.prnt("", "You need the have pkg_resources installed for version checking")
  60. else:
  61. print("You need the have pkg_resources installed for version checking")
  62. # These two keys is what identifies this twitter client as "weechat twitter"
  63. # If you want to change it you can register your own keys at:
  64. # https://dev.twitter.com/apps/new
  65. CONSUMER_SECRET = 'ivx3oxxkSOAOofRuhmGXQK4nkLFNXD94wbJiRUBhN1g'
  66. CONSUMER_KEY = 'NVkYe8DAeaw6YRcjw662ZQ'
  67. script_options = {
  68. "oauth_token" : "",
  69. "oauth_secret" : "",
  70. "auth_complete" : False,
  71. "screen_name" : "",
  72. "last_id" : "",
  73. "print_id" : True,
  74. "alt_rt_style" : False,
  75. "home_replies" : False,
  76. "tweet_nicks" : True,
  77. }
  78. #TODO have a dict for each buffer
  79. tweet_dict = {'cur_index': "a0"}
  80. #Mega command dict
  81. command_dict = dict(user="u",replies="r",view_tweet="v",
  82. retweet="rt",delete="d",tweet="t",reply="re",new_tweets="new",
  83. follow_user="follow",unfollow_user="unfollow",following="f",
  84. followers="fo",about="a",block="b",unblock="ub",
  85. blocked_users="blocks",favorite="fav",unfavorite="unfav",
  86. favorites="favs", rate_limits="limits",home_timeline="home",
  87. clear_nicks="cnicks",clear_buffer="clear",create_stream="stream",
  88. restart_home_stream="re_home")
  89. desc_dict = dict(
  90. user="<user>[<id><count>|<id>|<count>], Request user timeline, " +
  91. "if <id> is given it will get tweets older than <id>, " +
  92. "<count> is how many tweets to get, valid number is 1-200",
  93. replies="[<id><count>|<id>|<count>],Get any replies/mentions of you " +
  94. "if <id> is given it will get tweets older than <id>, " +
  95. "<count> is how many tweets to get, valid number is 1-200",
  96. view_tweet="<id>, View/get tweet with <id>",
  97. retweet="<id>, Retweet <id>",
  98. delete="<id>, Delete tweet <id>. You can only delete your own tweets...",
  99. tweet="<text>Tweet the text following this command",
  100. reply="<id><text>, reply to <id>. You need to have @<username> " +
  101. "of the user that you reply to in the tweet text. If this is not " +
  102. "the case this will be treated like a normal tweet instead.",
  103. new_tweets="Get new tweets from your home_timeline. This is only " +
  104. "useful if you have disabled the auto updater",
  105. follow_user="<user>, Add user to people you follow",
  106. unfollow_user="<user>, Remove user for people you follow",
  107. following="[|<id>|<user>|<user><id>], Show 'friends' of <user> or " +
  108. "if no user were given show the people you follow. If not all " +
  109. "followers were printed supply the <id> of the last list to get " +
  110. "the new batch of nicks",
  111. followers="[|<id>|<user>|<user><id>], Who followes <user> or " +
  112. "if no user were given show your follower. If not all " +
  113. "followers were printed supply the <id> of the last list to get " +
  114. "the new batch of nicks",
  115. about="<user>, Print info about <user>",
  116. block="<user>, Block <user>",
  117. unblock="<user>, Unblock <user>",
  118. blocked_users="Print a list of users you have currently blocked",
  119. favorite="<id>, Add tweet <id> to you favorites",
  120. unfavorite="<id>, Remove tweet <id> from yout favorites",
  121. favorites="[|<user>][<id><count>|<id>|<count>], Request <user> favs, " +
  122. "if <user> is not given get your own favs. " +
  123. "If <id> is given it will get tweets older than <id>, " +
  124. "<count> is how many tweets to get, valid number is 1-200",
  125. rate_limits="[|<sub_group>], get the current status of the twitter " +
  126. "api limits. It prints how much you have left/used. " +
  127. " if <sub_group> is supplied it will only get/print that sub_group.",
  128. home_timeline="[<id><count>|<id>|<count>],Get tweets from you home " +
  129. "timeline" +
  130. "if <id> is given it will get tweets older than <id>, " +
  131. "<count> is how many tweets to get, valid number is 1-200",
  132. clear_nicks="Clear nicks from the 'Tweet_parse' nick group. "+
  133. "These nicks are parsed from recived tweets, it can get " +
  134. "messy at times...",
  135. clear_buffer="Clear the twitter buffer of text "+
  136. "same as '/buffer clear'",
  137. create_stream="Create a twitter stream with the following filter "+
  138. "options: <user to stream> & <keywords>. Note that they must be " +
  139. "seperated by a ' & '. To only use keywords just have ' & ' in the "+
  140. "begininng.\n NOTE: you can only have one stream at a time because "+
  141. "twitter will IP ban you if you repeatedly request more than one "+
  142. "stream.",
  143. restart_home_stream="Restart the home timeline stream after it has " +
  144. "shutdown.")
  145. SCRIPT_NAME = "weetweet"
  146. SCRIPT_FILE_PATH = os.path.abspath(__file__)
  147. twit_buf = ""
  148. timer_hook = ""
  149. sock_hooks = {}
  150. proc_hooks = {}
  151. sock_fd_dict = {}
  152. tweet_nicks_group = {}
  153. friends_nicks_group = {}
  154. html_escape_table = {
  155. '"': "&quot;",
  156. "'": "&apos;",
  157. }
  158. def html_escape(text):
  159. """Produce entities within text."""
  160. return "".join(html_escape_table.get(c,c) for c in text)
  161. def dict_tweet(tweet_id):
  162. cur_index = tweet_dict['cur_index']
  163. if not tweet_id in tweet_dict.values():
  164. if cur_index == 'z9':
  165. cur_index = 'a0'
  166. if cur_index[1] == '9':
  167. cur_index = chr(ord(cur_index[0]) + 1) + '0'
  168. else:
  169. cur_index = cur_index[0] + chr(ord(cur_index[1]) + 1)
  170. tweet_dict[cur_index] = tweet_id
  171. tweet_dict['cur_index'] = cur_index
  172. return cur_index
  173. else:
  174. for index, t_id in tweet_dict.items():
  175. if t_id == tweet_id:
  176. return index
  177. def read_config():
  178. for item in script_options:
  179. script_options[item] = weechat.config_string(weechat.config_get("plugins.var.python."+SCRIPT_NAME+"." + item))
  180. for item in ["auth_complete","print_id","alt_rt_style","home_replies","tweet_nicks"]:
  181. #Convert to bool
  182. script_options[item] = weechat.config_string_to_boolean(script_options[item])
  183. def config_cb(data, option, value):
  184. """Callback called when a script option is changed."""
  185. # for example, read all script options to script variables...
  186. # ...
  187. read_config()
  188. return weechat.WEECHAT_RC_OK
  189. def add_to_nicklist(buf, nick, group=""):
  190. """Add nick to the nicklist."""
  191. if group == "":
  192. group = friends_nicks_group[buf]
  193. weechat.nicklist_add_nick(buf, group, nick, 'bar_fg', '', '', 1)
  194. def remove_from_nicklist(buf, nick, group=""):
  195. """Remove nick from the nicklist."""
  196. if group == "":
  197. group = friends_nicks_group[buf]
  198. nick_ptr = weechat.nicklist_search_nick(buf, group, nick)
  199. weechat.nicklist_remove_nick(buf, nick_ptr)
  200. def parse_for_nicks(text,buffer):
  201. #Parse text for twitter nicks and add them to nicklist
  202. regex = re.compile(r'@([A-Za-z0-9_]+)')
  203. reset = weechat.color('reset')
  204. for word in text.split():
  205. match = re.search(regex,word)
  206. if str(type(match)) == "<type '_sre.SRE_Match'>":
  207. nick = word[match.start(1):match.end(0)]
  208. add_to_nicklist(buffer,nick,tweet_nicks_group[buffer])
  209. def print_tweet_data(buffer,tweets,data):
  210. for message in tweets:
  211. nick = message[1]
  212. text = message[3]
  213. reply_id = ""
  214. if script_options['tweet_nicks']:
  215. parse_for_nicks(text,buffer)
  216. add_to_nicklist(buffer,nick,tweet_nicks_group[buffer])
  217. if script_options['print_id']:
  218. t_id = weechat.color('reset') + ' ' + dict_tweet(message[2])
  219. else:
  220. t_id = ''
  221. if len(message) == 5:
  222. #This is a reply to a tweet
  223. arrow_col = weechat.color('chat_prefix_suffix')
  224. reset_col = weechat.color('reset')
  225. reply_id = arrow_col + "<" + reset_col + dict_tweet(message[4]) + arrow_col + "> " + reset_col
  226. temp_text = text
  227. text = reply_id
  228. reply_id = temp_text
  229. weechat.prnt_date_tags(buffer, message[0], "notify_message",
  230. "%s%s\t%s%s" % (nick, t_id, text,reply_id))
  231. if data == "id":
  232. try:
  233. if script_options['last_id'] < tweets[-1][2]:
  234. script_options['last_id'] = tweets[-1][2]
  235. # Save last id
  236. weechat.config_set_plugin("last_id",script_options["last_id"])
  237. except:
  238. pass
  239. def trim_tweet_data(tweet_data, screen_name, alt_rt_style):
  240. # Because of the huge amount of data, we need to cut down on most of it because we only really want
  241. # a small subset of it. This also prevents the output buffer from overflowing when fetching many tweets
  242. # at once.
  243. h = html.parser.HTMLParser()
  244. output = []
  245. for message in tweet_data:
  246. if alt_rt_style and message.get('retweeted_status'):
  247. if message['user']['screen_name'] == screen_name:
  248. #escape highlighting
  249. message['user']['screen_name'] = "<you>"
  250. message['text'] = message['retweeted_status']['text'] + " (retweeted by " + message['user']['screen_name'] + ")"
  251. message['user'] = message['retweeted_status']['user']
  252. mes_list = [calendar.timegm(time.strptime(message['created_at'],'%a %b %d %H:%M:%S +0000 %Y')),
  253. message['user']['screen_name'],
  254. message['id_str'],
  255. #convert text to bytes so python2 can read it correctly
  256. #TODO remove the encode when weechat is running python3 as default
  257. h.unescape(message['text']).encode('utf-8')]
  258. if message["in_reply_to_status_id_str"] != None:
  259. mes_list.append(message["in_reply_to_status_id_str"])
  260. output.append(mes_list)
  261. output.reverse()
  262. return output
  263. def twitter_stream_cb(buffer,fd):
  264. #accept connection
  265. server = sock_fd_dict[sock_fd_dict[fd]]
  266. conn, addr = server.accept()
  267. error = False
  268. tweet = ""
  269. data = True
  270. while data:
  271. try:
  272. data = conn.recv(1024).decode('utf-8')
  273. tweet += data
  274. except:
  275. break
  276. try:
  277. tweet = ast.literal_eval(tweet)
  278. except:
  279. weechat.prnt(buffer, "Error resv stream message")
  280. return weechat.WEECHAT_RC_OK
  281. #Is this a text message (normal tweet)?
  282. if isinstance(tweet,list):
  283. if buffer == twit_buf:
  284. #Update last recv id
  285. print_tweet_data(buffer,tweet,"id")
  286. else:
  287. print_tweet_data(buffer,tweet,"")
  288. elif False:
  289. #https://dev.twitter.com/docs/streaming-apis/messages
  290. #TODO handle stream events
  291. weechat.prnt(buffer, "%s%s" % (weechat.prefix("network"),
  292. "recv stream data: " + str(tweet)))
  293. conn.close()
  294. return weechat.WEECHAT_RC_OK
  295. def twitter_stream(cmd_args):
  296. if len(cmd_args) < 5:
  297. return "Invalid stream command"
  298. if not os.path.exists(cmd_args[4]):
  299. return "The socket file doesn't exist! " + cmd_args[4]
  300. oauth_token = cmd_args[1]
  301. oauth_secret= cmd_args[2]
  302. try:
  303. if cmd_args[-1][0] == "{":
  304. option_dict = ast.literal_eval(cmd_args[-1])
  305. cmd_args.pop(-1)
  306. home_replies = option_dict['home_replies']
  307. alt_rt_style = option_dict['alt_rt_style']
  308. screen_name = option_dict['screen_name']
  309. name = option_dict['name']
  310. stream_args = option_dict['stream_args']
  311. except:
  312. return "Error starting stream, no option arguments"
  313. def connect():
  314. client = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM )
  315. client.connect(cmd_args[4])
  316. #Don't block, timeout if no data is present
  317. client.setblocking(0)
  318. return client
  319. # These arguments are optional. But the current code only handles this
  320. # configuration. So it's defined here if the defaults change.
  321. stream_options = dict( timeout=None, block=True, heartbeat_timeout=90 )
  322. if name == "twitter":
  323. #home timeline stream
  324. stream = TwitterStream(auth=OAuth(
  325. oauth_token, oauth_secret, CONSUMER_KEY, CONSUMER_SECRET),
  326. domain="userstream.twitter.com", **stream_options)
  327. if home_replies:
  328. tweet_iter = stream.user(replies="all")
  329. else:
  330. tweet_iter = stream.user()
  331. else:
  332. h = html.parser.HTMLParser()
  333. args = stream_args.split(" & ")
  334. stream = TwitterStream(auth=OAuth(
  335. oauth_token, oauth_secret, CONSUMER_KEY, CONSUMER_SECRET),
  336. **stream_options)
  337. twitter = Twitter(auth=OAuth(
  338. oauth_token, oauth_secret, CONSUMER_KEY, CONSUMER_SECRET))
  339. if args[0] != "":
  340. follow = ",".join(h.unescape(args[0]).split())
  341. twitter_data = twitter.users.lookup(screen_name=follow)
  342. follow_ids = ""
  343. for user in twitter_data:
  344. follow_ids += user['id_str'] + ","
  345. follow_ids = follow_ids[:-1]
  346. if len(args) == 2 and args[1] != "":
  347. track = ",".join(h.unescape(args[1]).split())
  348. tweet_iter = stream.statuses.filter(track=track,follow=follow_ids)
  349. else:
  350. tweet_iter = stream.statuses.filter(follow=follow_ids)
  351. else:
  352. track = ",".join(h.unescape(args[1]).split())
  353. tweet_iter = stream.statuses.filter(track=track)
  354. stream_end_message = "Unknown reason"
  355. # Iterate over the stream.
  356. for tweet in tweet_iter:
  357. # You must test that your tweet has text. It might be a delete
  358. # or data message.
  359. if tweet is None:
  360. stream_end_message = "'None' reply"
  361. elif tweet is stream.Timeout:
  362. stream_end_message = "Timeout"
  363. elif tweet is stream.HeartbeatTimeout:
  364. stream_end_message = "Heartbeat Timeout"
  365. elif tweet is stream.Hangup:
  366. stream_end_message = "Hangup"
  367. elif tweet.get('text'):
  368. tweet = trim_tweet_data([tweet],screen_name,alt_rt_style)
  369. client = connect()
  370. client.sendall(bytes(str(tweet),"utf-8"))
  371. client.close()
  372. stream_end_message = "Text message"
  373. else:
  374. #Got a other type of message
  375. client = connect()
  376. client.sendall(bytes(str(tweet),"utf-8"))
  377. client.close()
  378. stream_end_message = "Unhandled type message"
  379. return "Stream shut down after: " + stream_end_message + ". You'll have to restart the stream manually."
  380. def stream_close_cb(name,buffer):
  381. global sock_fd_dict
  382. global proc_hooks
  383. weechat.unhook(sock_hooks[name])
  384. weechat.unhook(proc_hooks[name])
  385. #remove fd key
  386. for key, value in sock_fd_dict.items():
  387. if value == name:
  388. sock_fd_dict.pop(key, None)
  389. break
  390. sock_fd_dict[name].close()
  391. proc_hooks.pop(name,None)
  392. sock_fd_dict.pop(name, None)
  393. return weechat.WEECHAT_RC_OK
  394. def create_stream(name, args = ""):
  395. global sock_fd_dict
  396. global proc_hooks
  397. global sock_hooks
  398. if proc_hooks.get(name):
  399. return "Stream has already been created, close it before trying to open a new one"
  400. #Check if buffer exists
  401. buffer = weechat.buffer_search("python", name)
  402. if buffer == "":
  403. buffer = weechat.buffer_new(name, "buffer_input_cb", name, "stream_close_cb", name)
  404. setup_buffer(buffer)
  405. if not sock_fd_dict.get(name):
  406. file_name = tempfile.gettempdir() + "/we_tw_" + name
  407. if os.path.exists(file_name):
  408. os.remove(file_name)
  409. server = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM )
  410. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  411. server.bind(file_name)
  412. #Don't block, timeout if no data is present
  413. server.setblocking(0)
  414. server.listen(1)
  415. file_fd = server.fileno()
  416. sock_fd_dict[str(file_fd)] = name
  417. sock_fd_dict[name] = server
  418. sock_hooks[name] = weechat.hook_fd(file_fd, 1, 0, 0, "twitter_stream_cb", buffer)
  419. options = dict(screen_name = script_options['screen_name'], name = name,
  420. alt_rt_style = int(script_options['alt_rt_style']),
  421. home_replies = int(script_options['home_replies']),
  422. stream_args = args)
  423. proc_hooks[name] = weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  424. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  425. "stream " + file_name + ' "' + str(options) + '"', 0 , "my_process_cb", str([buffer,"Stream"]))
  426. return "Started stream"
  427. def my_process_cb(data, command, rc, out, err):
  428. if rc == weechat.WEECHAT_HOOK_PROCESS_ERROR:
  429. weechat.prnt("", "Error with command '%s'" %
  430. command.replace(script_options["oauth_token"],"").replace(script_options["oauth_secret"],""))
  431. return weechat.WEECHAT_RC_OK
  432. data = ast.literal_eval(data)
  433. buffer = data[0]
  434. end_mes = data[1]
  435. if out != "":
  436. if out[0] != "[" and out[0] != "{":
  437. #If message is just a string print it
  438. weechat.prnt(buffer, "%s%s" % (weechat.prefix("network"), out))
  439. return weechat.WEECHAT_RC_OK
  440. process_output = ast.literal_eval(out)
  441. #List message
  442. if len(end_mes) >= 1 and end_mes[0] == "L":
  443. if isinstance(process_output[-1], int):
  444. t_id = dict_tweet(str(process_output[-1])) + "\t"
  445. process_output = process_output[:-1]
  446. more = " ..."
  447. else:
  448. t_id = weechat.prefix("network")
  449. more = ""
  450. for nick in process_output:
  451. if end_mes == "LYFollowing":
  452. add_to_nicklist(buffer,nick)
  453. elif script_options['tweet_nicks']:
  454. add_to_nicklist(buffer,nick,tweet_nicks_group[buffer])
  455. weechat.prnt_date_tags(buffer, 0, "no_highlight",
  456. "%s%s: %s%s" % (t_id, end_mes[1:], process_output, more))
  457. return weechat.WEECHAT_RC_OK
  458. if end_mes == "About":
  459. weechat.prnt(buffer, "Nick: %s | Name: %s | Protected: %s" % (process_output['screen_name'],
  460. process_output['name'],
  461. process_output['protected']))
  462. weechat.prnt(buffer, "Description: %s" % process_output['description'])
  463. weechat.prnt(buffer, "Location: %s | Time zone: %s" % (process_output['location'], process_output['time_zone']))
  464. weechat.prnt(buffer, "Created at: %s | Verified user: %s" % (process_output['created_at'], process_output['verified']))
  465. weechat.prnt(buffer, "Following: %s | Followers: %s | Favourites: %s | Tweets: %s" % (process_output['friends_count'],
  466. process_output['followers_count'],
  467. process_output['favourites_count'],
  468. process_output['statuses_count']))
  469. weechat.prnt(buffer, "Are you currently following this person: %s" % (process_output['following']))
  470. return weechat.WEECHAT_RC_OK
  471. elif end_mes == "Stream":
  472. #Clean up the stream hooks
  473. name = weechat.buffer_get_string(buffer, "name")
  474. stream_close_cb(name, buffer)
  475. #TODO restart stream correctly
  476. #create_stream(name)
  477. print_tweet_data(buffer,process_output,end_mes)
  478. if end_mes != "id" and end_mes != "":
  479. weechat.prnt(buffer, "%s%s" % (weechat.prefix("network"), end_mes))
  480. if err != "":
  481. weechat.prnt("", "stderr: %s" % err)
  482. return weechat.WEECHAT_RC_OK
  483. def get_twitter_data(cmd_args):
  484. # Read the oauth token and auth with the twitter api.
  485. # Return the requested tweets
  486. no_home_replies = True
  487. alt_rt_style = False
  488. screen_name = ""
  489. h = html.parser.HTMLParser()
  490. try:
  491. if cmd_args[-1][0] == "[":
  492. option_list = ast.literal_eval(cmd_args[-1])
  493. cmd_args.pop(-1)
  494. if "home_replies" in option_list:
  495. no_home_replies = False
  496. if "alt_rt_style" in option_list:
  497. alt_rt_style = True
  498. screen_name = option_list[0]
  499. except:
  500. pass
  501. if len(cmd_args) < 4:
  502. return "Invalid command"
  503. oauth_token = cmd_args[1]
  504. oauth_secret= cmd_args[2]
  505. if cmd_args[3] == "auth":
  506. twitter = Twitter(
  507. auth=OAuth(oauth_token, oauth_secret, CONSUMER_KEY, CONSUMER_SECRET),
  508. format='', api_version=None)
  509. if len(cmd_args) == 5:
  510. #pin
  511. return twitter.oauth.access_token(oauth_verifier=cmd_args[4])
  512. else:
  513. return twitter.oauth.request_token()
  514. try:
  515. twitter = Twitter(auth=OAuth(
  516. oauth_token, oauth_secret, CONSUMER_KEY, CONSUMER_SECRET))
  517. if cmd_args[3] == "settings":
  518. #this only gets called from within weechat
  519. return twitter.account.settings()['screen_name']
  520. elif cmd_args[3] == "u":
  521. kwargs = dict(count=20, screen_name=cmd_args[4])
  522. if len(cmd_args) == 7:
  523. kwargs['count'] = int(cmd_args[6])
  524. kwargs['max_id'] = cmd_args[5]
  525. elif len(cmd_args) == 6:
  526. if int(cmd_args[5]) <= 200:
  527. kwargs['count'] = int(cmd_args[5])
  528. else:
  529. kwargs['max_id'] = cmd_args[5]
  530. tweet_data = twitter.statuses.user_timeline(**kwargs)
  531. elif cmd_args[3] == "r":
  532. if len(cmd_args) == 6:
  533. kwargs = dict(count=int(cmd_args[5]), max_id=cmd_args[4])
  534. tweet_data = twitter.statuses.mentions_timeline(**kwargs)
  535. elif len(cmd_args) == 5:
  536. if int(cmd_args[4]) <= 200:
  537. tweet_data = twitter.statuses.mentions_timeline(count=int(cmd_args[4]))
  538. else:
  539. tweet_data = twitter.statuses.mentions_timeline(max_id=cmd_args[4])
  540. else:
  541. tweet_data = twitter.statuses.mentions_timeline()
  542. elif cmd_args[3] == "v":
  543. tweet_data = [twitter.statuses.show._(cmd_args[4])()]
  544. elif cmd_args[3] == "rt":
  545. tweet_data = [twitter.statuses.retweet._(cmd_args[4])()]
  546. #The home stream prints you messages as well...
  547. # TODO add a switch to print this if the user has deatived the home timeline stream.
  548. # For all commands like this!
  549. tweet_data = []
  550. elif cmd_args[3] == "d":
  551. #deletes tweet made by the user _(...) converts the id string to a call
  552. #returns the tweet that was deleted (not a list(dict) just a dict)
  553. #make it into a list so we don't have to write special cases for this
  554. tweet_data = [twitter.statuses.destroy._(cmd_args[4])()]
  555. elif cmd_args[3] == "t":
  556. #returns the tweet that was sent (not a list(dict) just a dict)
  557. #make it into a list so we don't have to write special cases for this
  558. tweet_data = [twitter.statuses.update(status=h.unescape(cmd_args[4]))]
  559. #The home stream prints you messages as well...
  560. tweet_data = []
  561. elif cmd_args[3] == "re":
  562. tweet_data = [twitter.statuses.update(status=h.unescape(cmd_args[5]),
  563. in_reply_to_status_id=cmd_args[4])]
  564. #The home stream prints you messages as well...
  565. tweet_data = []
  566. elif cmd_args[3] == "new":
  567. tweet_data = twitter.statuses.home_timeline(since_id = cmd_args[4], count=200, exclude_replies = no_home_replies)
  568. if tweet_data == []:
  569. return "No new tweets available."
  570. elif cmd_args[3] == "follow":
  571. tweet_data = []
  572. twitter.friendships.create(screen_name = cmd_args[4])
  573. elif cmd_args[3] == "unfollow":
  574. tweet_data = []
  575. twitter.friendships.destroy(screen_name = cmd_args[4])
  576. elif cmd_args[3] == "f" or cmd_args[3] == "fo":
  577. if len(cmd_args) == 6:
  578. kwargs = dict(screen_name = cmd_args[4], stringify_ids = True, cursor = int(cmd_args[5]), count = 250)
  579. else:
  580. kwargs = dict(screen_name = cmd_args[4], stringify_ids = True, cursor = -1, count = 250)
  581. if cmd_args[3] == "f":
  582. tweet_data = twitter.friends.ids(**kwargs)
  583. else:
  584. tweet_data = twitter.followers.ids(**kwargs)
  585. kwargs['cursor'] = tweet_data['next_cursor']
  586. friend_ids = tweet_data['ids']
  587. friend_list = list()
  588. while len(friend_ids) > 100:
  589. tweet_data = twitter.users.lookup(user_id=",".join(friend_ids[:100]))
  590. friend_ids = friend_ids[100:]
  591. for user in tweet_data:
  592. friend_list.append(user['screen_name'])
  593. tweet_data = twitter.users.lookup(user_id=",".join(friend_ids))
  594. for user in tweet_data:
  595. friend_list.append(user['screen_name'])
  596. if kwargs['cursor'] != 0:
  597. friend_list.append(kwargs['cursor'])
  598. return friend_list
  599. elif cmd_args[3] == "a":
  600. return twitter.users.show(screen_name = cmd_args[4])
  601. elif cmd_args[3] == "b":
  602. tweet_data = []
  603. twitter.blocks.create(screen_name = cmd_args[4])
  604. elif cmd_args[3] == "ub":
  605. tweet_data = []
  606. twitter.blocks.destroy(screen_name = cmd_args[4])
  607. elif cmd_args[3] == "blocks":
  608. tweet_data = twitter.blocks.list(skip_status = True)
  609. block_list = list()
  610. for user in tweet_data['users']:
  611. block_list.append(user['screen_name'])
  612. return block_list
  613. elif cmd_args[3] == "fav":
  614. tweet_data = [twitter.favorites.create(_id=cmd_args[4])]
  615. elif cmd_args[3] == "unfav":
  616. tweet_data = [twitter.favorites.destroy(_id=cmd_args[4])]
  617. elif cmd_args[3] == "favs":
  618. if len(cmd_args) >= 5:
  619. kwargs = dict()
  620. if not cmd_args[4].isdigit():
  621. kwargs['screen_name'] = cmd_args[4]
  622. cmd_args.pop(4)
  623. if len(cmd_args) == 5:
  624. if int(cmd_args[4]) <= 200:
  625. kwargs['count'] = int(cmd_args[4])
  626. else:
  627. kwargs['max_id'] = cmd_args[4]
  628. elif len(cmd_args) == 6:
  629. kwargs['count'] = int(cmd_args[5])
  630. kwargs['max_id'] = cmd_args[4]
  631. tweet_data = twitter.favorites.list(**kwargs)
  632. else:
  633. tweet_data = twitter.favorites.list()
  634. elif cmd_args[3] == "limits":
  635. output = ""
  636. if len(cmd_args) >= 5:
  637. tweet_data = twitter.application.rate_limit_status(resources=",".join(cmd_args[4:]))
  638. else:
  639. tweet_data = twitter.application.rate_limit_status()
  640. for res in tweet_data['resources']:
  641. output += res + ":\n"
  642. for sub_res in tweet_data['resources'][res]:
  643. output += " " + sub_res[len(res)+2:] + ":\n"
  644. output += " " + 'reset' + ": " + time.strftime('%Y-%m-%d %H:%M:%S',
  645. time.localtime(tweet_data['resources'][res][sub_res]['reset'])) + "\n"
  646. output += " " + 'limit' + ": " + str(tweet_data['resources'][res][sub_res]['limit']) + "\n"
  647. output += " " + 'remaining' + ": " + str(tweet_data['resources'][res][sub_res]['remaining']) + "\n"
  648. return output
  649. elif cmd_args[3] == "home":
  650. if len(cmd_args) == 6:
  651. kwargs = dict(count=int(cmd_args[5]), max_id=cmd_args[4], exclude_replies = no_home_replies)
  652. tweet_data = twitter.statuses.home_timeline(**kwargs)
  653. elif len(cmd_args) == 5:
  654. if int(cmd_args[4]) <= 200:
  655. tweet_data = twitter.statuses.home_timeline(count=int(cmd_args[4]), exclude_replies = no_home_replies)
  656. else:
  657. tweet_data = twitter.statuses.home_timeline(max_id=cmd_args[4], exclude_replies = no_home_replies)
  658. else:
  659. tweet_data = twitter.statuses.home_timeline(exclude_replies = no_home_replies)
  660. else:
  661. return "Invalid command: " + cmd_args[3]
  662. except:
  663. return "Unexpected error in get_twitter_data:%s\n Call: %s" % (sys.exc_info(), cmd_args[3])
  664. return trim_tweet_data(tweet_data,screen_name,alt_rt_style)
  665. # callback for data received in input
  666. def buffer_input_cb(data, buffer, input_data):
  667. # ...
  668. end_message = ""
  669. options = [script_options['screen_name']]
  670. if script_options['alt_rt_style']:
  671. options.append("alt_rt_style")
  672. if script_options['home_replies']:
  673. options.append("home_replies")
  674. if input_data[0] == ':':
  675. if data != "silent":
  676. weechat.prnt_date_tags(buffer, 0, "no_highlight", input_data)
  677. input_args = input_data.split()
  678. command = input_args[0][1:]
  679. if command_dict.get(command):
  680. input_data = input_data.replace(command,command_dict[command],1)
  681. command = command_dict[command]
  682. if command == 'd' and tweet_dict.get(input_args[1]):
  683. input_data = 'd ' + tweet_dict[input_args[1]]
  684. weechat.prnt(buffer, "%sYou deleted the following tweet:" % weechat.prefix("network"))
  685. elif command == 'v' and tweet_dict.get(input_args[1]):
  686. input_data = 'v ' + tweet_dict[input_args[1]]
  687. end_message = "Done"
  688. elif command == 'rt' and tweet_dict.get(input_args[1]):
  689. end_message = "id"
  690. input_data = 'rt ' + tweet_dict[input_args[1]]
  691. elif command == 're' and tweet_dict.get(input_args[1]):
  692. end_message = "id"
  693. input_data = 're ' + tweet_dict[input_args[1]] + " '" + html_escape(input_data[6:]) + "'"
  694. elif command == 'new':
  695. end_message = "id"
  696. if script_options['last_id'] != "":
  697. input_data = 'new ' + script_options['last_id']
  698. else:
  699. input_data = 'home'
  700. elif command == 'home' or command == 'r' or (command == 'favs' and len(input_args) >= 2 and input_args[1].isdigit()):
  701. input_data = command
  702. if len(input_args) == 3 and tweet_dict.get(input_args[1]) and input_args[2].isdigit():
  703. num = int(input_args[2])
  704. # 200 tweets is the max request limit
  705. if num <= 200 and num > 0:
  706. input_data += " " + tweet_dict[input_args[1]] + " " + input_args[2]
  707. else:
  708. input_data += " " + tweet_dict[input_args[1]]
  709. elif len(input_args) == 2:
  710. if tweet_dict.get(input_args[1]):
  711. input_data += " " + tweet_dict[input_args[1]]
  712. elif input_args[1].isdigit():
  713. num = int(input_args[1])
  714. # 200 tweets is the max request limit
  715. if num <= 200 and num > 0:
  716. input_data += " " + input_args[1]
  717. end_message = "Done"
  718. elif command == 'u' or (command == 'favs' and len(input_args) >= 3):
  719. input_data = " ".join(input_args[:2])[1:]
  720. if len(input_args) == 4 and tweet_dict.get(input_args[2]) and input_args[3].isdigit():
  721. num = int(input_args[3])
  722. # 200 tweets is the max request limit
  723. if num <= 200 and num > 0:
  724. input_data += " " + tweet_dict[input_args[2]] + " " + input_args[3]
  725. else:
  726. input_data += " " + tweet_dict[input_args[2]]
  727. elif len(input_args) == 3:
  728. if tweet_dict.get(input_args[2]):
  729. input_data += " " + tweet_dict[input_args[2]]
  730. elif input_args[2].isdigit():
  731. num = int(input_args[2])
  732. # 200 tweets is the max request limit
  733. if num <= 200 and num > 0:
  734. input_data += " " + input_args[2]
  735. end_message = "Done"
  736. elif command == 'auth':
  737. if len(input_args) == 2:
  738. oauth_dance(buffer,input_args[1])
  739. else:
  740. oauth_dance(buffer)
  741. return weechat.WEECHAT_RC_OK
  742. elif command == 'f' or command == 'fo':
  743. #L because we are returning a list to be printed later on
  744. end_message = "L"
  745. if len(input_args) == 3 and tweet_dict.get(input_args[2]):
  746. input_data = command + " " + input_args[1] + " " + tweet_dict[input_args[2]]
  747. elif len(input_args) == 2:
  748. if tweet_dict.get(input_args[1]):
  749. input_data = command + " " + script_options['screen_name'] + " " + tweet_dict[input_args[1]]
  750. #Your list, not any other users
  751. end_message += "Y"
  752. else:
  753. input_data = input_data[1:]
  754. else:
  755. input_data = command + " " + script_options['screen_name']
  756. end_message += "Y"
  757. if command == 'f':
  758. end_message += "Following"
  759. else:
  760. end_message += "Followers"
  761. elif command == 'a':
  762. input_data = input_data[1:]
  763. end_message = "About"
  764. elif command == 'blocks':
  765. input_data = input_data[1:]
  766. end_message = "LBlock list"
  767. elif command == 'fav' and tweet_dict.get(input_args[1]):
  768. input_data = 'fav ' + tweet_dict[input_args[1]]
  769. weechat.prnt(buffer, "%sYou fave'd the following tweet:" % weechat.prefix("network"))
  770. elif command == 'unfav' and tweet_dict.get(input_args[1]):
  771. input_data = 'unfav ' + tweet_dict[input_args[1]]
  772. weechat.prnt(buffer, "%sYou unfave'd the following tweet:" % weechat.prefix("network"))
  773. elif command == 'cnicks':
  774. global tweet_nicks_group
  775. if tweet_nicks_group[buffer] != "":
  776. weechat.nicklist_remove_group(buffer, tweet_nicks_group[buffer])
  777. tweet_nicks_group[buffer] = ""
  778. tweet_nicks_group[buffer] = weechat.nicklist_add_group(buffer, "", "Tweet_parse",
  779. "weechat.color.nicklist_group", 1)
  780. return weechat.WEECHAT_RC_OK
  781. elif command == 'help':
  782. weechat.command(buffer,"/help twitter")
  783. weechat.prnt(buffer, "Exec command /help twitter, check your root buffer")
  784. return weechat.WEECHAT_RC_OK
  785. elif command == 'clear':
  786. weechat.command(buffer,"/buffer clear")
  787. return weechat.WEECHAT_RC_OK
  788. elif command == 'stream':
  789. args = html_escape(input_data[7:])
  790. weechat.prnt(buffer,create_stream("t_stream",args))
  791. return weechat.WEECHAT_RC_OK
  792. elif command == 're_home':
  793. weechat.prnt(buffer,create_stream("twitter"))
  794. return weechat.WEECHAT_RC_OK
  795. else:
  796. input_data = input_data[1:]
  797. end_message = "Done"
  798. else:
  799. end_message = "id"
  800. #esacpe special chars when printing to commandline
  801. input_data = 't ' + "'" + html_escape(input_data) + "'"
  802. #input_data = 't ' + "'" + html.escape(input_data) + "'"
  803. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  804. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  805. input_data + " " + '"' + str(options) + '"', 10 * 1000, "my_process_cb", str([buffer,end_message]))
  806. return weechat.WEECHAT_RC_OK
  807. def my_command_cb(data, buffer, args):
  808. # ...
  809. buffer_input_cb(data, twit_buf, ":"+args)
  810. return weechat.WEECHAT_RC_OK
  811. def hook_commands_and_completions():
  812. compl_list = []
  813. com_list = []
  814. desc_list = []
  815. for command in sorted(command_dict):
  816. compl_list.append(command)
  817. com_list.append(command + weechat.color("*red") + " or " +
  818. weechat.color('reset') + command_dict[command] + "\n")
  819. desc_list.append(weechat.color("chat_nick_other") + command + ": \n" + desc_dict[command])
  820. weechat.hook_command("twitter", "Command to interact with the twitter api/plugin",
  821. " | ".join(com_list),
  822. "You can type all of these command in the twitter buffer if you add a ':' before the command, IE:\n"
  823. ":limits\n\n"
  824. "If you don't type a command in the twitter buffer you will tweet that instead,\n"
  825. "text after 140 chars will turn red to let you know were twitter will cut off your tweet.\n\n"
  826. + weechat.color("*red") + "NOTE:\n"
  827. "There are limits on how many twitter api calls you can do, some calls are _quite_ restricted.\n"
  828. "So if you get HTML errors from the twitter lib you probably exceeded the limit\n"
  829. "you can check out your limits with the rate_limits/limits command.\n"
  830. "_Most_ commands in this plugin only uses one call. If you want to check old tweets\n"
  831. "in your home timeline it's better to request many tweets in one go.\n"
  832. "That way you don't have to request new tweets as often to go further back in the timeline.\n"
  833. "And thus you are less likely to hit the limit of requests you can do in the 15 min time window.\n"
  834. "\nYou can write newlines in your tweet with html newline '&#13;&#10;' (you can autocomplete it)\n"
  835. "\nThe 'number' next to the nicks in the chat window is the <id> of the tweet it's used\n"
  836. "in the some of the twitter plugin commands.\n\n"
  837. "Command desc:\n"+ "\n".join(desc_list),
  838. " || ".join(compl_list),
  839. "my_command_cb", "")
  840. # callback called when buffer is closed
  841. # TODO rewrite this so it unloads the plugin
  842. def buffer_close_cb(data, buffer):
  843. # ...
  844. #TODO handle multiple buffers and free up global buffer pointers
  845. weechat.unhook_all()
  846. return weechat.WEECHAT_RC_OK
  847. def tweet_length(message):
  848. """Replace URLs with placeholders, 20 for http URLs, 21 for https."""
  849. # regexes to match URLs
  850. octet = r'(?:2(?:[0-4]\d|5[0-5])|1\d\d|\d{1,2})'
  851. ip_addr = r'%s(?:\.%s){3}' % (octet, octet)
  852. # Base domain regex off RFC 1034 and 1738
  853. label = r'[0-9a-z][-0-9a-z]*[0-9a-z]?'
  854. domain = r'%s(?:\.%s)*\.[a-z][-0-9a-z]*[a-z]?' % (label, label)
  855. url_re = re.compile(r'(\w+://(?:%s|%s)(?::\d+)?(?:/[^\])>\s]*)?)' % \
  856. (domain, ip_addr), re.I)
  857. new_message = message
  858. for url in url_re.findall(message):
  859. short_url = 'x' * 20
  860. if url.startswith('https'):
  861. short_url = 'x' * 21
  862. new_message = new_message.replace(url, short_url)
  863. return len(new_message)
  864. def my_modifier_cb(data, modifier, modifier_data, string):
  865. if not weechat.current_buffer() in friends_nicks_group:
  866. return string
  867. #check if this is a commandline argument
  868. if string == "" or string[0] == "/":
  869. return string
  870. length = tweet_length(string)
  871. # Subtract local command argument from length
  872. if string[:3] == ":re":
  873. #:re a2
  874. length = length - 6
  875. if length > 140:
  876. index = 140 - length
  877. string = string[:index] + weechat.color("*red") + string[index:]
  878. return string
  879. def parse_oauth_tokens(result):
  880. for r in result.split('&'):
  881. k, v = r.split('=')
  882. if k == 'oauth_token':
  883. oauth_token = v
  884. elif k == 'oauth_token_secret':
  885. oauth_token_secret = v
  886. return oauth_token, oauth_token_secret
  887. def oauth_proc_cb(data, command, rc, out, err):
  888. global script_options
  889. buffer = twit_buf
  890. if rc == weechat.WEECHAT_HOOK_PROCESS_ERROR:
  891. weechat.prnt("", "Error with command '%s'" %
  892. command.replace(script_options["oauth_token"],"").replace(script_options["oauth_secret"],""))
  893. return weechat.WEECHAT_RC_OK
  894. if out != "":
  895. if data == "nick":
  896. weechat.config_set_plugin('screen_name', out.strip())
  897. finish_init()
  898. elif data == "friends":
  899. process_output = ast.literal_eval(out)
  900. if isinstance(process_output[-1], int):
  901. t_id = dict_tweet(str(process_output[-1])) + "\t"
  902. process_output = process_output[:-1]
  903. weechat.prnt_date_tags(buffer, 0, "no_highlight", t_id +
  904. "It sees like you are following more than 250 people. Due to twitter api limits " +
  905. "it is nearly impossible to get large groups of followers in one go. However the " +
  906. "nicks will be added when they tweet something so if you don't have to be able " +
  907. "autocomplete them from the start this is not a problem for you." +
  908. " If you want to get the rest of the nicks you can use the id of this text.")
  909. for nick in process_output:
  910. add_to_nicklist(buffer,nick)
  911. #Get latest tweets from timeline
  912. buffer_input_cb("silent", buffer, ":new")
  913. elif data == "auth1":
  914. #First auth step to request pin code
  915. oauth_token, oauth_token_secret = parse_oauth_tokens(out)
  916. script_options['oauth_token'] = oauth_token
  917. script_options['oauth_secret'] = oauth_token_secret
  918. weechat.prnt(buffer,"""
  919. Copy the PIN number that appears on the linked web page and type ":auth <pin>"
  920. in weechat. For example ":auth 123456"
  921. """)
  922. oauth_url = ('https://api.twitter.com/oauth/authorize?oauth_token=' +
  923. oauth_token)
  924. weechat.prnt(buffer," Please go here to get your PIN: " + oauth_url)
  925. elif data == "auth2":
  926. oauth_token, oauth_token_secret = parse_oauth_tokens(out)
  927. weechat.config_set_plugin('oauth_token', oauth_token)
  928. weechat.config_set_plugin('oauth_secret', oauth_token_secret)
  929. weechat.config_set_plugin('auth_complete', "on")
  930. weechat.prnt(buffer," Done! now you can begin using this script!")
  931. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  932. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  933. "settings []", 10 * 1000, "oauth_proc_cb", "nick")
  934. return weechat.WEECHAT_RC_OK
  935. def oauth_dance(buffer, pin = ""):
  936. #Auth the twitter client
  937. if pin == "":
  938. weechat.prnt(buffer,"Hi there! We're gonna get you all set up to use this plugin.")
  939. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " + "'' " + "'' " +
  940. "auth", 10 * 1000, "oauth_proc_cb", "auth1")
  941. else:
  942. oauth_verifier = pin.strip()
  943. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  944. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  945. "auth "+ oauth_verifier, 10 * 1000, "oauth_proc_cb", "auth2")
  946. def setup_buffer(buffer):
  947. # set title
  948. weechat.buffer_set(buffer, "title", "Twitter buffer, type ':help' for options.")
  949. # disable logging, by setting local variable "no_log" to "1"
  950. weechat.buffer_set(buffer, "localvar_set_no_log", "1")
  951. #create main nicklist
  952. friends_nicks_group[buffer] = weechat.nicklist_add_group(buffer, "", "Friends",
  953. "weechat.color.nicklist_group", 1)
  954. tweet_nicks_group[buffer] = weechat.nicklist_add_group(buffer, "", "Tweet_parse",
  955. "weechat.color.nicklist_group", 1)
  956. autocomp_group = weechat.nicklist_add_group(buffer, "", "Autocomp",
  957. "weechat.color.nicklist_group", 1)
  958. #newline autocomplete
  959. weechat.nicklist_add_nick(buffer, autocomp_group, "&#13;&#10;", 'bar_fg', '', '', 1)
  960. #show nicklist
  961. weechat.buffer_set(buffer, "nicklist", "1")
  962. user_nick = script_options['screen_name']
  963. weechat.buffer_set(buffer, "localvar_set_nick", user_nick)
  964. add_to_nicklist(buffer, user_nick)
  965. # Highlight user nick
  966. weechat.buffer_set(buffer, "highlight_words", user_nick)
  967. def finish_init():
  968. global timer_hook
  969. buffer = twit_buf
  970. if script_options['screen_name'] == "":
  971. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  972. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  973. "settings []", 10 * 1000, "oauth_proc_cb", "nick")
  974. return
  975. setup_buffer(buffer)
  976. #Add friends to nick list and print new tweets
  977. weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " +
  978. script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " +
  979. "f " + script_options['screen_name'] + " []", 10 * 1000, "oauth_proc_cb", "friends")
  980. if __name__ == "__main__" and weechat_call:
  981. weechat.register( SCRIPT_NAME , "DarkDefender", "1.2.1", "GPL3", "Weechat twitter client", "", "")
  982. if not import_ok:
  983. weechat.prnt("", "Can't load twitter python lib >= " + required_twitter_version)
  984. weechat.prnt("", "Install it via your package manager or go to http://mike.verdone.ca/twitter/")
  985. else:
  986. hook_commands_and_completions()
  987. # Set register script options if not available
  988. for option, default_value in script_options.items():
  989. if not weechat.config_is_set_plugin(option):
  990. if isinstance(default_value,bool):
  991. if default_value:
  992. default_value = "on"
  993. else:
  994. default_value = "off"
  995. weechat.config_set_plugin(option, default_value)
  996. read_config()
  997. # hook for config changes
  998. weechat.hook_config("plugins.var.python." + SCRIPT_NAME + ".*", "config_cb", "")
  999. # create buffer
  1000. twit_buf = weechat.buffer_new("twitter", "buffer_input_cb", "", "buffer_close_cb", "")
  1001. #Hook text input so we can update the bar item
  1002. weechat.hook_modifier("input_text_display", "my_modifier_cb", "")
  1003. if script_options['auth_complete']:
  1004. finish_init()
  1005. #create home_timeline stream
  1006. create_stream("twitter")
  1007. else:
  1008. weechat.prnt(twit_buf,"""You have to register this plugin with twitter for it to work.
  1009. Type ":auth" and follow the instructions to do that""")
  1010. elif import_ok:
  1011. if sys.argv[3] == "stream":
  1012. print(twitter_stream(sys.argv))
  1013. else:
  1014. print(get_twitter_data(sys.argv))
  1015. else:
  1016. print("Can't load twitter python lib >= " + required_twitter_version )