forked from samhunter/recentxx
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
10 KiB
279 lines
10 KiB
#!/usr/bin/env python3
|
|
# recent++ for rawtext.club by samhunter
|
|
# https://git.rawtext.club/samhunter/recentxx
|
|
# inspired by:
|
|
# https://git.rawtext.club/hannu/recent
|
|
|
|
import glob
|
|
import sys
|
|
import os
|
|
import time
|
|
import datetime
|
|
import sqlite3 as sql
|
|
import json
|
|
import subprocess
|
|
import getpass
|
|
import argparse
|
|
|
|
# default timespan shown (in days)
|
|
DAYS = 14
|
|
MARKER = "-" * 20
|
|
IGNORE = ["/home/mieum/public_gemini/rtc-recent",
|
|
"/home/mieum/public_gopher/rtc-recent",
|
|
"/home/mieum/public_html/rtc-recent",
|
|
"/home/hedy/public_gemini/recent.txt",
|
|
"/home/sloum/public_gemini/spacewalk.gmi"]
|
|
|
|
parser = argparse.ArgumentParser(description='Python rewrite of the venerable "recent" utility for RTC')
|
|
parser.add_argument("-c", "--compatible", help="Emulates behaviour of the standard 'recent'", action="store_true")
|
|
parser.add_argument("-e", "--exitcode", help="Returns RC>1 if no changes since the last check. No display.", action="store_true")
|
|
parser.add_argument("-m", "--mark", help="Set 'read' marker to current time.", action="store_true")
|
|
|
|
filters = parser.add_argument_group("filtering")
|
|
uparser = filters.add_mutually_exclusive_group()
|
|
uparser.add_argument("-u", "--user", help="Comma separated list of usernames to include in the report", type=lambda x:x.split(","))
|
|
uparser.add_argument("-U", "--exclude-user", metavar="USER", help="Comma separated list of usernames to exclude in the report", type=lambda x:x.split(","))
|
|
|
|
sparser = filters.add_mutually_exclusive_group()
|
|
sparser.add_argument("-s", "--service", help="Comma separated list of services to include in the report", type=lambda x:x.split(","))
|
|
sparser.add_argument("-S", "--exclude-service", metavar="SERVICE", help="Comma separated list of services to exclude in the report", type=lambda x:x.split(","))
|
|
|
|
filters.add_argument("--since", metavar="TIME", help="Show items newer than TIME, provided in Unix time format")
|
|
args = parser.parse_args()
|
|
|
|
|
|
def get_files():
|
|
services = dict([
|
|
('gab','.gab'),
|
|
('shlog','.shlog'),
|
|
('linkulator','.linkulator/linkulator.data'),
|
|
('iris','.iris.messages'),
|
|
('who-is','.who-is'),
|
|
('oneliner', '.oneliner'),
|
|
('fortune', '.fortune'),
|
|
('train','.choochoo'),
|
|
('library','books'),
|
|
('gopher','public_gopher'),
|
|
('gemini','public_gemini'),
|
|
('web','public_html'),
|
|
('spartan','public_spartan'),
|
|
('spacelaunch','.vroom'),
|
|
('gitbbs','.gitbbs'),
|
|
('plan','.plan'),
|
|
('project','.project'),
|
|
('poll','.rtc/polls.templates'),
|
|
('mail','Maildir/new'),
|
|
('botany','.botany/*_plant_data.json'),
|
|
('capitalist','.local/share/capitalist-scores'),
|
|
('wiki','.wiki'),
|
|
(MARKER,'.config/recentxx')
|
|
])
|
|
|
|
if args.service:
|
|
services = dict(filter(lambda x : x[0] in args.service, services.items()))
|
|
elif args.exclude_service:
|
|
services = dict(filter(lambda x : x[0] not in args.exclude_service, services.items()))
|
|
|
|
# add gab channels the current user was/is active in
|
|
if (not args.service or "gab" in args.service) and (not args.exclude_service or "gab" not in args.exclude_service):
|
|
files = glob.glob("/home/"+getpass.getuser()+"/.gab-*")
|
|
for filepath in files:
|
|
service_path = filepath.split('/')[-1]
|
|
if args.compatible == True:
|
|
service = "gab-" + service_path[5:10]
|
|
else:
|
|
service = "gab-" + service_path[5:]
|
|
services[service]=service_path
|
|
|
|
ret = []
|
|
users = [[x, "/home/{}".format(x)] for x in os.listdir("/home/") if os.access("/home/"+x, os.R_OK)]
|
|
|
|
if args.user:
|
|
users = filter(lambda x : x[0] in args.user, users)
|
|
elif args.exclude_user:
|
|
users = filter(lambda x : x[0] not in args.exclude_user, users)
|
|
|
|
for user in users:
|
|
if not os.path.isdir(user[1]):
|
|
pass
|
|
for service in services.keys():
|
|
if service == "mail" and user[0] != getpass.getuser():
|
|
continue
|
|
if service == MARKER and user[0] != getpass.getuser():
|
|
continue
|
|
files = glob.glob(user[1] + '/' + str(services[service]))
|
|
for filepath in files:
|
|
try:
|
|
if os.path.isdir(filepath):
|
|
filepath =max(glob.glob(filepath+'/*', recursive=True), key=os.path.getmtime)
|
|
ret.append( (filepath, user[0], service) )
|
|
except:
|
|
continue
|
|
return ret
|
|
|
|
|
|
if args.since:
|
|
if args.since[-1] == "d":
|
|
DAYS = 1 * int(args.since[0:-1])
|
|
ts = time.time() - (24 * 3600 * DAYS)
|
|
elif args.since[-1] == "w":
|
|
DAYS = 7 * int(args.since[0:-1])
|
|
ts = time.time() - (24 * 3600 * DAYS)
|
|
elif args.since[-1] == "m":
|
|
DAYS = 30 * int(args.since[0:-1])
|
|
ts = time.time() - (24 * 3600 * DAYS)
|
|
else:
|
|
ts = int(args.since)
|
|
else:
|
|
ts = time.time() - (24 * 3600 * DAYS)
|
|
|
|
out = []
|
|
timefmt = "%Y-%m-%d %H:%M"
|
|
for d in get_files():
|
|
service=d[2]
|
|
user=d[1]
|
|
if service[0:3] == "gab" and os.access(d[0], os.R_OK):
|
|
with open(d[0]) as f:
|
|
try:
|
|
ftim = float(f.readline().split("|")[0])
|
|
except:
|
|
continue
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
elif service == "linkulator":
|
|
with open(d[0]) as f:
|
|
try:
|
|
# read last line
|
|
last_line = f.readlines()[-1]
|
|
ftim = float(last_line.split("|")[0])
|
|
except:
|
|
continue
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
elif service == "mail": #XXX
|
|
with open(d[0]) as f:
|
|
ftim = os.stat(d[0]).st_mtime
|
|
try:
|
|
ftim = time.time()
|
|
lines = f.readlines()
|
|
for line in lines:
|
|
if line.startswith("Date:"):
|
|
fdat = line.strip()
|
|
fdat = fdat.replace('Date: ','')
|
|
try:
|
|
ftim = time.mktime(datetime.datetime.strptime(fdat, "%a, %d %b %Y %H:%M:%S %z").timetuple())
|
|
except:
|
|
ftim = os.stat(d[0]).st_mtime
|
|
if line.startswith("Return-Path:"):
|
|
try:
|
|
ffrom = line.strip()
|
|
ffrom = ffrom.replace('Return-Path: ','').replace("<","").replace(">","")
|
|
except:
|
|
ffrom ="---"
|
|
except:
|
|
continue
|
|
d = (d[0], ffrom, d[2])
|
|
#if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
elif service == "botany":
|
|
try:
|
|
with open(d[0]) as f:
|
|
ftim = json.load(f)["last_watered"]
|
|
except subprocess.CalledProcessError as e:
|
|
continue
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
elif service == "gitbbs":
|
|
try:
|
|
ftim = float(subprocess.check_output( ['/usr/bin/git', '-C', d[0], 'log', '--pretty=format:%at', '-n1'], stderr=subprocess.STDOUT ).decode('ascii'))
|
|
except subprocess.CalledProcessError as e:
|
|
continue
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
elif service == "iris":
|
|
with open(d[0]) as f:
|
|
ftim = os.stat(d[0]).st_mtime
|
|
try:
|
|
# read last line
|
|
last_line = f.readlines()[-1]
|
|
# empty = new user
|
|
if last_line.startswith("[]"):
|
|
continue
|
|
except:
|
|
continue
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
else:
|
|
if d[0] not in IGNORE:
|
|
ftim = os.stat(d[0]).st_mtime
|
|
if ftim > ts:
|
|
st = datetime.datetime.fromtimestamp(ftim).strftime(timefmt)
|
|
out.append((st,d))
|
|
|
|
if (not args.service or "cspc" in args.service) and (not args.exclude_service or "cspc" not in args.exclude_service):
|
|
db_path = '/usr/local/share/cspc/db/cspc'
|
|
if os.access(db_path, os.R_OK):
|
|
query = '''SELECT max(last_updated), author, max(type) FROM (
|
|
SELECT
|
|
MAX(last_updated) AS last_updated,
|
|
author,
|
|
CASE type
|
|
WHEN 'topic' THEN 1
|
|
WHEN 'post' THEN 2
|
|
WHEN 'reply' THEN 3
|
|
END AS type
|
|
FROM data
|
|
WHERE last_updated > ''' +str(ts)+ '''
|
|
GROUP BY author, type)
|
|
GROUP BY last_updated'''
|
|
try:
|
|
conn = sql.connect(db_path)
|
|
c = conn.cursor()
|
|
c.execute(query)
|
|
for row in c:
|
|
st = datetime.datetime.fromtimestamp(float(row[0])).strftime(timefmt)
|
|
if (not args.user or row[1] in args.user) and (not args.exclude_user or row[1] not in args.exclude_user):
|
|
out.append((st, ("", row[1],"cspc")))
|
|
conn.close()
|
|
except:
|
|
pass
|
|
finally:
|
|
conn.close()
|
|
|
|
if args.compatible == True:
|
|
fmt = "{date:16s} {service:>11s} {user:14s}"
|
|
else:
|
|
fmt = "{date:16s} {service:20s} {user:14s}"
|
|
|
|
if args.mark == True:
|
|
markfile = "/home/"+getpass.getuser()+"/.config/recentxx"
|
|
os.utime(markfile)
|
|
|
|
if len(out) > 0:
|
|
if args.exitcode == False:
|
|
for item in sorted(out, reverse=True):
|
|
date=item[0]
|
|
user=item[1][1]
|
|
service=item[1][2]
|
|
print(fmt.format(date=date,user=user,service=service.split('/')[0]))
|
|
exit(0)
|
|
else:
|
|
if args.exitcode == False:
|
|
if args.since:
|
|
sys.stderr.write("No results in the specified period.\n")
|
|
else:
|
|
sys.stderr.write(
|
|
f'''No results in the last {DAYS} days.
|
|
Use --since <Unix time> to extend the search, or
|
|
--since 0 to disable filtering by time fully
|
|
''')
|
|
exit(1)
|
|
|
|
|