#!/usr/bin/python
+#---------- setup ----------
+
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
opts = None
+#---------- YPP parameters and arrays ----------
puzzles = ('Swordfighting/Bilging/Sailing/Rigging/Navigating'+
'/Battle Navigation/Gunning/Carpentry/Rumble/Treasure Haul'+
max_pirate_namelen = 12
+#---------- general utilities ----------
+
def debug(m):
if opts.debug > 0:
print m
+def format_time_interval(ti):
+ if ti < 120: return '%d:%02d' % (ti / 60, ti % 60)
+ if ti < 7200: return '%2dm' % (ti / 60)
+ if ti < 86400: return '%dh' % (ti / 3600)
+ return '%dd' % (ti / 86400)
+
+#---------- caching and rate-limiting data fetcher ----------
+
class Fetcher:
def __init__(self, ocean, cachedir):
debug('Fetcher init %s' % cachedir)
self.ocean, kind, tail)
return self.fetch(url, max_age)
+#---------- logging assistance for troubled screenscrapers ----------
+
class SoupLog:
def __init__(self):
self.msgs = [ ]
convertEntities=BeautifulSoup.HTML_ENTITIES
)
+#---------- scraper for pirate pages ----------
+
class PirateInfo(SomethingSoupInfo):
# Public data members:
# pi.standings = { 'Treasure Haul': 'Able' ... }
def __str__(self):
return `(self.crew, self.flag, self.standings, self.msgs)`
+#---------- scraper for crew pages ----------
+
class CrewInfo(SomethingSoupInfo):
# Public data members:
# ci.crew = [ ('Captain', ['Pirate', ...]),
def __str__(self):
return `(self.crew, self.msgs)`
+#---------- pretty-printer for tables of pirate puzzle standings ----------
+
class StandingsTable:
def __init__(self, use_puzzles=None, col_width=6):
if use_puzzles is None:
def results(self):
return self.s
-def do_pirate(pirates, bu):
- print '{'
- for pirate in pirates:
- info = PirateInfo(pirate)
- print '%s: %s,' % (`pirate`, info)
- print '}'
-
-def prep_crew_of(args, bu, max_age=300):
- if len(args) != 1: bu('crew-of takes one pirate name')
- pi = PirateInfo(args[0], max_age)
- if pi.crew is None: return None
- return CrewInfo(pi.crew[0], max_age)
-
-def do_crew_of(args, bu):
- ci = prep_crew_of(args, bu)
- print ci
-
-def do_standings_crew_of(args, bu):
- ci = prep_crew_of(args, bu, 60)
- tab = StandingsTable()
- tab.headings()
- for (rank, members) in ci.crew:
- if not members: continue
- tab.literalline('%s:' % rank)
- for p in members:
- pi = PirateInfo(p, random.randint(900,1800))
- tab.pirate(pi)
- print tab.results()
+#---------- chat log parser ----------
class PirateAboard:
- # pa.v
- # pa.name
- # pa.last_time
- # pa.last_event
- # pa.gunner
- # pa.last_chat_time
- # pa.last_chat_chan
- # pa.pi
+ # This is essentially a transparent, dumb, data class.
+ # pa.v
+ # pa.name
+ # pa.last_time
+ # pa.last_event
+ # pa.gunner
+ # pa.last_chat_time
+ # pa.last_chat_chan
+ # pa.pi
def __init__(pa, pn, v, time, event):
pa.name = pn
return pa.pi
class ChatLogTracker:
+ # This is quite complex so we make it opaque. Use the
+ # official invokers, accessors etc.
+
def __init__(self, myself_pi, logfn):
self._pl = {} # self._pl['Pirate'] =
self._vl = {} # self._vl['Vessel']['Pirate'] = PirateAboard
for pn in sorted(self._v.keys())
if not pn.startswith('#') ]
+#---------- implementations of actual operation modes ----------
+
+def do_pirate(pirates, bu):
+ print '{'
+ for pirate in pirates:
+ info = PirateInfo(pirate)
+ print '%s: %s,' % (`pirate`, info)
+ print '}'
+
+def prep_crew_of(args, bu, max_age=300):
+ if len(args) != 1: bu('crew-of takes one pirate name')
+ pi = PirateInfo(args[0], max_age)
+ if pi.crew is None: return None
+ return CrewInfo(pi.crew[0], max_age)
+
+def do_crew_of(args, bu):
+ ci = prep_crew_of(args, bu)
+ print ci
+
+def do_standings_crew_of(args, bu):
+ ci = prep_crew_of(args, bu, 60)
+ tab = StandingsTable()
+ tab.headings()
+ for (rank, members) in ci.crew:
+ if not members: continue
+ tab.literalline('%s:' % rank)
+ for p in members:
+ pi = PirateInfo(p, random.randint(900,1800))
+ tab.pirate(pi)
+ print tab.results()
+
class ProgressPrintPercentage:
def __init__(self, f=sys.stdout): self._f = f
def progress(self,done,total):
self._f.write(' \r')
self._f.flush()
+#----- modes which use the chat log parser are quite complex -----
+
def prep_chat_log(args, bu,
progress=ProgressPrintPercentage(),
max_myself_age=3600):
print track
time.sleep(1)
-def format_time_interval(ti):
- if ti < 120: return '%d:%02d' % (ti / 60, ti % 60)
- if ti < 7200: return '%2dm' % (ti / 60)
- if ti < 86400: return '%dh' % (ti / 3600)
- return '%dd' % (ti / 86400)
-
def do_ship_aid(args, bu):
if opts.ship_duty is None: opts.ship_duty = True
time.sleep(1)
rotate_nya = rotate_nya[1:2] + rotate_nya[0]
+#---------- main program ----------
+
def main():
global opts, fetcher