diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 946b3d0a..e1fcce2f 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1019,14 +1019,15 @@ def add_general(ap, nc, srvname): def add_qr(ap, tty): ap2 = ap.add_argument_group("qr options") - ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup") - ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup") + ap2.add_argument("--qr", action="store_true", help="show QR-code on startup") + ap2.add_argument("--qrs", action="store_true", help="change the QR-code URL to https://") ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]") ap2.add_argument("--qri", metavar="PREFIX", type=u, default="", help="select IP which starts with \033[33mPREFIX\033[0m; [\033[32m.\033[0m] to force default IP when mDNS URL would have been used instead") - ap2.add_argument("--qr-fg", metavar="COLOR", type=int, default=0 if tty else 16, help="foreground; try [\033[32m0\033[0m] if the qr-code is unreadable") + ap2.add_argument("--qr-fg", metavar="COLOR", type=int, default=0 if tty else 16, help="foreground; try [\033[32m0\033[0m] or [\033[32m-1\033[0m] if the qr-code is unreadable") ap2.add_argument("--qr-bg", metavar="COLOR", type=int, default=229, help="background (white=255)") ap2.add_argument("--qrp", metavar="CELLS", type=int, default=4, help="padding (spec says 4 or more, but 1 is usually fine)") ap2.add_argument("--qrz", metavar="N", type=int, default=0, help="[\033[32m1\033[0m]=1x, [\033[32m2\033[0m]=2x, [\033[32m0\033[0m]=auto (try [\033[32m2\033[0m] on broken fonts)") + ap2.add_argument("--qr-pin", metavar="N", type=int, default=0, help="sticky/pin the qr-code to always stay on-screen; [\033[32m0\033[0m]=disabled, [\033[32m1\033[0m]=with-url, [\033[32m2\033[0m]=just-qr") def add_fs(ap): diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 5e0ab886..a6f87a85 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -2,6 +2,7 @@ from __future__ import print_function, unicode_literals import argparse +import atexit import errno import logging import os @@ -73,6 +74,7 @@ from .util import ( pybin, start_log_thrs, start_stackmon, + termsize, ub64enc, ) @@ -775,6 +777,39 @@ class SvcHub(object): def sigterm(self) -> None: self.signal_handler(signal.SIGTERM, None) + def sticky_qr(self) -> None: + tw, th = termsize() + zs1, qr = self.tcpsrv.qr.split("\n", 1) + url, colr = zs1.split(" ", 1) + nl = len(qr.split("\n")) # numlines + lp = 3 if nl * 2 + 4 < tw else 0 # leftpad + lp0 = lp + if self.args.qr_pin == 2: + url = "" + else: + while lp and (nl + lp) * 2 + len(url) + 1 > tw: + lp -= 1 + if (nl + lp) * 2 + len(url) + 1 > tw: + qr = url + "\n" + qr + url = "" + nl += 1 + lp = lp0 + sh = 1 + th - nl + if lp: + zs = " " * lp + qr = zs + qr.replace("\n", "\n" + zs) + if url: + url = "%s\033[%d;%dH%s\033[0m" % (colr, sh + 1, (nl + lp) * 2, url) + qr = colr + qr + + def unlock(): + print("\033[s\033[r\033[u", file=sys.stderr) + + atexit.register(unlock) + t = "%s\033[%dA" % ("\n" * nl, nl) + t = "%s\033[s\033[1;%dr\033[%dH%s%s\033[u" % (t, sh - 1, sh, qr, url) + self.pr(t, file=sys.stderr) + def cb_httpsrv_up(self) -> None: self.httpsrv_up += 1 if self.httpsrv_up != self.broker.num_workers: @@ -787,7 +822,10 @@ class SvcHub(object): break if self.tcpsrv.qr: - self.log("qr-code", self.tcpsrv.qr) + if self.args.qr_pin: + self.sticky_qr() + else: + self.log("qr-code", self.tcpsrv.qr) else: self.log("root", "workers OK\n") diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py index 6c61fe61..55ea3a56 100644 --- a/copyparty/tcpsrv.py +++ b/copyparty/tcpsrv.py @@ -614,6 +614,10 @@ class TcpSrv(object): fg = self.args.qr_fg bg = self.args.qr_bg + nocolor = fg == -1 + if nocolor: + fg = 0 + pad = self.args.qrp zoom = self.args.qrz qrc = QrCode.encode_binary(btxt) @@ -641,6 +645,8 @@ class TcpSrv(object): qr = qr.replace("\n", "\033[K\n") + "\033[K" # win10do cc = " \033[0;38;5;{0};47;48;5;{1}m" if fg else " \033[0;30;47m" + if nocolor: + cc = " \033[0m" t = cc + "\n{2}\033[999G\033[0m\033[J" t = t.format(fg, bg, qr) if ANYWIN: diff --git a/tests/util.py b/tests/util.py index d3884ca9..f02f81ba 100644 --- a/tests/util.py +++ b/tests/util.py @@ -161,7 +161,7 @@ class Cfg(Namespace): ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who" ka.update(**{k: 9 for k in ex.split()}) - ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" + ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" ka.update(**{k: 0 for k in ex.split()}) ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"