tweets = {}
for line in archive.readlines():
- tid, text = line.strip().split(" ", 1)
- tweets[int(tid)] = text.decode("utf-8")
+ try:
+ tid, text = line.strip().split(" ", 1)
+ tweets[int(tid)] = text.decode("utf-8")
+ except Exception as e:
+ err("loading tweet %s failed due to %s" % (line, unicode(e)))
archive.close()
return tweets
return
for k in sorted(tweets.keys()):
- archive.write("%i %s\n" % (k, tweets[k].encode('utf-8')))
+ try:
+ archive.write("%i %s\n" % (k, tweets[k].encode('utf-8')))
+ except Exception as ex:
+ err("archiving tweet %s failed due to %s" % (k, unicode(ex)))
archive.close()
-def format_date(utc, to_localtime=True, isoformat=False):
+def format_date(utc, isoformat=False):
"""Parse Twitter's UTC date into UTC or local time."""
u = datetime.strptime(utc.replace('+0000','UTC'), '%a %b %d %H:%M:%S %Z %Y')
+ # This is the least painful way I could find to create a non-naive
+ # datetime including a UTC timezone. Alternative suggestions
+ # welcome.
unew = datetime.combine(u.date(), time(u.time().hour,
u.time().minute, u.time().second, tzinfo=UTC))
- if to_localtime and _time.timezone != 0:
- unew = unew.astimezone(Local)
+ # Convert to localtime
+ unew = unew.astimezone(Local)
+
if isoformat:
return unew.isoformat()
else:
tweets = {}
if mentions:
- tl = twitter.statuses.mentions(**kwargs)
+ tl = twitter.statuses.mentions_timeline(**kwargs)
elif favorites:
- tl = twitter.favorites(**kwargs) # API v1, favorites.list() in v1.1
+ tl = twitter.favorites.list(**kwargs)
elif received_dms != None:
if received_dms:
tl = twitter.direct_messages(**kwargs)
err("Fail: %i Unauthorized (tweets of that user are protected)"
% e.e.code)
break
- elif e.e.code == 400:
+ elif e.e.code == 429:
err("Fail: %i API rate limit exceeded" % e.e.code)
- rate = twitter.account.rate_limit_status()
- reset = rate['reset_time_in_seconds']
- reset = time.asctime(time.localtime(reset))
- delay = int(rate['reset_time_in_seconds']
- - time.time()) + 5 # avoid race
- err("Hourly limit of %i requests reached, next reset on %s: "
- "going to sleep for %i secs" % (rate['hourly_limit'],
+ rls = twitter.application.rate_limit_status()
+ reset = rls.rate_limit_reset
+ reset = _time.asctime(_time.localtime(reset))
+ delay = int(rls.rate_limit_reset
+ - _time.time()) + 5 # avoid race
+ err("Interval limit of %i requests reached, next reset on %s: "
+ "going to sleep for %i secs" % (rls.rate_limit_limit,
reset, delay))
fail.wait(delay)
continue
def rate_limit_status(twitter):
"""Print current Twitter API rate limit status."""
- r = twitter.account.rate_limit_status()
- print("Remaining API requests: %i/%i (hourly limit)"
- % (r['remaining_hits'], r['hourly_limit']))
+ rls = twitter.application.rate_limit_status()
+ print("Remaining API requests: %i/%i (interval limit)"
+ % (rls.rate_limit_remaining, rls.rate_limit_limit))
print("Next reset in %is (%s)"
- % (int(r['reset_time_in_seconds'] - time.time()),
- time.asctime(time.localtime(r['reset_time_in_seconds']))))
+ % (int(rls.rate_limit_reset - _time.time()),
+ _time.asctime(_time.localtime(rls.rate_limit_reset))))
def main(args=sys.argv[1:]):
options = {
# authenticate using OAuth, asking for token if necessary
if options['oauth']:
- oauth_filename = (os.getenv("HOME", "") + os.sep
- + ".twitter-archiver_oauth")
+ oauth_filename = (os.environ.get('HOME',
+ os.environ.get('USERPROFILE', ''))
+ + os.sep
+ + '.twitter-archiver_oauth')
+
if not os.path.exists(oauth_filename):
oauth_dance("Twitter-Archiver", CONSUMER_KEY, CONSUMER_SECRET,
oauth_filename)
else:
auth = NoAuth()
- twitter = Twitter(auth=auth, api_version='1', domain='api.twitter.com')
+ twitter = Twitter(auth=auth, api_version='1.1', domain='api.twitter.com')
if options['api-rate']:
rate_limit_status(twitter)
dms = {}
try:
dms = load_tweets(filename)
- except Exception, e:
+ except Exception as e:
err("Error when loading saved DMs: %s - continuing without"
% str(e))