Files

66 lines
2.2 KiB
Python

"""Share links.
/s/<token>: one recording and the conversation it belongs to, open without the site password (Caddy lets
/s/* through). The token is random and maps to DAY/FILE here only: no path ever appears in the link or page.
"""
import os
import re
import secrets
import threading
import time
from datetime import datetime
from radio.config import CONV_GAP_S, REC_DIR, SHARES_FILE
from radio.recordings import FILE_RE, arch_index, find_item
from radio.util import read_json, write_json_atomic
SHARE_RE = re.compile(r"^[A-Za-z0-9_-]{16,32}$")
_share_lock = threading.Lock()
def share_token(rid):
with _share_lock:
shares = read_json(SHARES_FILE, {})
for t, v in shares.items():
if v.get("id") == rid:
return t
t = secrets.token_urlsafe(12)
shares[t] = {"id": rid, "created": int(time.time())}
write_json_atomic(SHARES_FILE, shares)
return t
def share_conv(token):
"""[items of the conversation, oldest first], index of the shared one; None if unknown / gone."""
if not SHARE_RE.match(token or ""):
return None
sh = read_json(SHARES_FILE, {}).get(token)
it = find_item(sh["id"]) if sh else None
if not it:
return None
day, name = it["id"].split("/")
freq = FILE_RE.match(name)["f"]
names = set()
try:
names.update(n for n in os.listdir(os.path.join(REC_DIR, day)) if FILE_RE.match(n))
except OSError:
pass
names.update(arch_index(day).keys())
same = []
for n in names:
m = FILE_RE.match(n)
if not m or m["f"] != freq:
continue
x = it if n == name else find_item(f"{day}/{n}")
if x and (x is it or x.get("class") != "noise"):
same.append(x)
ts = lambda x: datetime.fromisoformat(x["ts"]).timestamp()
same.sort(key=ts)
i = next(k for k, x in enumerate(same) if x["id"] == it["id"])
lo = hi = i
while lo > 0 and ts(same[lo]) - (ts(same[lo - 1]) + (same[lo - 1].get("duration_s") or 0)) < CONV_GAP_S:
lo -= 1
while hi < len(same) - 1 and ts(same[hi + 1]) - (ts(same[hi]) + (same[hi].get("duration_s") or 0)) < CONV_GAP_S:
hi += 1
return same[lo:hi + 1], i - lo