Compare commits

...

13 Commits

Author SHA1 Message Date
ed
abc404a5b7 v1.1.6 2021-12-07 01:17:56 +01:00
ed
04b9e21330 update web-deps 2021-12-07 01:12:32 +01:00
ed
1044aa071b deal with consecutive dupes even without sqlite 2021-12-06 23:51:44 +01:00
ed
4c3192c8cc set window-title to listening ip 2021-12-06 23:08:04 +01:00
ed
689e77a025 option to set a custom servicename 2021-12-06 22:24:25 +01:00
ed
3bd89403d2 apply per-volume index config to ui 2021-12-06 22:04:24 +01:00
ed
b4800d9bcb option to disable onboot-scans per-volume 2021-12-06 20:54:13 +01:00
ed
05485e8539 md: smaller indent on outermost list 2021-12-06 20:17:12 +01:00
ed
0e03dc0868 and fix the markdown breadcrumbs too 2021-12-06 19:51:47 +01:00
ed
352b1ed10a generate correct links when trailing slash missing 2021-12-06 19:49:14 +01:00
ed
0db1244d04 also consider TMPDIR and friends 2021-12-06 09:47:39 +01:00
ed
ece08b8179 create ~/.config if /tmp is readonly 2021-12-06 02:02:44 +01:00
ed
b8945ae233 fix tests and readme 2021-12-04 18:52:14 +01:00
24 changed files with 271 additions and 166 deletions

View File

