def debug(m):
if opts.debug:
- print >>sys.stderr, m
+ print m
class Fetcher:
def __init__(self, ocean, cachedir):
# pa.last_time
# pa.last_event
# pa.gunner
+ # pa.last_chat_time
+ # pa.last_chat_chan
def __init__(pa, v, time, event):
pa.v = v
pa.last_time = time
pa.last_event = event
+ pa.last_chat_time = None
+ pa.last_chat_chan = None
pa.gunner = False
-class ShipCrewTracker:
- def __init__(self, myself_pi):
+class ChatLogTracker:
+ def __init__(self, myself_pi, logfn):
self._pl = {} # self._pl['Pirate'] =
self._vl = {} # self._vl['Vessel']['Pirate'] = PirateAboard
# self._vl['Vessel']['#lastaboard']
self._vessel = None # self._vl[self._vessel]
self._date = None
self._myself = myself_pi
- self._need_redisplay = False
+ self.need_redisplay = False
+ self._f = file(logfn)
+ self._lbuf = ''
+ self._progress = [0, os.fstat(self._f.fileno()).st_size]
def _refresh(self):
- self._need_redisplay = True
+ self.need_redisplay = True
def _onboard_event(self,timestamp,pirate,event):
try: pa = self._pl[pirate]
self._refresh()
return pa
+ def _trash_vessel(self, v):
+ for pn in v:
+ if pn.startswith('#'): continue
+ del self._pl[pn]
+ self._refresh()
+
+ def expire_garbage(self, timestamp):
+ for (vn,v) in list(self._vl.iteritems()):
+ la = v['#lastaboard']
+ if timestamp - la > opts.ship_reboard_clearout:
+ self._debug_line_disposition(timestamp,'',
+ 'stale reset '+vn)
+ self._trash_vessel(v)
+ del self._vl[vn]
+
def clear_vessel(self, timestamp):
if self._v is not None:
- for p in self._v:
- if p.startswith('#'): continue
- del self._pl[p]
+ self._trash_vessel(self._v)
self._v = {'#lastaboard': timestamp}
+ self._vl[self._vessel] = self._v
def _debug_line_disposition(self,timestamp,l,m):
- debug('SCT %-13s %-30s %s' % (timestamp,m,l))
+ debug('CLT %13s %-30s %s' % (timestamp,m,l))
def chatline(self,l):
rm = lambda re: regexp.match(re,l)
timestamp = time.mktime(time_tuple)
l = l[l.find(' ')+1:]
- ob = lambda who, event: self._onboard_event(
- timestamp, who, event)
- oba = lambda m, did: ob(
- m.group(1), '%s %s' % (did, m.group(2)))
+ def ob_x(who,event):
+ return self._onboard_event(timestamp, who, event)
+ def ob1(did): ob_x(m.group(1), did); return d(did)
+ def oba(did): return ob1('%s %s' % (did, m.group(2)))
m = rm('Going aboard the (\\S.*\\S)\\.\\.\\.$')
if m:
+ pn = self._myself.name
self._vessel = m.group(1)
dm = 'boarding'
+
try: self._v = self._vl[self._vessel]
except KeyError: self._v = None; dm += ' new'
+
if self._v is not None: la = self._v['#lastaboard']
else: la = 0; dm += ' ?la'
- if timestamp - la > 3600:
+
+ if timestamp - la > opts.ship_reboard_clearout:
self.clear_vessel(timestamp)
dm += ' stale'
- self._vl[self._vessel] = self._v
- ob(self._myself.name, 'we boarded')
+
+ ob_x(pn, 'we boarded')
+ self.expire_garbage(timestamp)
return d(dm)
if self._v is None:
return d('no vessel')
+ m = rm('(\\w+) has come aboard\\.$')
+ if m: return ob1('boarded');
+
m = rm('You have ordered (\\w+) to do some (\\S.*\\S)\\.$')
if m:
- pa = oba(m, 'ordered')
- if m.group(2) == 'Gunning':
+ (who,what) = m.groups()
+ pa = ob_x(who,'ordered '+what)
+ if what == 'Gunning':
pa.gunner = True
return d('duty order')
m = rm('(\\w+) abandoned a (\\S.*\\S) station\\.$')
- if m: oba(m,'abandoned'); return d('abandoned')
+ if m: oba('stopped'); return d('stopped')
+
+ def chat(what):
+ who = m.group(1)
+ try: pa = self._pl[who]
+ except KeyError: return d('chat mystery')
+ if pa.v is self._v:
+ pa.last_chat_time = timestamp
+ pa.last_chat_chan = what
+ self._refresh()
+ return d(what+' chat')
+
+ m = rm('(\\w+) (?:issued an order|ordered everyone) "')
+ if m: return ob1('general order');
m = rm('(\\w+) says, "')
- if m: ob(m.group(1), 'talked'); return d('talked')
+ if m: return chat('public')
+
+ m = rm('(\\w+) tells ye, "')
+ if m: return chat('private')
+
+ m = rm('(\\w+) flag officer chats, "')
+ if m: return chat('flag officer')
+
+ m = rm('(\\w+) officer chats, "')
+ if m: return chat('officer')
+
+ m = rm('Game over\\. Winners: ([A-Za-z, ]+)\\.$')
+ if m:
+ pl = m.group(1).split(', ')
+ if not self._myself.name in pl:
+ return d('lost boarding battle')
+ for pn in pl:
+ if ' ' in pn: continue
+ ob_x(pn,'won boarding battle')
+ return d('won boarding battle')
+
+ m = rm('(\\w+) is eliminated\\!')
+ if m: return ob1('eliminated in fray');
m = rm('(\\w+) has left the vessel\.')
if m:
who = m.group(1)
- ob(who, 'disembarked')
+ ob_x(who, 'disembarked')
del self._v[who]
del self._pl[who]
return d('disembarked')
return d('not matched')
-def do_ship_aid(args, bu):
+ def _str_vessel(self, vn, v):
+ s = ' vessel %s\n' % vn
+ s += ' '*20 + "%-*s %13s\n" % (
+ max_pirate_namelen, '#lastaboard',
+ v['#lastaboard'])
+ for pn in sorted(v.keys()):
+ if pn.startswith('#'): continue
+ pa = v[pn]
+ assert pa.v == v
+ assert self._pl[pn] == pa
+ s += ' '*20 + "%s %-*s %13s %-30s %13s %s\n" % (
+ (' ','G')[pa.gunner],
+ max_pirate_namelen, pn,
+ pa.last_time, pa.last_event,
+ pa.last_chat_time, pa.last_chat_chan)
+ return s
+
+ def __str__(self):
+ s = '''<ChatLogTracker
+ myself %s
+ vessel %s
+''' % (self._myself.name, self._vessel)
+ assert ((self._v is None and self._vessel is None) or
+ (self._v is self._vl[self._vessel]))
+ if self._vessel is not None:
+ s += self._str_vessel(self._vessel, self._v)
+ for vn in sorted(self._vl.keys()):
+ if vn == self._vessel: continue
+ s += self._str_vessel(vn, self._vl[vn])
+ for p in self._pl:
+ pa = self._pl[p]
+ assert pa.v[p] is pa
+ assert pa.v in self._vl.values()
+ s += '>\n'
+ return s
+
+ def catchup(self, progress=None):
+ while True:
+ more = self._f.readline()
+ if not more: break
+
+ self._progress[0] += len(more)
+ if progress: progress.progress(*self._progress)
+
+ self._lbuf += more
+ if self._lbuf.endswith('\n'):
+ self.chatline(self._lbuf.rstrip())
+ self._lbuf = ''
+ if progress: progress.caughtup()
+
+class ProgressPrintPercentage:
+ def __init__(self, f): self._f = f
+ def progress(self,done,total):
+ self._f.write("scan chat logs %3d%%\r" % ((done*100) / total))
+ self._f.flush()
+ def caughtup(self):
+ self._f.write(' \r')
+ self._f.flush()
+
+def do_track_chat_log(args, bu):
if len(args) != 1: bu('ship-aid takes only chat log filename')
logfn = args[0]
logfn_re = '(?:.*/)?([A-Z][a-z]+)_([a-z]+)_chat-log-\\w+$'
match = regexp.match(logfn_re, logfn)
if not match: bu('ship-aid chat log filename is not in default format')
(pirate, fetcher.ocean) = match.groups()
+
+ track = ChatLogTracker(pirate, logfn)
myself_pi = PirateInfo(pirate,3600)
- track = ShipCrewTracker(myself_pi)
- f = file(logfn)
- l = ''
+ track = ChatLogTracker(myself_pi, logfn)
+ track.catchup(ProgressPrintPercentage(sys.stdout))
while True:
- l += f.readline()
- if l.endswith('\n'):
- track.chatline(l.rstrip())
-# print `track.__dict__`
- l = ''
- continue
- if l:
- continue
- print `track.__dict__`
- os.sleep(1)
+ track.catchup()
+ if track.need_redisplay:
+ print track
+ track.need_redisplay = False
+ time.sleep(1)
def main():
global opts, fetcher
yoweb-scrape [--ocean OCEAN ...] pirate PIRATE
yoweb-scrape [--ocean OCEAN ...] crew-of PIRATE
yoweb-scrape [--ocean OCEAN ...] standings-crew-of PIRATE
+ yoweb-scrape [--ocean OCEAN ...] track-chat-log CHAT-LOG
yoweb-scrape [--ocean OCEAN ...] ship-aid CHAT-LOG
''')
ao = pa.add_option
# fixed parameters
opts.min_max_age = 60
opts.expire_age = 3600
+ opts.ship_reboard_clearout = 3600
if opts.cache_dir.startswith('~/'):
opts.cache_dir = os.getenv('HOME') + opts.cache_dir[1:]