diff -uNr a/logotron/MANIFEST.TXT b/logotron/MANIFEST.TXT --- a/logotron/MANIFEST.TXT dbba91f83102533d1e4c0c7efa6c861054c4a9c7ce713f92813916f9a5692592a8d0e2efbb8ebe0d3c87ddd7477581228e59d3a9d52dabfde0a0d18fc13e4bf8 +++ b/logotron/MANIFEST.TXT 4f46ccc238ff725712306588453e7a1ce18e29d69ed1589988e1e276dc7a6d0f1f0de31a86c47d08541e68150b83c55177499fa4c704453ac8c4edf372495daa @@ -9,3 +9,4 @@ 593779 uptimefix_bye_cache lobbes "Fix in bot.py for global time_last_conn. Remove Cache from reader.py. Small README fix re: create database." 594463 raw_line_fix lobbes "Fix to raw line export in reader.py to remove semi-colon from right side of nick on action lines" 595435 irssi_format diana_coman "Updates the irssi2tmsr converter to work on out-of-the-box irssi format. Updated README file too with example of format." +596907 sept_fixes asciilifeform "Several small improvements to bot and reader." diff -uNr a/logotron/README.txt b/logotron/README.txt --- a/logotron/README.txt a6bfa0bc96bde13236f34d83bff5d8053e73031be0ba1aafe29c84f8e38f475470919e785d2a9afa6e134f02a6c64908e14be04c89465c8cfcf5958fba23b13b +++ b/logotron/README.txt 1f4326cf8d7a7ac9ccd54da9ccc56b4c5eef008245933a2905a87978aabdb27d438c8bdd2430275ae75c5ce2a4d335df9fbd1f671a69d046b12f7cf2f57b4ae9 @@ -92,3 +92,29 @@ (4) WWW: Links in log lines now open in new browser tab (a la Phf's log) (5) WWW: Can now be loaded 'in reverse gear', http://...../log?rev=1 (6) WWW: 'Random' knob, takes reader to an arbitrary moment in past log. + +############### +Sep. 28 Update: +############### + +(1) Bot: incorporated reconnector fixes. +(2) Bot: 'seen', 'seen-all', and 'version' knobs implemented. +(3) WWW: up/down arrows for mouse-driven operation on pocket comps +(4) WWW: double-quotes prevent breakup of search query + (Note: still needs improvement to force matching on word boundaries) +(5) WWW: demarkation of "action" lines +(6) WWW: Raw 'Tape" knob: + +e.g. http://logs.nosuchlabs.com/tape?istart=1937934&iend=1937941 +returns: + +trilema;1937934;1569444908;asciilifeform;achtung panzers! piz pipe down ?! +trilema;1937935;1569444920;diana_coman;seems so +trilema;1937936;1569444957;asciilifeform;paging BingoBoingo ! +trilema;1937937;1569444974;diana_coman;well, apparetly he was connected from piz too, lol +trilema;1937938;1569444982;diana_coman;ossasepia.com (pizarro) is down too, yes +trilema;1937939;1569445010;asciilifeform;dulap unreachable for 1st time since year+ ago when bb elbowed the mains cord +trilema;1937940;1569445073;diana_coman;apparently back on +trilema;1937941;1569445079;diana_coman;wb BingoBoingo ! + +Still needs a variant of 'eater' that will eat these. diff -uNr a/logotron/bot.py b/logotron/bot.py --- a/logotron/bot.py 19772a67f431072de4c51c6600d860c8cbb77f4e5172f4c20f43078565eda7c07c599e165ee588552741a703cbd13b1043d6c2850858cbe2cc9d3f5249f54c8f +++ b/logotron/bot.py 7980970a1d40b7a348a8fed795896d0cfa4568e3b4464768a0ea118efde16645bcdf2e934ba1ed42bc1d7708bccb9ef28f0645c13cbdc80754d00d8dd47a6729 @@ -13,6 +13,11 @@ ############################################################################## +# Version. If changing this program, always set this to same # as in MANIFEST +Ver = 596907 + +############################################################################## + cfg = ConfigParser.ConfigParser() ############################################################################## @@ -211,6 +216,9 @@ if act: action = True text = act.group(1) + # Remove turd if present: + if text[-1:] == '\x01': + text = text[:-1] # This line is edible, process it. eat_logline(user, chan, text, action) @@ -312,6 +320,15 @@ ############################################################################## +# Get perma-URL corresponding to given log line +def line_url(l): + return "{0}log/{1}/{2}#{3}".format(Base_URL, + l['chan'], + l['t'].strftime(Date_Short_Format), + l['idx']) + +############################################################################## + # Commands: def cmd_help(arg, user, chan): @@ -324,7 +341,68 @@ speak(chan, get_search_res(chan, arg)) def cmd_seen(arg, user, chan): - speak(chan, "%s: this command is not yet implemented." % user); + # Empty query is prohibited: + if arg == "": + speak(chan, "Required argument: USER") + return + + # Perform query: + seen_line = query_db( + '''select t, idx, payload, chan from loglines where + chan=%s and speaker=%s order by t desc limit 1;''', + [chan, arg], one=True) + + # Where output will go + result = "" + + # If user has been seen in THE CURRENT chan: + if seen_line != None: + time_txt = seen_line['t'].strftime(Date_Long_Format) + time_link = "[%s][%s]" % (line_url(seen_line), time_txt) + seen_line = "%s last seen here on %s: %s" % (arg, + time_link, + seen_line['payload']) + result = seen_line + else: + # If user has never been seen in this chan: + result = "The user %s has never been seen in #%s." % (arg, chan) + + # Speak the result into the chan where command was issued + speak(chan, result) + +def cmd_seen_anywhere(arg, user, chan): + # Empty query is prohibited: + if arg == "": + speak(chan, "Required argument: USER") + return + + # Perform query: + seen_line = query_db( + '''select t, idx, payload, chan from loglines where speaker=%s + order by t desc limit 1;''', + [arg], one=True) + + # Where output will go + result = "" + + # If user has been seen in ANY logged chan: + if seen_line != None: + time_txt = seen_line['t'].strftime(Date_Long_Format) + time_link = "[%s][%s]" % (line_url(seen_line), time_txt) + seen_line = "%s last seen in #%s on %s: %s" % (arg, + seen_line['chan'], + time_link, + seen_line['payload']) + result = seen_line + else: + # If user has never been seen at all: + result = "The user %s has never been seen by this logger." % arg + + # Speak the result into the chan where command was issued + speak(chan, result) + +def cmd_version(arg, user, chan): + speak(chan, "I am bot version %s." % Ver); def cmd_src(arg, user, chan): speak(chan, "%s: my source code can be seen at: %s" % (user, Src_URL)); @@ -343,11 +421,13 @@ (user, uptime_txt)); Commands = { - "help" : cmd_help, - "s" : cmd_search, - "seen" : cmd_seen, - "uptime" : cmd_uptime, - "src" : cmd_src + "help" : cmd_help, + "s" : cmd_search, + "seen" : cmd_seen, + "seen-anywhere" : cmd_seen_anywhere, + "uptime" : cmd_uptime, + "src" : cmd_src, + "version" : cmd_version } ############################################################################## @@ -384,8 +464,7 @@ # RE for finding log refs -logref_re = re.compile(Base_URL + """log\/([^/]+)/([^/]+)#(\d+)""") - +logref_re = re.compile(Base_URL + """log\/([^/]+)/[^/]+#(\d+)""") # All valid received lines end up here def eat_logline(user, chan, text, action): @@ -422,7 +501,7 @@ else: # Finally, see if contains log refs: for ref in re.findall(logref_re, text): - ref_chan, ref_date, ref_idx = ref + ref_chan, ref_idx = ref # Find this line in DB: ref_line = query_db( '''select t, speaker, payload from loglines @@ -430,10 +509,20 @@ [ref_chan, ref_idx], one=True) # If retrieved line is valid, echo it: if ref_line != None: - time_txt = ref_line['t'].strftime(Date_Long_Format) - my_line = "Logged on %s %s: %s" % (time_txt, - ref_line['speaker'], - ref_line['payload']) + # If referred line was spoken in THIS chan: + if ref_chan == chan: + time_txt = ref_line['t'].strftime(Date_Long_Format) + my_line = "Logged on %s %s: %s" % (time_txt, + ref_line['speaker'], + ref_line['payload']) + else: + # If this is a cross-chan echo: + time_txt = ref_line['t'].strftime(Date_Short_Format) + my_line = "(%s) %s %s: %s" % (ref_chan, + time_txt, + ref_line['speaker'], + ref_line['payload']) + # Speak the line echo into the chan where ref was seen speak(chan, my_line) diff -uNr a/logotron/reader.py b/logotron/reader.py --- a/logotron/reader.py 932db323be19ae3d24ecec90b63d8e0e551eddfe2278233cfb73e66e89cf36108768d3fb8a0e5bb330d25ba31b0634f7805adf2be3e0abe2d18e6a546179c6f9 +++ b/logotron/reader.py e67f9263580fce464d48e985cc229c279a89c2f79296def56631eb295da2b4604ebdc681914c1217d139b68873f721cd5df0af1a82f6f199e16a87f1dbbbedb9 @@ -15,6 +15,7 @@ import os import threading import re +import shlex from datetime import datetime from urlparse import urljoin from flask import Flask, request, session, url_for, redirect, Response, \ @@ -276,16 +277,26 @@ if ss <= l['idx'] <= se: dclass = "highlight" + speaker = l['speaker'] + separator = ":" + + # If 'action', annotate: + if l['self']: + separator = "" + payload = "" + payload + "" + speaker = "" + speaker + "" + # HTMLize the given line : s = ("
" "{1}: {4}
").format(l['idx'], - l['speaker'], - l['t'], - line_url(l), - payload, - bot, - dclass) + " href=\"{3}\">{1}{5} {4}").format(l['idx'], + speaker, + l['t'], + line_url(l), + payload, + bot, + dclass, + separator) return s # Make above callable from inside htm templater: @@ -436,6 +447,49 @@ return Response(res, mimetype='text/plain') +# "Tape" is a raw log containing entried from ALL logged chans: +@app.route('/tape') +def tape(): + res = "" + + # Get start and end indices: + idx_start = request.args.get('istart', default = 0, type = int) + idx_end = request.args.get('iend', default = 0, type = int) + + # Malformed bounds? + if idx_start > idx_end: + return Response("EGGOG: Start must precede End!", + mimetype='text/plain') + + # Demanded too many in one burst ? + if (idx_end - idx_start) > Max_Raw_Ln : + return Response("EGGOG: May request Max. of %s Lines !" % Max_Raw_Ln, + mimetype='text/plain') + + # Get the loglines from DB + lines = query_db( + '''select * from loglines where + idx between %s and %s order by idx asc;''', + [idx_start, idx_end], one=False) + + # Retrieve raw lines in Tape format: + for l in lines: + action = "" + speaker = "%s;" % l['speaker'] + if l['self']: + action = "*;" + speaker = "%s " % l['speaker'] + res += "%s;%s;%s;%s%s%s\n" % (l['chan'], + l['idx'], + l['t'].strftime('%s'), + action, + speaker, + l['payload']) + + # Return plain text: + return Response(res, mimetype='text/plain') + + Name_Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-" def sanitize_speaker(s): @@ -464,7 +518,7 @@ # Forbid query that is too short: if len(query) >= Min_Query_Length: # Get the search tokens to use: - tokens = query.split() + tokens = shlex.split(query) tokens_standard = [] from_users = [] diff -uNr a/logotron/templates/layout.html b/logotron/templates/layout.html --- a/logotron/templates/layout.html 8a0c101964ae3ae0ce1687e8a6da575c9de35990dd0bca507b58539dd01af67d6e3f775f8f00ccc9ea40053b80f63815ff02e12e6a7e69a0b832949c3b8f50ad +++ b/logotron/templates/layout.html 96ec2c4262fdc5a0707910cc69ccf6c522e6d4b7c0597b61672afcfe1f17bcabe94629c97517328d1f02bc8bb8b2f96bb69d1f39027f55a671b0b290e83c6248 @@ -78,11 +78,19 @@ .annotations a { text-decoration: none; } - - #navbar { + + .navbarblock { margin-bottom: 1em; } - + + .navbar { + float:left; + } + + .jump { + float:right; + } + .highlight { background: yellow !important;; padding: 1px; @@ -93,6 +101,8 @@ + +

@@ -137,6 +147,9 @@
Random({{ chan }}) | Download daily DB snapshot | Get Source Code
+ + + diff -uNr a/logotron/templates/log.html b/logotron/templates/log.html --- a/logotron/templates/log.html 52d528c55a54d0077907ddae6d862d9b3e9c4afb9d787874a8844de4c3231b8c8d714dc2bef369004efbef7cbdba4b81ec1081f71a1ea48f5598b5780facef6a +++ b/logotron/templates/log.html 2a1af43ab7aa90d58c85b05d4badf528c9d6af150c470629ae5394ddc577cae27fcf42d5527659df61a73e422af5ba67ac0aa55ac4022091455e61cf92ce3af8 @@ -6,7 +6,11 @@ {% block body %} - + +
{% for l in loglines %} @@ -14,6 +18,10 @@ {% endfor %}
- + +
{% endblock %}