@@ -169,7 +169,6 @@ feature summary
* ☑ ...of audio (spectrograms) using FFmpeg * ☑ ...of audio (spectrograms) using FFmpeg
* ☑ cache eviction (max-age; maybe max-size eventually) * ☑ cache eviction (max-age; maybe max-size eventually)
* ☑ SPA (browse while uploading) * ☑ SPA (browse while uploading)
* if you use the navpane to navigate, not folders in the file list
* server indexing * server indexing
* ☑ [locate files by contents](#file-search) * ☑ [locate files by contents](#file-search)
* ☑ search by name/path/date/size * ☑ search by name/path/date/size
@@ -325,6 +324,7 @@ the browser has the following hotkeys (always qwerty)
* `V` toggle folders / textfiles in the navpane * `V` toggle folders / textfiles in the navpane
* `G` toggle list / [grid view](#thumbnails) * `G` toggle list / [grid view](#thumbnails)
* `T` toggle thumbnails / icons * `T` toggle thumbnails / icons
* `ESC` close various things
* `ctrl-X` cut selected files/folders * `ctrl-X` cut selected files/folders
* `ctrl-V` paste * `ctrl-V` paste
* `F2` [rename](#batch-rename) selected file/folder * `F2` [rename](#batch-rename) selected file/folder
@@ -376,9 +376,13 @@ switching between breadcrumbs or navpane
click the `🌲` or pressing the `B` hotkey to toggle between breadcrumbs path (default), or a navpane (tree-browser sidebar thing) click the `🌲` or pressing the `B` hotkey to toggle between breadcrumbs path (default), or a navpane (tree-browser sidebar thing)
* `[-]` and `[+]` (or hotkeys `A`/`D`) adjust the size * `[+]` and `[-]` (or hotkeys `A`/`D`) adjust the size
* `[v]` jumps to the currently open folder * `[🎯]` jumps to the currently open folder
* `[📃]` toggles between showing folders and textfiles
* `[📌]` shows the name of all parent folders in a docked panel
* `[a]` toggles automatic widening as you go deeper * `[a]` toggles automatic widening as you go deeper
* `[↵]` toggles wordwrap
* `[👀]` show full name on hover (if wordwrap is off)
## thumbnails ## thumbnails
@@ -394,6 +398,7 @@ audio files are covnerted into spectrograms using FFmpeg unless you `--no-athumb
images with the following names (see `--th-covers`) become the thumbnail of the folder they're in: `folder.png`, `folder.jpg`, `cover.png`, `cover.jpg` images with the following names (see `--th-covers`) become the thumbnail of the folder they're in: `folder.png`, `folder.jpg`, `cover.png`, `cover.jpg`
in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked
* indicated by the audio files having the ▶ icon instead of 💾
## zip downloads ## zip downloads
@@ -621,10 +626,12 @@ through arguments:
* `-e2ts` also scans for tags in all files that don't have tags yet * `-e2ts` also scans for tags in all files that don't have tags yet
* `-e2tsr` also deletes all existing tags, doing a full reindex * `-e2tsr` also deletes all existing tags, doing a full reindex
the same arguments can be set as volume flags, in addition to `d2d` and `d2t` for disabling: the same arguments can be set as volume flags, in addition to `d2d`, `d2ds`, `d2t`, `d2ts` for disabling:
* `-v ~/music::r:c,e2dsa,e2tsr` does a full reindex of everything on startup * `-v ~/music::r:c,e2dsa,e2tsr` does a full reindex of everything on startup
* `-v ~/music::r:c,d2d` disables **all** indexing, even if any `-e2*` are on * `-v ~/music::r:c,d2d` disables **all** indexing, even if any `-e2*` are on
* `-v ~/music::r:c,d2t` disables all `-e2t*` (tags), does not affect `-e2d*` * `-v ~/music::r:c,d2t` disables all `-e2t*` (tags), does not affect `-e2d*`
* `-v ~/music::r:c,d2ds` disables on-boot scans; only index new uploads
* `-v ~/music::r:c,d2ts` same except only affecting tags
note: note:
* the parser can finally handle `c,e2dsa,e2tsr` so you no longer have to `c,e2dsa:c,e2tsr` * the parser can finally handle `c,e2dsa,e2tsr` so you no longer have to `c,e2dsa:c,e2tsr`
@@ -850,7 +857,7 @@ copyparty returns a truncated sha512sum of your PUT/POST as base64; you can gene
b512(){ printf "$((sha512sum||shasum -a512)|sed -E 's/ .*//;s/(..)/\\x\1/g')"|base64|tr '+/' '-_'|head -c44;} b512(){ printf "$((sha512sum||shasum -a512)|sed -E 's/ .*//;s/(..)/\\x\1/g')"|base64|tr '+/' '-_'|head -c44;}
b512 <movie.mkv b512 <movie.mkv
you can provide passwords using cookie 'cppwd=hunter2', as a url query `?pw=hunter2`, or with basic-authentication (either as the username or password) you can provide passwords using cookie `cppwd=hunter2`, as a url query `?pw=hunter2`, or with basic-authentication (either as the username or password)
# up2k # up2k

View File

@@ -25,26 +25,34 @@ ANYWIN = WINDOWS or sys.platform in ["msys"]
MACOS = platform.system() == "Darwin" MACOS = platform.system() == "Darwin"
def get_unix_home(): def get_unixdir():
try: paths = [
v = os.environ["XDG_CONFIG_HOME"] (os.environ.get, "XDG_CONFIG_HOME"),
if not v: (os.path.expanduser, "~/.config"),
raise Exception() (os.environ.get, "TMPDIR"),
ret = os.path.normpath(v) (os.environ.get, "TEMP"),
os.listdir(ret) (os.environ.get, "TMP"),
return ret (unicode, "/tmp"),
except: ]
pass for chk in [os.listdir, os.mkdir]:
for pf, pa in paths:
try:
p = pf(pa)
# print(chk.__name__, p, pa)
if not p or p.startswith("~"):
continue
try: p = os.path.normpath(p)
v = os.path.expanduser("~/.config") chk(p)
if v.startswith("~"): p = os.path.join(p, "copyparty")
raise Exception() if not os.path.isdir(p):
ret = os.path.normpath(v) os.mkdir(p)
os.listdir(ret)
return ret return p
except: except:
return "/tmp" pass
raise Exception("could not find a writable path for config")
class EnvParams(object): class EnvParams(object):
@@ -59,7 +67,7 @@ class EnvParams(object):
elif sys.platform == "darwin": elif sys.platform == "darwin":
self.cfg = os.path.expanduser("~/Library/Preferences/copyparty") self.cfg = os.path.expanduser("~/Library/Preferences/copyparty")
else: else:
self.cfg = get_unix_home() + "/copyparty" self.cfg = get_unixdir()
self.cfg = self.cfg.replace("\\", "/") self.cfg = self.cfg.replace("\\", "/")
try: try:

View File

@@ -350,6 +350,8 @@ def run_argparse(argv, formatter):
\033[0mdatabase, general: \033[0mdatabase, general:
\033[36me2d\033[35m sets -e2d (all -e2* args can be set using ce2* volflags) \033[36me2d\033[35m sets -e2d (all -e2* args can be set using ce2* volflags)
\033[36md2ts\033[35m disables metadata collection for existing files
\033[36md2ds\033[35m disables onboot indexing, overrides -e2ds*
\033[36md2t\033[35m disables metadata collection, overrides -e2t* \033[36md2t\033[35m disables metadata collection, overrides -e2t*
\033[36md2d\033[35m disables all database stuff, overrides -e2* \033[36md2d\033[35m disables all database stuff, overrides -e2*
\033[36mnohash=\\.iso$\033[35m skips hashing file contents if path matches *.iso \033[36mnohash=\\.iso$\033[35m skips hashing file contents if path matches *.iso
@@ -416,6 +418,7 @@ def run_argparse(argv, formatter):
ap2.add_argument("-emp", action="store_true", help="enable markdown plugins") ap2.add_argument("-emp", action="store_true", help="enable markdown plugins")
ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="md-editor mod-chk rate") ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="md-editor mod-chk rate")
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-forms; examples: [stash], [save,get]") ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-forms; examples: [stash], [save,get]")
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="window title, for example '$ip-10.1.2.' or '$ip-'")
ap2 = ap.add_argument_group('upload options') ap2 = ap.add_argument_group('upload options')
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads") ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads")
@@ -529,6 +532,7 @@ def run_argparse(argv, formatter):
ap2.add_argument("--js-browser", metavar="L", type=u, help="URL to additional JS to include") ap2.add_argument("--js-browser", metavar="L", type=u, help="URL to additional JS to include")
ap2.add_argument("--css-browser", metavar="L", type=u, help="URL to additional CSS to include") ap2.add_argument("--css-browser", metavar="L", type=u, help="URL to additional CSS to include")
ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext") ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty", help="title / service-name to show in html documents")
ap2 = ap.add_argument_group('debug options') ap2 = ap.add_argument_group('debug options')
ap2.add_argument("--no-sendfile", action="store_true", help="disable sendfile") ap2.add_argument("--no-sendfile", action="store_true", help="disable sendfile")
@@ -605,6 +609,9 @@ def main(argv=None):
except: except:
print("\nfailed to disable quick-edit-mode:\n" + min_ex() + "\n") print("\nfailed to disable quick-edit-mode:\n" + min_ex() + "\n")
if not VT100:
al.wintitle = ""
nstrs = [] nstrs = []
anymod = False anymod = False
for ostr in al.v or []: for ostr in al.v or []:

View File

@@ -1,8 +1,8 @@
# coding: utf-8 # coding: utf-8
VERSION = (1, 1, 5) VERSION = (1, 1, 6)
CODENAME = "opus" CODENAME = "opus"
BUILD_DT = (2021, 12, 4) BUILD_DT = (2021, 12, 7)
S_VERSION = ".".join(map(str, VERSION)) S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT) S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -926,6 +926,14 @@ class AuthSrv(object):
vol.flags["d2t"] = True vol.flags["d2t"] = True
vol.flags = {k: v for k, v in vol.flags.items() if not k.startswith(rm)} vol.flags = {k: v for k, v in vol.flags.items() if not k.startswith(rm)}
# d2ds drops all onboot scans for a volume
for grp, rm in [["d2ds", "e2ds"], ["d2ts", "e2ts"]]:
if not vol.flags.get(grp, False):
continue
vol.flags["d2ts"] = True
vol.flags = {k: v for k, v in vol.flags.items() if not k.startswith(rm)}
# mt* needs e2t so drop those too # mt* needs e2t so drop those too
for grp, rm in [["e2t", "mt"]]: for grp, rm in [["e2t", "mt"]]:
if vol.flags.get(grp, False): if vol.flags.get(grp, False):

View File

@@ -92,6 +92,7 @@ class HttpCli(object):
tpl = self.conn.hsrv.j2[name] tpl = self.conn.hsrv.j2[name]
if ka: if ka:
ka["ts"] = self.conn.hsrv.cachebuster() ka["ts"] = self.conn.hsrv.cachebuster()
ka["svcname"] = self.args.doctitle
return tpl.render(**ka) return tpl.render(**ka)
return tpl return tpl
@@ -2096,6 +2097,7 @@ class HttpCli(object):
url_suf = self.urlq({}, []) url_suf = self.urlq({}, [])
is_ls = "ls" in self.uparam is_ls = "ls" in self.uparam
is_js = self.cookies.get("js") == "y"
tpl = "browser" tpl = "browser"
if "b" in self.uparam: if "b" in self.uparam:
@@ -2124,6 +2126,7 @@ class HttpCli(object):
"taglist": [], "taglist": [],
"srvinf": srv_info, "srvinf": srv_info,
"acct": self.uname, "acct": self.uname,
"idx": ("e2d" in vn.flags),
"perms": perms, "perms": perms,
"logues": logues, "logues": logues,
"readme": readme, "readme": readme,
@@ -2213,7 +2216,7 @@ class HttpCli(object):
for fn in vfs_ls: for fn in vfs_ls:
base = "" base = ""
href = fn href = fn
if not is_ls and not self.trailing_slash and vpath: if not is_ls and not is_js and not self.trailing_slash and vpath:
base = "/" + vpath + "/" base = "/" + vpath + "/"
href = base + fn href = base + fn
@@ -2356,7 +2359,7 @@ class HttpCli(object):
dirs.sort(key=itemgetter("name")) dirs.sort(key=itemgetter("name"))
if self.cookies.get("js") == "y": if is_js:
j2a["ls0"] = {"dirs": dirs, "files": files, "taglist": taglist} j2a["ls0"] = {"dirs": dirs, "files": files, "taglist": taglist}
j2a["files"] = [] j2a["files"] = []
else: else:

View File

@@ -302,6 +302,10 @@ class SvcHub(object):
print("nailed it", end="") print("nailed it", end="")
ret = self.retcode ret = self.retcode
finally: finally:
if self.args.wintitle:
print("\033]0;\033\\", file=sys.stderr, end="")
sys.stderr.flush()
print("\033[0m") print("\033[0m")
if self.logf: if self.logf:
self.logf.close() self.logf.close()

View File

@@ -2,9 +2,10 @@
from __future__ import print_function, unicode_literals from __future__ import print_function, unicode_literals
import re import re
import sys
import socket import socket
from .__init__ import MACOS, ANYWIN from .__init__ import MACOS, ANYWIN, unicode
from .util import chkcmd from .util import chkcmd
@@ -54,6 +55,8 @@ class TcpSrv(object):
eps[x] = "external" eps[x] = "external"
msgs = [] msgs = []
title_tab = {}
title_vars = [x[1:] for x in self.args.wintitle.split(" ") if x.startswith("$")]
m = "available @ http://{}:{}/ (\033[33m{}\033[0m)" m = "available @ http://{}:{}/ (\033[33m{}\033[0m)"
for ip, desc in sorted(eps.items(), key=lambda x: x[1]): for ip, desc in sorted(eps.items(), key=lambda x: x[1]):
for port in sorted(self.args.p): for port in sorted(self.args.p):
@@ -62,11 +65,36 @@ class TcpSrv(object):
msgs.append(m.format(ip, port, desc)) msgs.append(m.format(ip, port, desc))
if not self.args.wintitle:
continue
if port in [80, 443]:
ep = ip
else:
ep = "{}:{}".format(ip, port)
hits = []
if "pub" in title_vars and "external" in unicode(desc):
hits.append(("pub", ep))
for var in title_vars:
if var.startswith("ip-") and ep.startswith(var[3:]):
hits.append((var, ep))
for tk, tv in hits:
try:
title_tab[tk] += " and {}".format(tv)
except:
title_tab[tk] = tv
if msgs: if msgs:
msgs[-1] += "\n" msgs[-1] += "\n"
for m in msgs: for m in msgs:
self.log("tcpsrv", m) self.log("tcpsrv", m)
if self.args.wintitle:
self._set_wintitle(title_tab)
def _listen(self, ip, port): def _listen(self, ip, port):
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -232,3 +260,17 @@ class TcpSrv(object):
eps[default_route] = desc eps[default_route] = desc
return eps return eps
def _set_wintitle(self, vars):
if "pub" not in vars:
vars["pub"] = "Local-Only"
title = ""
for p in self.args.wintitle.split(" "):
if p.startswith("$"):
p = vars.get(p[1:], "(None)")
title += "{} ".format(p)
print("\033]0;{}\033\\".format(title), file=sys.stderr, end="")
sys.stderr.flush()

View File

@@ -1308,11 +1308,14 @@ class Up2k(object):
err = "partial upload exists at a different location; please resume uploading here instead:\n" err = "partial upload exists at a different location; please resume uploading here instead:\n"
err += "/" + quotep(vsrc) + " " err += "/" + quotep(vsrc) + " "
dupe = [cj["prel"], cj["name"], cj["lmod"]] # registry is size-constrained + can only contain one unique wark;
try: # let want_recheck trigger symlink (if still in reg) or reupload
self.dupesched[src].append(dupe) if cur:
except: dupe = [cj["prel"], cj["name"], cj["lmod"]]
self.dupesched[src] = [dupe] try:
self.dupesched[src].append(dupe)
except:
self.dupesched[src] = [dupe]
raise Pebkac(400, err) raise Pebkac(400, err)

View File

@@ -8,13 +8,9 @@ function dbg(msg) {
// toolbar // toolbar
ebi('ops').innerHTML = ( ebi('ops').innerHTML = (
'<a href="#" data-dest="" tt="close submenu">--</a>\n' + '<a href="#" data-dest="" tt="close submenu">--</a>\n' +
(have_up2k_idx ? ( '<a href="#" data-perm="read" data-dep="idx" data-dest="search" tt="search for files by attributes, path/name, music tags, or any combination of those$N$N&lt;code&gt;foo bar&lt;/code&gt; = must contain both foo and bar,$N&lt;code&gt;foo -bar&lt;/code&gt; = must contain foo but not bar,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = start with yana and be an opus file$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contain exactly «try unite»">🔎</a>\n' +
'<a href="#" data-perm="read" data-dest="search" tt="search for files by attributes, path/name, music tags, or any combination of those$N$N&lt;code&gt;foo bar&lt;/code&gt; = must contain both foo and bar,$N&lt;code&gt;foo -bar&lt;/code&gt; = must contain foo but not bar,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = start with yana and be an opus file$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contain exactly «try unite»">🔎</a>\n' + (have_del && have_unpost ? '<a href="#" data-dest="unpost" data-dep="idx" tt="unpost: delete your recent uploads">🧯</a>\n' : '') +
(have_del && have_unpost ? '<a href="#" data-dest="unpost" tt="unpost: delete your recent uploads">🧯</a>\n' : '') + '<a href="#" data-dest="up2k">🚀</a>\n' +
'<a href="#" data-dest="up2k" tt="up2k: upload files (if you have write-access) or toggle into the search-mode to see if they exist somewhere on the server">🚀</a>\n'
) : (
'<a href="#" data-perm="write" data-dest="up2k" tt="up2k: upload files with resume support (close your browser and drop the same files in later)">🚀</a>\n'
)) +
'<a href="#" data-perm="write" data-dest="bup" tt="bup: basic uploader, even supports netscape 4.0">🎈</a>\n' + '<a href="#" data-perm="write" data-dest="bup" tt="bup: basic uploader, even supports netscape 4.0">🎈</a>\n' +
'<a href="#" data-perm="write" data-dest="mkdir" tt="mkdir: create a new directory">📂</a>\n' + '<a href="#" data-perm="write" data-dest="mkdir" tt="mkdir: create a new directory">📂</a>\n' +
'<a href="#" data-perm="read write" data-dest="new_md" tt="new-md: create a new markdown document">📝</a>\n' + '<a href="#" data-perm="read write" data-dest="new_md" tt="new-md: create a new markdown document">📝</a>\n' +
@@ -68,12 +64,10 @@ ebi('op_up2k').innerHTML = (
' <input type="checkbox" id="ask_up" />\n' + ' <input type="checkbox" id="ask_up" />\n' +
' <label for="ask_up" tt="ask for confirmation before upload starts">💭</label>\n' + ' <label for="ask_up" tt="ask for confirmation before upload starts">💭</label>\n' +
' </td>\n' + ' </td>\n' +
(have_up2k_idx ? ( ' <td class="c" data-perm="read" data-dep="idx" rowspan="2">\n' +
' <td class="c" data-perm="read" rowspan="2">\n' + ' <input type="checkbox" id="fsearch" />\n' +
' <input type="checkbox" id="fsearch" />\n' + ' <label for="fsearch" tt="don\'t actually upload, instead check if the files already $N exist on the server (will scan all folders you can read)">🔎</label>\n' +
' <label for="fsearch" tt="don\'t actually upload, instead check if the files already $N exist on the server (will scan all folders you can read)">🔎</label>\n' + ' </td>\n' +
' </td>\n'
) : '') +
' <td data-perm="read" rowspan="2" id="u2btn_cw"></td>\n' + ' <td data-perm="read" rowspan="2" id="u2btn_cw"></td>\n' +
' <td data-perm="read" rowspan="2" id="u2c3w"></td>\n' + ' <td data-perm="read" rowspan="2" id="u2c3w"></td>\n' +
' </tr>\n' + ' </tr>\n' +
@@ -1934,10 +1928,6 @@ var fileman = (function () {
(function (a) { (function (a) {
f[a].inew.onkeydown = function (e) { f[a].inew.onkeydown = function (e) {
rn_ok(a, true); rn_ok(a, true);
if (e.key == 'Escape')
return rn_cancel();
if (e.key == 'Enter') if (e.key == 'Enter')
return rn_apply(); return rn_apply();
}; };
@@ -2970,6 +2960,9 @@ document.onkeydown = function (e) {
if (k == 'Escape') { if (k == 'Escape') {
ae && ae.blur(); ae && ae.blur();
if (ebi('rn_cancel'))
return ebi('rn_cancel').click();
if (QS('.opview.act')) if (QS('.opview.act'))
return QS('#ops>a').click(); return QS('#ops>a').click();
@@ -3875,6 +3868,7 @@ var treectl = (function () {
r.gentab(this.top, res); r.gentab(this.top, res);
acct = res.acct; acct = res.acct;
have_up2k_idx = res.idx;
apply_perms(res.perms); apply_perms(res.perms);
despin('#files'); despin('#files');
despin('#gfiles'); despin('#gfiles');
@@ -4065,6 +4059,17 @@ function despin(sel) {
function apply_perms(newperms) { function apply_perms(newperms) {
perms = newperms || []; perms = newperms || [];
var a = QS('#ops a[data-dest="up2k"]');
if (have_up2k_idx) {
a.removeAttribute('data-perm');
a.setAttribute('tt', 'up2k: upload files (if you have write-access) or toggle into the search-mode to see if they exist somewhere on the server');
}
else {
a.setAttribute('data-perm', 'write');
a.setAttribute('tt', 'up2k: upload files with resume support (close your browser and drop the same files in later)');
}
tt.att(QS('#ops'));
var axs = [], var axs = [],
aclass = '>', aclass = '>',
chk = ['read', 'write', 'move', 'delete', 'get']; chk = ['read', 'write', 'move', 'delete', 'get'];
@@ -4094,6 +4099,12 @@ function apply_perms(newperms) {
o[a].style.display = display; o[a].style.display = display;
} }
var o = QSA('#ops>a[data-dep], #u2conf td[data-dep]');
for (var a = 0; a < o.length; a++)
o[a].style.display = (
o[a].getAttribute('data-dep') != 'idx' || have_up2k_idx
) ? '' : 'none';
var act = QS('#ops>a.act'); var act = QS('#ops>a.act');
if (act && act.style.display === 'none') if (act && act.style.display === 'none')
goto(); goto();
@@ -4762,7 +4773,7 @@ function show_md(md, name, div, url, depth) {
try { try {
clmod(div, 'mdo', 1); clmod(div, 'mdo', 1);
div.innerHTML = marked(md, { div.innerHTML = marked.parse(md, {
headerPrefix: 'md-', headerPrefix: 'md-',
breaks: true, breaks: true,
gfm: true gfm: true
@@ -5045,15 +5056,15 @@ function reload_browser() {
var parts = get_evpath().split('/'), var parts = get_evpath().split('/'),
rm = QSA('#path>a+a+a'), rm = QSA('#path>a+a+a'),
ftab = ebi('files'); ftab = ebi('files'),
link = '/', o;
for (a = rm.length - 1; a >= 0; a--) for (a = rm.length - 1; a >= 0; a--)
rm[a].parentNode.removeChild(rm[a]); rm[a].parentNode.removeChild(rm[a]);
var link = '/';
for (var a = 1; a < parts.length - 1; a++) { for (var a = 1; a < parts.length - 1; a++) {
link += parts[a] + '/'; link += parts[a] + '/';
var o = mknod('a'); o = mknod('a');
o.setAttribute('href', link); o.setAttribute('href', link);
o.textContent = uricom_dec(parts[a])[0]; o.textContent = uricom_dec(parts[a])[0];
ebi('path').appendChild(o); ebi('path').appendChild(o);

View File

@@ -10,7 +10,7 @@
{%- endif %} {%- endif %}
</head> </head>
<body> <body>
<div id="mn">navbar</div> <div id="mn"></div>
<div id="mh"> <div id="mh">
<a id="lightswitch" href="#">go dark</a> <a id="lightswitch" href="#">go dark</a>
<a id="navtoggle" href="#">hide nav</a> <a id="navtoggle" href="#">hide nav</a>

View File

@@ -39,20 +39,14 @@ var md_plug = {};
// add navbar // add navbar
(function () { (function () {
var n = document.location + ''; var parts = get_evpath().split('/'), link = '', o;
n = n.substr(n.indexOf('//') + 2).split('?')[0].split('/'); for (var a = 0, aa = parts.length - 2; a <= aa; a++) {
n[0] = 'top'; link += parts[a] + (a < aa ? '/' : '');
var loc = []; o = mknod('a');
var nav = []; o.setAttribute('href', link);
for (var a = 0; a < n.length; a++) { o.textContent = uricom_dec(parts[a])[0] || 'top';
if (a > 0) dom_nav.appendChild(o);
loc.push(n[a]);
var dec = esc(uricom_dec(n[a])[0]);
nav.push('<a href="/' + loc.join('/') + '">' + dec + '</a>');
} }
dom_nav.innerHTML = nav.join('');
})(); })();
@@ -256,7 +250,7 @@ function convert_markdown(md_text, dest_dom) {
Object.assign(marked_opts, ext[0]); Object.assign(marked_opts, ext[0]);
try { try {
var md_html = marked(md_text, marked_opts); var md_html = marked.parse(md_text, marked_opts);
} }
catch (ex) { catch (ex) {
if (ext) if (ext)

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>copyparty</title> <title>{{ svcname }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=0.8"> <meta name="viewport" content="width=device-width, initial-scale=0.8">
<link rel="stylesheet" media="screen" href="/.cpr/msg.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="/.cpr/msg.css?_={{ ts }}">

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>copyparty</title> <title>{{ svcname }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=0.8"> <meta name="viewport" content="width=device-width, initial-scale=0.8">
<link rel="stylesheet" media="screen" href="/.cpr/splash.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="/.cpr/splash.css?_={{ ts }}">

View File

@@ -354,6 +354,13 @@ html.light textarea:focus {
} }
.mdo ul, .mdo ul,
.mdo ol { .mdo ol {
padding-left: 1em;
}
.mdo ul ul,
.mdo ul ol,
.mdo ol ul,
.mdo ol ol {
padding-left: 2em;
border-left: .3em solid #ddd; border-left: .3em solid #ddd;
} }
.mdo ul>li, .mdo ul>li,

View File

@@ -2038,7 +2038,7 @@ function up2k_init(subtle) {
new_state = true; new_state = true;
fixed = true; fixed = true;
} }
if (!has(perms, 'read')) { if (!has(perms, 'read') || !have_up2k_idx) {
new_state = false; new_state = false;
fixed = true; fixed = true;
} }

View File

@@ -1,10 +1,10 @@
FROM alpine:3.14 FROM alpine:3.15
WORKDIR /z WORKDIR /z
ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \ ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \
ver_hashwasm=4.9.0 \ ver_hashwasm=4.9.0 \
ver_marked=3.0.4 \ ver_marked=4.0.6 \
ver_mde=2.15.0 \ ver_mde=2.15.0 \
ver_codemirror=5.62.3 \ ver_codemirror=5.64.0 \
ver_fontawesome=5.13.0 \ ver_fontawesome=5.13.0 \
ver_zopfli=1.0.3 ver_zopfli=1.0.3
@@ -82,7 +82,6 @@ RUN cd marked-$ver_marked \
&& patch -p1 < /z/marked.patch \ && patch -p1 < /z/marked.patch \
&& npm run build \ && npm run build \
&& cp -pv marked.min.js /z/dist/marked.js \ && cp -pv marked.min.js /z/dist/marked.js \
&& cp -pv lib/marked.js /z/dist/marked.full.js \
&& mkdir -p /z/nodepkgs \ && mkdir -p /z/nodepkgs \
&& ln -s $(pwd) /z/nodepkgs/marked && ln -s $(pwd) /z/nodepkgs/marked
# && npm run test \ # && npm run test \
@@ -98,8 +97,10 @@ RUN cd CodeMirror-$ver_codemirror \
# build easymde # build easymde
COPY easymde-marked6.patch /z/
COPY easymde.patch /z/ COPY easymde.patch /z/
RUN cd easy-markdown-editor-$ver_mde \ RUN cd easy-markdown-editor-$ver_mde \
&& patch -p1 < /z/easymde-marked6.patch \
&& patch -p1 < /z/easymde.patch \ && patch -p1 < /z/easymde.patch \
&& sed -ri 's`https://registry.npmjs.org/marked/-/marked-[0-9\.]+.tgz`file:/z/nodepkgs/marked`' package-lock.json \ && sed -ri 's`https://registry.npmjs.org/marked/-/marked-[0-9\.]+.tgz`file:/z/nodepkgs/marked`' package-lock.json \
&& sed -ri 's`("marked": ")[^"]+`\1file:/z/nodepkgs/marked`' ./package.json \ && sed -ri 's`("marked": ")[^"]+`\1file:/z/nodepkgs/marked`' ./package.json \

View File

@@ -0,0 +1,12 @@
diff --git a/src/js/easymde.js b/src/js/easymde.js
--- a/src/js/easymde.js
+++ b/src/js/easymde.js
@@ -1962,7 +1962,7 @@ EasyMDE.prototype.markdown = function (text) {
marked.setOptions(markedOptions);
// Convert the markdown to HTML
- var htmlText = marked(text);
+ var htmlText = marked.parse(text);
// Sanitize HTML
if (this.options.renderingConfig && typeof this.options.renderingConfig.sanitizerFunction === 'function') {

View File

@@ -1,15 +1,15 @@
diff --git a/src/Lexer.js b/src/Lexer.js diff --git a/src/Lexer.js b/src/Lexer.js
adds linetracking to marked.js v3.0.4; adds linetracking to marked.js v4.0.6;
add data-ln="%d" to most tags, %d is the source markdown line add data-ln="%d" to most tags, %d is the source markdown line
--- a/src/Lexer.js --- a/src/Lexer.js
+++ b/src/Lexer.js +++ b/src/Lexer.js
@@ -50,4 +50,5 @@ function mangle(text) { @@ -50,4 +50,5 @@ function mangle(text) {
module.exports = class Lexer { export class Lexer {
constructor(options) { constructor(options) {
+ this.ln = 1; // like most editors, start couting from 1 + this.ln = 1; // like most editors, start couting from 1
this.tokens = []; this.tokens = [];
this.tokens.links = Object.create(null); this.tokens.links = Object.create(null);
@@ -127,4 +128,15 @@ module.exports = class Lexer { @@ -127,4 +128,15 @@ export class Lexer {
} }
+ set_ln(token, ln = this.ln) { + set_ln(token, ln = this.ln) {
@@ -25,7 +25,7 @@ add data-ln="%d" to most tags, %d is the source markdown line
+ +
/** /**
* Lexing * Lexing
@@ -134,7 +146,11 @@ module.exports = class Lexer { @@ -134,7 +146,11 @@ export class Lexer {
src = src.replace(/^ +$/gm, ''); src = src.replace(/^ +$/gm, '');
} }
- let token, lastToken, cutSrc, lastParagraphClipped; - let token, lastToken, cutSrc, lastParagraphClipped;
@@ -38,105 +38,105 @@ add data-ln="%d" to most tags, %d is the source markdown line
+ +
if (this.options.extensions if (this.options.extensions
&& this.options.extensions.block && this.options.extensions.block
@@ -142,4 +158,5 @@ module.exports = class Lexer { @@ -142,4 +158,5 @@ export class Lexer {
if (token = extTokenizer.call({ lexer: this }, src, tokens)) { if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
return true; return true;
@@ -153,4 +170,5 @@ module.exports = class Lexer { @@ -153,4 +170,5 @@ export class Lexer {
if (token = this.tokenizer.space(src)) { if (token = this.tokenizer.space(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); // is \n if not type + this.set_ln(token, ln); // is \n if not type
if (token.type) { if (token.type) {
tokens.push(token); tokens.push(token);
@@ -162,4 +180,5 @@ module.exports = class Lexer { @@ -162,4 +180,5 @@ export class Lexer {
if (token = this.tokenizer.code(src)) { if (token = this.tokenizer.code(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
lastToken = tokens[tokens.length - 1]; lastToken = tokens[tokens.length - 1];
// An indented code block cannot interrupt a paragraph. // An indented code block cannot interrupt a paragraph.
@@ -177,4 +196,5 @@ module.exports = class Lexer { @@ -177,4 +196,5 @@ export class Lexer {
if (token = this.tokenizer.fences(src)) { if (token = this.tokenizer.fences(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -184,4 +204,5 @@ module.exports = class Lexer { @@ -184,4 +204,5 @@ export class Lexer {
if (token = this.tokenizer.heading(src)) { if (token = this.tokenizer.heading(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -191,4 +212,5 @@ module.exports = class Lexer { @@ -191,4 +212,5 @@ export class Lexer {
if (token = this.tokenizer.hr(src)) { if (token = this.tokenizer.hr(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -198,4 +220,5 @@ module.exports = class Lexer { @@ -198,4 +220,5 @@ export class Lexer {
if (token = this.tokenizer.blockquote(src)) { if (token = this.tokenizer.blockquote(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -205,4 +228,5 @@ module.exports = class Lexer { @@ -205,4 +228,5 @@ export class Lexer {
if (token = this.tokenizer.list(src)) { if (token = this.tokenizer.list(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -212,4 +236,5 @@ module.exports = class Lexer { @@ -212,4 +236,5 @@ export class Lexer {
if (token = this.tokenizer.html(src)) { if (token = this.tokenizer.html(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -219,4 +244,5 @@ module.exports = class Lexer { @@ -219,4 +244,5 @@ export class Lexer {
if (token = this.tokenizer.def(src)) { if (token = this.tokenizer.def(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
lastToken = tokens[tokens.length - 1]; lastToken = tokens[tokens.length - 1];
if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
@@ -236,4 +262,5 @@ module.exports = class Lexer { @@ -236,4 +262,5 @@ export class Lexer {
if (token = this.tokenizer.table(src)) { if (token = this.tokenizer.table(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -243,4 +270,5 @@ module.exports = class Lexer { @@ -243,4 +270,5 @@ export class Lexer {
if (token = this.tokenizer.lheading(src)) { if (token = this.tokenizer.lheading(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
tokens.push(token); tokens.push(token);
continue; continue;
@@ -263,4 +291,5 @@ module.exports = class Lexer { @@ -263,4 +291,5 @@ export class Lexer {
} }
if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) { if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
+ this.set_ln(token, ln); + this.set_ln(token, ln);
lastToken = tokens[tokens.length - 1]; lastToken = tokens[tokens.length - 1];
if (lastParagraphClipped && lastToken.type === 'paragraph') { if (lastParagraphClipped && lastToken.type === 'paragraph') {
@@ -280,4 +309,6 @@ module.exports = class Lexer { @@ -280,4 +309,6 @@ export class Lexer {
if (token = this.tokenizer.text(src)) { if (token = this.tokenizer.text(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.set_ln(token, ln); + this.set_ln(token, ln);
+ this.ln++; + this.ln++;
lastToken = tokens[tokens.length - 1]; lastToken = tokens[tokens.length - 1];
if (lastToken && lastToken.type === 'text') { if (lastToken && lastToken.type === 'text') {
@@ -355,4 +386,5 @@ module.exports = class Lexer { @@ -355,4 +386,5 @@ export class Lexer {
if (token = extTokenizer.call({ lexer: this }, src, tokens)) { if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.ln = token.ln || this.ln; + this.ln = token.ln || this.ln;
tokens.push(token); tokens.push(token);
return true; return true;
@@ -420,4 +452,6 @@ module.exports = class Lexer { @@ -420,4 +452,6 @@ export class Lexer {
if (token = this.tokenizer.br(src)) { if (token = this.tokenizer.br(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ // no need to reset (no more blockTokens anyways) + // no need to reset (no more blockTokens anyways)
+ token.ln = this.ln++; + token.ln = this.ln++;
tokens.push(token); tokens.push(token);
continue; continue;
@@ -462,4 +496,5 @@ module.exports = class Lexer { @@ -462,4 +496,5 @@ export class Lexer {
if (token = this.tokenizer.inlineText(cutSrc, smartypants)) { if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
+ this.ln = token.ln || this.ln; + this.ln = token.ln || this.ln;
@@ -145,13 +145,13 @@ add data-ln="%d" to most tags, %d is the source markdown line
diff --git a/src/Parser.js b/src/Parser.js diff --git a/src/Parser.js b/src/Parser.js
--- a/src/Parser.js --- a/src/Parser.js
+++ b/src/Parser.js +++ b/src/Parser.js
@@ -18,4 +18,5 @@ module.exports = class Parser { @@ -18,4 +18,5 @@ export class Parser {
this.textRenderer = new TextRenderer(); this.textRenderer = new TextRenderer();
this.slugger = new Slugger(); this.slugger = new Slugger();
+ this.ln = 0; // error indicator; should always be set >=1 from tokens + this.ln = 0; // error indicator; should always be set >=1 from tokens
} }
@@ -64,4 +65,8 @@ module.exports = class Parser { @@ -64,4 +65,8 @@ export class Parser {
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
token = tokens[i]; token = tokens[i];
+ // take line-numbers from tokens whenever possible + // take line-numbers from tokens whenever possible
@@ -160,7 +160,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ this.renderer.tag_ln(this.ln); + this.renderer.tag_ln(this.ln);
// Run any renderer extensions // Run any renderer extensions
@@ -124,7 +129,10 @@ module.exports = class Parser { @@ -124,7 +129,10 @@ export class Parser {
} }
- body += this.renderer.tablerow(cell); - body += this.renderer.tablerow(cell);
@@ -173,7 +173,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).table(header, body); + out += this.renderer.tag_ln(token.ln).table(header, body);
continue; continue;
} }
@@ -167,8 +175,12 @@ module.exports = class Parser { @@ -167,8 +175,12 @@ export class Parser {
itemBody += this.parse(item.tokens, loose); itemBody += this.parse(item.tokens, loose);
- body += this.renderer.listitem(itemBody, task, checked); - body += this.renderer.listitem(itemBody, task, checked);
@@ -188,7 +188,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).list(body, ordered, start); + out += this.renderer.tag_ln(token.ln).list(body, ordered, start);
continue; continue;
} }
@@ -179,5 +191,6 @@ module.exports = class Parser { @@ -179,5 +191,6 @@ export class Parser {
} }
case 'paragraph': { case 'paragraph': {
- out += this.renderer.paragraph(this.parseInline(token.tokens)); - out += this.renderer.paragraph(this.parseInline(token.tokens));
@@ -196,7 +196,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).paragraph(t); + out += this.renderer.tag_ln(token.ln).paragraph(t);
continue; continue;
} }
@@ -221,4 +234,7 @@ module.exports = class Parser { @@ -221,4 +234,7 @@ export class Parser {
token = tokens[i]; token = tokens[i];
+ // another thing that only affects <br/> and other inlines + // another thing that only affects <br/> and other inlines
@@ -207,7 +207,7 @@ diff --git a/src/Parser.js b/src/Parser.js
diff --git a/src/Renderer.js b/src/Renderer.js diff --git a/src/Renderer.js b/src/Renderer.js
--- a/src/Renderer.js --- a/src/Renderer.js
+++ b/src/Renderer.js +++ b/src/Renderer.js
@@ -11,6 +11,12 @@ module.exports = class Renderer { @@ -11,6 +11,12 @@ export class Renderer {
constructor(options) { constructor(options) {
this.options = options || defaults; this.options = options || defaults;
+ this.ln = ""; + this.ln = "";
@@ -220,7 +220,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js
+ +
code(code, infostring, escaped) { code(code, infostring, escaped) {
const lang = (infostring || '').match(/\S*/)[0]; const lang = (infostring || '').match(/\S*/)[0];
@@ -26,10 +32,10 @@ module.exports = class Renderer { @@ -26,10 +32,10 @@ export class Renderer {
if (!lang) { if (!lang) {
- return '<pre><code>' - return '<pre><code>'
@@ -233,55 +233,55 @@ diff --git a/src/Renderer.js b/src/Renderer.js
+ return '<pre' + this.ln + '><code class="' + return '<pre' + this.ln + '><code class="'
+ this.options.langPrefix + this.options.langPrefix
+ escape(lang, true) + escape(lang, true)
@@ -40,5 +46,5 @@ module.exports = class Renderer { @@ -40,5 +46,5 @@ export class Renderer {
blockquote(quote) { blockquote(quote) {
- return '<blockquote>\n' + quote + '</blockquote>\n'; - return '<blockquote>\n' + quote + '</blockquote>\n';
+ return '<blockquote' + this.ln + '>\n' + quote + '</blockquote>\n'; + return '<blockquote' + this.ln + '>\n' + quote + '</blockquote>\n';
} }
@@ -51,4 +57,5 @@ module.exports = class Renderer { @@ -51,4 +57,5 @@ export class Renderer {
return '<h' return '<h'
+ level + level
+ + this.ln + + this.ln
+ ' id="' + ' id="'
+ this.options.headerPrefix + this.options.headerPrefix
@@ -61,5 +68,5 @@ module.exports = class Renderer { @@ -61,5 +68,5 @@ export class Renderer {
} }
// ignore IDs // ignore IDs
- return '<h' + level + '>' + text + '</h' + level + '>\n'; - return '<h' + level + '>' + text + '</h' + level + '>\n';
+ return '<h' + level + this.ln + '>' + text + '</h' + level + '>\n'; + return '<h' + level + this.ln + '>' + text + '</h' + level + '>\n';
} }
@@ -75,5 +82,5 @@ module.exports = class Renderer { @@ -75,5 +82,5 @@ export class Renderer {
listitem(text) { listitem(text) {
- return '<li>' + text + '</li>\n'; - return '<li>' + text + '</li>\n';
+ return '<li' + this.ln + '>' + text + '</li>\n'; + return '<li' + this.ln + '>' + text + '</li>\n';
} }
@@ -87,5 +94,5 @@ module.exports = class Renderer { @@ -87,5 +94,5 @@ export class Renderer {
paragraph(text) { paragraph(text) {
- return '<p>' + text + '</p>\n'; - return '<p>' + text + '</p>\n';
+ return '<p' + this.ln + '>' + text + '</p>\n'; + return '<p' + this.ln + '>' + text + '</p>\n';
} }
@@ -102,5 +109,5 @@ module.exports = class Renderer { @@ -102,5 +109,5 @@ export class Renderer {
tablerow(content) { tablerow(content) {
- return '<tr>\n' + content + '</tr>\n'; - return '<tr>\n' + content + '</tr>\n';
+ return '<tr' + this.ln + '>\n' + content + '</tr>\n'; + return '<tr' + this.ln + '>\n' + content + '</tr>\n';
} }
@@ -127,5 +134,5 @@ module.exports = class Renderer { @@ -127,5 +134,5 @@ export class Renderer {
br() { br() {
- return this.options.xhtml ? '<br/>' : '<br>'; - return this.options.xhtml ? '<br/>' : '<br>';
+ return this.options.xhtml ? '<br' + this.ln + '/>' : '<br' + this.ln + '>'; + return this.options.xhtml ? '<br' + this.ln + '/>' : '<br' + this.ln + '>';
} }
@@ -153,5 +160,5 @@ module.exports = class Renderer { @@ -153,5 +160,5 @@ export class Renderer {
} }
- let out = '<img src="' + href + '" alt="' + text + '"'; - let out = '<img src="' + href + '" alt="' + text + '"';
@@ -291,7 +291,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js
diff --git a/src/Tokenizer.js b/src/Tokenizer.js diff --git a/src/Tokenizer.js b/src/Tokenizer.js
--- a/src/Tokenizer.js --- a/src/Tokenizer.js
+++ b/src/Tokenizer.js +++ b/src/Tokenizer.js
@@ -301,4 +301,7 @@ module.exports = class Tokenizer { @@ -297,4 +297,7 @@ export class Tokenizer {
const l = list.items.length; const l = list.items.length;
+ // each nested list gets +1 ahead; this hack makes every listgroup -1 but atleast it doesn't get infinitely bad + // each nested list gets +1 ahead; this hack makes every listgroup -1 but atleast it doesn't get infinitely bad

View File

@@ -1,7 +1,7 @@
diff --git a/src/Lexer.js b/src/Lexer.js diff --git a/src/Lexer.js b/src/Lexer.js
--- a/src/Lexer.js --- a/src/Lexer.js
+++ b/src/Lexer.js +++ b/src/Lexer.js
@@ -6,5 +6,5 @@ const { repeatString } = require('./helpers.js'); @@ -6,5 +6,5 @@ import { repeatString } from './helpers.js';
/** /**
* smartypants text replacement * smartypants text replacement
- */ - */
@@ -15,21 +15,21 @@ diff --git a/src/Lexer.js b/src/Lexer.js
+ * + *
function mangle(text) { function mangle(text) {
let out = '', let out = '',
@@ -465,5 +465,5 @@ module.exports = class Lexer { @@ -466,5 +466,5 @@ export class Lexer {
// autolink // autolink
- if (token = this.tokenizer.autolink(src, mangle)) { - if (token = this.tokenizer.autolink(src, mangle)) {
+ if (token = this.tokenizer.autolink(src)) { + if (token = this.tokenizer.autolink(src)) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
tokens.push(token); tokens.push(token);
@@ -472,5 +472,5 @@ module.exports = class Lexer { @@ -473,5 +473,5 @@ export class Lexer {
// url (gfm) // url (gfm)
- if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) { - if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
+ if (!this.state.inLink && (token = this.tokenizer.url(src))) { + if (!this.state.inLink && (token = this.tokenizer.url(src))) {
src = src.substring(token.raw.length); src = src.substring(token.raw.length);
tokens.push(token); tokens.push(token);
@@ -493,5 +493,5 @@ module.exports = class Lexer { @@ -494,5 +494,5 @@ export class Lexer {
} }
} }
- if (token = this.tokenizer.inlineText(cutSrc, smartypants)) { - if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
@@ -39,14 +39,14 @@ diff --git a/src/Lexer.js b/src/Lexer.js
diff --git a/src/Renderer.js b/src/Renderer.js diff --git a/src/Renderer.js b/src/Renderer.js
--- a/src/Renderer.js --- a/src/Renderer.js
+++ b/src/Renderer.js +++ b/src/Renderer.js
@@ -142,5 +142,5 @@ module.exports = class Renderer { @@ -142,5 +142,5 @@ export class Renderer {
link(href, title, text) { link(href, title, text) {
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href); - href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
+ href = cleanUrl(this.options.baseUrl, href); + href = cleanUrl(this.options.baseUrl, href);
if (href === null) { if (href === null) {
return text; return text;
@@ -155,5 +155,5 @@ module.exports = class Renderer { @@ -155,5 +155,5 @@ export class Renderer {
image(href, title, text) { image(href, title, text) {
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href); - href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
@@ -56,7 +56,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js
diff --git a/src/Tokenizer.js b/src/Tokenizer.js diff --git a/src/Tokenizer.js b/src/Tokenizer.js
--- a/src/Tokenizer.js --- a/src/Tokenizer.js
+++ b/src/Tokenizer.js +++ b/src/Tokenizer.js
@@ -321,14 +321,7 @@ module.exports = class Tokenizer { @@ -320,14 +320,7 @@ export class Tokenizer {
type: 'html', type: 'html',
raw: cap[0], raw: cap[0],
- pre: !this.options.sanitizer - pre: !this.options.sanitizer
@@ -72,7 +72,7 @@ diff --git a/src/Tokenizer.js b/src/Tokenizer.js
- } - }
return token; return token;
} }
@@ -477,15 +470,9 @@ module.exports = class Tokenizer { @@ -476,15 +469,9 @@ export class Tokenizer {
return { return {
- type: this.options.sanitize - type: this.options.sanitize
@@ -90,7 +90,7 @@ diff --git a/src/Tokenizer.js b/src/Tokenizer.js
+ text: cap[0] + text: cap[0]
}; };
} }
@@ -672,10 +659,10 @@ module.exports = class Tokenizer { @@ -671,10 +658,10 @@ export class Tokenizer {
} }
- autolink(src, mangle) { - autolink(src, mangle) {
@@ -103,7 +103,7 @@ diff --git a/src/Tokenizer.js b/src/Tokenizer.js
+ text = escape(cap[1]); + text = escape(cap[1]);
href = 'mailto:' + text; href = 'mailto:' + text;
} else { } else {
@@ -700,10 +687,10 @@ module.exports = class Tokenizer { @@ -699,10 +686,10 @@ export class Tokenizer {
} }
- url(src, mangle) { - url(src, mangle) {
@@ -116,7 +116,7 @@ diff --git a/src/Tokenizer.js b/src/Tokenizer.js
+ text = escape(cap[0]); + text = escape(cap[0]);
href = 'mailto:' + text; href = 'mailto:' + text;
} else { } else {
@@ -737,12 +724,12 @@ module.exports = class Tokenizer { @@ -736,12 +723,12 @@ export class Tokenizer {
} }
- inlineText(src, smartypants) { - inlineText(src, smartypants) {
@@ -135,7 +135,7 @@ diff --git a/src/Tokenizer.js b/src/Tokenizer.js
diff --git a/src/defaults.js b/src/defaults.js diff --git a/src/defaults.js b/src/defaults.js
--- a/src/defaults.js --- a/src/defaults.js
+++ b/src/defaults.js +++ b/src/defaults.js
@@ -9,12 +9,8 @@ function getDefaults() { @@ -9,12 +9,8 @@ export function getDefaults() {
highlight: null, highlight: null,
langPrefix: 'language-', langPrefix: 'language-',
- mangle: true, - mangle: true,
@@ -151,10 +151,10 @@ diff --git a/src/defaults.js b/src/defaults.js
diff --git a/src/helpers.js b/src/helpers.js diff --git a/src/helpers.js b/src/helpers.js
--- a/src/helpers.js --- a/src/helpers.js
+++ b/src/helpers.js +++ b/src/helpers.js
@@ -64,18 +64,5 @@ function edit(regex, opt) { @@ -64,18 +64,5 @@ export function edit(regex, opt) {
const nonWordAndColonTest = /[^\w:]/g; const nonWordAndColonTest = /[^\w:]/g;
const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i; const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
-function cleanUrl(sanitize, base, href) { -export function cleanUrl(sanitize, base, href) {
- if (sanitize) { - if (sanitize) {
- let prot; - let prot;
- try { - try {
@@ -168,36 +168,30 @@ diff --git a/src/helpers.js b/src/helpers.js
- return null; - return null;
- } - }
- } - }
+function cleanUrl(base, href) { +export function cleanUrl(base, href) {
if (base && !originIndependentUrl.test(href)) { if (base && !originIndependentUrl.test(href)) {
href = resolveUrl(base, href); href = resolveUrl(base, href);
@@ -227,10 +214,4 @@ function findClosingBracket(str, b) { @@ -227,10 +214,4 @@ export function findClosingBracket(str, b) {
} }
-function checkSanitizeDeprecation(opt) { -export function checkSanitizeDeprecation(opt) {
- if (opt && opt.sanitize && !opt.silent) { - if (opt && opt.sanitize && !opt.silent) {
- console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options'); - console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
- } - }
-} -}
- -
// copied from https://stackoverflow.com/a/5450113/806777 // copied from https://stackoverflow.com/a/5450113/806777
function repeatString(pattern, count) { export function repeatString(pattern, count) {
@@ -260,5 +241,4 @@ module.exports = {
rtrim,
findClosingBracket,
- checkSanitizeDeprecation,
repeatString
};
diff --git a/src/marked.js b/src/marked.js diff --git a/src/marked.js b/src/marked.js
--- a/src/marked.js --- a/src/marked.js
+++ b/src/marked.js +++ b/src/marked.js
@@ -7,5 +7,4 @@ const Slugger = require('./Slugger.js'); @@ -7,5 +7,4 @@ import { Slugger } from './Slugger.js';
const { import {
merge, merge,
- checkSanitizeDeprecation, - checkSanitizeDeprecation,
escape escape
} = require('./helpers.js'); } from './helpers.js';
@@ -35,5 +34,4 @@ function marked(src, opt, callback) { @@ -35,5 +34,4 @@ export function marked(src, opt, callback) {
opt = merge({}, marked.defaults, opt || {}); opt = merge({}, marked.defaults, opt || {});
- checkSanitizeDeprecation(opt); - checkSanitizeDeprecation(opt);
@@ -219,37 +213,37 @@ diff --git a/src/marked.js b/src/marked.js
diff --git a/test/bench.js b/test/bench.js diff --git a/test/bench.js b/test/bench.js
--- a/test/bench.js --- a/test/bench.js
+++ b/test/bench.js +++ b/test/bench.js
@@ -33,5 +33,4 @@ async function runBench(options) { @@ -37,5 +37,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: false, pedantic: false,
- sanitize: false, - sanitize: false,
smartLists: false smartLists: false
}); });
@@ -45,5 +44,4 @@ async function runBench(options) { @@ -49,5 +48,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: false, pedantic: false,
- sanitize: false, - sanitize: false,
smartLists: false smartLists: false
}); });
@@ -58,5 +56,4 @@ async function runBench(options) { @@ -62,5 +60,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: false, pedantic: false,
- sanitize: false, - sanitize: false,
smartLists: false smartLists: false
}); });
@@ -70,5 +67,4 @@ async function runBench(options) { @@ -74,5 +71,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: false, pedantic: false,
- sanitize: false, - sanitize: false,
smartLists: false smartLists: false
}); });
@@ -83,5 +79,4 @@ async function runBench(options) { @@ -87,5 +83,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: true, pedantic: true,
- sanitize: false, - sanitize: false,
smartLists: false smartLists: false
}); });
@@ -95,5 +90,4 @@ async function runBench(options) { @@ -99,5 +94,4 @@ export async function runBench(options) {
breaks: false, breaks: false,
pedantic: true, pedantic: true,
- sanitize: false, - sanitize: false,
@@ -258,7 +252,7 @@ diff --git a/test/bench.js b/test/bench.js
diff --git a/test/specs/run-spec.js b/test/specs/run-spec.js diff --git a/test/specs/run-spec.js b/test/specs/run-spec.js
--- a/test/specs/run-spec.js --- a/test/specs/run-spec.js
+++ b/test/specs/run-spec.js +++ b/test/specs/run-spec.js
@@ -22,9 +22,4 @@ function runSpecs(title, dir, showCompletionTable, options) { @@ -25,9 +25,4 @@ function runSpecs(title, dir, showCompletionTable, options) {
} }
- if (spec.options.sanitizer) { - if (spec.options.sanitizer) {
@@ -268,77 +262,77 @@ diff --git a/test/specs/run-spec.js b/test/specs/run-spec.js
- -
(spec.only ? fit : (spec.skip ? xit : it))('should ' + passFail + example, async() => { (spec.only ? fit : (spec.skip ? xit : it))('should ' + passFail + example, async() => {
const before = process.hrtime(); const before = process.hrtime();
@@ -53,3 +48,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true }); @@ -56,3 +51,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true });
runSpecs('New', './new'); runSpecs('New', './new');
runSpecs('ReDOS', './redos'); runSpecs('ReDOS', './redos');
-runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning -runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning
diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js
--- a/test/unit/Lexer-spec.js --- a/test/unit/Lexer-spec.js
+++ b/test/unit/Lexer-spec.js +++ b/test/unit/Lexer-spec.js
@@ -589,5 +589,5 @@ paragraph @@ -635,5 +635,5 @@ paragraph
}); });
- it('sanitize', () => { - it('sanitize', () => {
+ /*it('sanitize', () => { + /*it('sanitize', () => {
expectTokens({ expectTokens({
md: '<div>html</div>', md: '<div>html</div>',
@@ -607,5 +607,5 @@ paragraph @@ -653,5 +653,5 @@ paragraph
] ]
}); });
- }); - });
+ });*/ + });*/
}); });
@@ -652,5 +652,5 @@ paragraph @@ -698,5 +698,5 @@ paragraph
}); });
- it('html sanitize', () => { - it('html sanitize', () => {
+ /*it('html sanitize', () => { + /*it('html sanitize', () => {
expectInlineTokens({ expectInlineTokens({
md: '<div>html</div>', md: '<div>html</div>',
@@ -660,5 +660,5 @@ paragraph @@ -706,5 +706,5 @@ paragraph
] ]
}); });
- }); - });
+ });*/ + });*/
it('link', () => { it('link', () => {
@@ -971,5 +971,5 @@ paragraph @@ -1017,5 +1017,5 @@ paragraph
}); });
- it('autolink mangle email', () => { - it('autolink mangle email', () => {
+ /*it('autolink mangle email', () => { + /*it('autolink mangle email', () => {
expectInlineTokens({ expectInlineTokens({
md: '<test@example.com>', md: '<test@example.com>',
@@ -991,5 +991,5 @@ paragraph @@ -1037,5 +1037,5 @@ paragraph
] ]
}); });
- }); - });
+ });*/ + });*/
it('url', () => { it('url', () => {
@@ -1028,5 +1028,5 @@ paragraph @@ -1074,5 +1074,5 @@ paragraph
}); });
- it('url mangle email', () => { - it('url mangle email', () => {
+ /*it('url mangle email', () => { + /*it('url mangle email', () => {
expectInlineTokens({ expectInlineTokens({
md: 'test@example.com', md: 'test@example.com',
@@ -1048,5 +1048,5 @@ paragraph @@ -1094,5 +1094,5 @@ paragraph
] ]
}); });
- }); - });
+ });*/ + });*/
}); });
@@ -1064,5 +1064,5 @@ paragraph @@ -1110,5 +1110,5 @@ paragraph
}); });
- describe('smartypants', () => { - describe('smartypants', () => {
+ /*describe('smartypants', () => { + /*describe('smartypants', () => {
it('single quotes', () => { it('single quotes', () => {
expectInlineTokens({ expectInlineTokens({
@@ -1134,5 +1134,5 @@ paragraph @@ -1180,5 +1180,5 @@ paragraph
}); });
}); });
- }); - });

View File

@@ -86,8 +86,6 @@ function have() {
python -c "import $1; $1; $1.__version__" python -c "import $1; $1; $1.__version__"
} }
mv copyparty/web/deps/marked.full.js.gz srv/ || true
. buildenv/bin/activate . buildenv/bin/activate
have setuptools have setuptools
have wheel have wheel

View File

@@ -35,8 +35,6 @@ ver="$1"
exit 1 exit 1
} }
mv copyparty/web/deps/marked.full.js.gz srv/ || true
mkdir -p dist mkdir -p dist
zip_path="$(pwd)/dist/copyparty-$ver.zip" zip_path="$(pwd)/dist/copyparty-$ver.zip"
tgz_path="$(pwd)/dist/copyparty-$ver.tar.gz" tgz_path="$(pwd)/dist/copyparty-$ver.tar.gz"

View File

@@ -29,6 +29,9 @@ class Cfg(Namespace):
v=v or [], v=v or [],
c=c, c=c,
rproxy=0, rproxy=0,
rsp_slp=0,
s_wr_slp=0,
s_wr_sz=512 * 1024,
ed=False, ed=False,
nw=False, nw=False,
unpost=600, unpost=600,
@@ -48,6 +51,7 @@ class Cfg(Namespace):
mte="a", mte="a",
mth="", mth="",
textfiles="", textfiles="",
doctitle="",
hist=None, hist=None,
no_idx=None, no_idx=None,
no_hash=None, no_hash=None,

View File

@@ -23,6 +23,7 @@ class Cfg(Namespace):
"mtp": [], "mtp": [],
"mte": "a", "mte": "a",
"mth": "", "mth": "",
"doctitle": "",
"hist": None, "hist": None,
"no_idx": None, "no_idx": None,
"no_hash": None, "no_hash": None,
@@ -31,6 +32,9 @@ class Cfg(Namespace):
"no_voldump": True, "no_voldump": True,
"re_maxage": 0, "re_maxage": 0,
"rproxy": 0, "rproxy": 0,
"rsp_slp": 0,
"s_wr_slp": 0,
"s_wr_sz": 512 * 1024,
} }
ex.update(ex2) ex.update(ex2)
super(Cfg, self).__init__(a=a or [], v=v or [], c=c, **ex) super(Cfg, self).__init__(a=a or [], v=v or [], c=c, **ex)