diff --git a/copyparty/__main__.py b/copyparty/__main__.py index f88c5cc1..81b2f255 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -946,6 +946,7 @@ def add_ui(ap, retry): 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("--html-head", metavar="TXT", type=u, default="", help="text to append to the
of all HTML pages") + ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI)") ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext") ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)") ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty", help="title / service-name to show in html documents") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index c996d9e4..f784d080 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -778,8 +778,8 @@ class HttpCli(object): if "k304" in self.uparam: return self.set_k304() - if "am_js" in self.uparam: - return self.set_am_js() + if "setck" in self.uparam: + return self.setck() if "reset" in self.uparam: return self.set_cfg_reset() @@ -2896,15 +2896,16 @@ class HttpCli(object): self.redirect("", "?h#cc") return True - def set_am_js(self) -> bool: - v = "n" if self.uparam["am_js"] == "n" else "y" - ck = gencookie("js", v, self.args.R, False, 86400 * 299) + def setck(self) -> bool: + k, v = self.uparam["setck"].split("=", 1) + t = None if v == "" else 86400 * 299 + ck = gencookie(k, v, self.args.R, False, t) self.out_headerlist.append(("Set-Cookie", ck)) - self.reply(b"promoted\n") + self.reply(b"o7\n") return True def set_cfg_reset(self) -> bool: - for k in ("k304", "js", "cppwd", "cppws"): + for k in ("k304", "js", "idxh", "cppwd", "cppws"): cookie = gencookie(k, "x", self.args.R, False, None) self.out_headerlist.append(("Set-Cookie", cookie)) @@ -3433,6 +3434,7 @@ class HttpCli(object): "dtheme": self.args.theme, "themes": self.args.themes, "turbolvl": self.args.turbo, + "idxh": int(self.args.ih), "u2sort": self.args.u2sort, } @@ -3566,6 +3568,16 @@ class HttpCli(object): files.append(item) item["rd"] = rem + if self.cookies.get("idxh") == "y": + idx_html = set(["index.htm", "index.html"]) + for item in files: + if item["name"] in idx_html: + # do full resolve in case of shadowed file + vp = vjoin(self.vpath.split("?")[0], item["name"]) + vn, rem = self.asrv.vfs.get(vp, self.uname, True, False) + ap = vn.canonical(rem) + return self.tx_file(ap) # is no-cache + tagset: set[str] = set() for fe in files: fn = fe["name"] diff --git a/copyparty/web/browser.html b/copyparty/web/browser.html index 83823d0c..0485b2c3 100644 --- a/copyparty/web/browser.html +++ b/copyparty/web/browser.html @@ -155,6 +155,7 @@ sb_lg = "{{ sb_lg }}", lifetime = {{ lifetime }}, turbolvl = {{ turbolvl }}, + idxh = {{ idxh }}, frand = {{ frand|tojson }}, u2sort = "{{ u2sort }}", have_emp = {{ have_emp|tojson }}, diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index d79e3a8e..bd3f09da 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -193,6 +193,7 @@ var Ls = { "ct_dots": "show hidden files (if server permits)", "ct_dir1st": "sort folders before files", "ct_readme": "show README.md in folder listings", + "ct_idxh": "show index.html instead of folder listing", "ct_sbars": "show scrollbars", "cut_turbo": "the yolo button, you probably DO NOT want to enable this:$N$Nuse this if you were uploading a huge amount of files and had to restart for some reason, and want to continue the upload ASAP$N$Nthis replaces the hash-check with a simple "does this have the same filesize on the server?" so if the file contents are different it will NOT be uploaded$N$Nyou should turn this off when the upload is done, and then "upload" the same files again to let the client verify them", @@ -652,6 +653,7 @@ var Ls = { "ct_dots": "vis skjulte filer (gitt at serveren tillater det)", "ct_dir1st": "sorter slik at mapper kommer foran filer", "ct_readme": "vis README.md nedenfor filene", + "ct_idxh": "vis index.html istedenfor fil-liste", "ct_sbars": "vis rullgardiner / skrollefelt", "cut_turbo": "forenklet befaring ved opplastning; bør sannsynlig ikke skrus på:$N$Nnyttig dersom du var midt i en svær opplastning som måtte restartes av en eller annen grunn, og du vil komme igang igjen så raskt som overhodet mulig.$N$Nnår denne er skrudd på så forenkles befaringen kraftig; istedenfor å utføre en trygg sjekk på om filene finnes på serveren i god stand, så sjekkes kun om filstørrelsen stemmer. Så dersom en korrupt fil skulle befinne seg på serveren allerede, på samme sted med samme størrelse og navn, så blir det ikke oppdaget.$N$Ndet anbefales å kun benytte denne funksjonen for å komme seg raskt igjennom selve opplastningen, for så å skru den av, og til slutt "laste opp" de samme filene én gang til -- slik at integriteten kan verifiseres", @@ -1083,6 +1085,7 @@ ebi('op_cfg').innerHTML = ( ' dotfiles\n' + ' 📁 first\n' + ' 📜 readme\n' + + ' htm\n' + ' ⟊\n' + ' \n' + '\n' + @@ -4986,6 +4989,7 @@ var treectl = (function () { treesz = clamp(icfg_get('treesz', 16), 10, 50); bcfg_bind(r, 'ireadme', 'ireadme', true); + bcfg_bind(r, 'idxh', 'idxh', idxh, setidxh); bcfg_bind(r, 'dyn', 'dyntree', true, onresize); bcfg_bind(r, 'dots', 'dotfiles', false, function (v) { r.goto(get_evpath()); @@ -5010,6 +5014,16 @@ var treectl = (function () { } setwrap(r.wtree); + function setidxh(v) { + if (!v == !/\bidxh=y\b/.exec('' + document.cookie)) + return; + + var xhr = new XHR(); + xhr.open('GET', SR + '/?setck=idxh=' + (v ? 'y' : 'n'), true); + xhr.send(); + } + setidxh(r.idxh); + r.entree = function (e, nostore) { ev(e); entreed = true; @@ -5438,6 +5452,9 @@ var treectl = (function () { return; } + if (r.chk_index_html(this.top, res)) + return; + for (var a = 0; a < res.files.length; a++) if (res.files[a].tags === undefined) res.files[a].tags = {}; @@ -5485,6 +5502,17 @@ var treectl = (function () { } } + r.chk_index_html = function (top, res) { + if (!r.idxh || !res || !res.files) + return; + + for (var a = 0; a < res.files.length; a++) + if (/^index.html?(\?|$)/i.exec(res.files[a].href)) { + window.location = vjoin(top, res.files[a].href); + return true; + } + }; + r.gentab = function (top, res) { var nodes = res.dirs.concat(res.files), html = mk_files_header(res.taglist), @@ -5605,14 +5633,18 @@ var treectl = (function () { qsr('#bbsw'); if (ls0 === null) { var xhr = new XHR(); - xhr.open('GET', SR + '/?am_js', true); + xhr.open('GET', SR + '/?setck=js=y', true); xhr.send(); r.ls_cb = showfile.addlinks; return r.reqls(get_evpath(), false); } - r.gentab(get_evpath(), ls0); + var top = get_evpath(); + if (r.chk_index_html(top, ls0)) + return; + + r.gentab(top, ls0); pbar.onresize(); vbar.onresize(); showfile.addlinks(); diff --git a/copyparty/web/util.js b/copyparty/web/util.js index c6103459..4156ad60 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -632,6 +632,29 @@ function vsplit(vp) { } +function vjoin(p1, p2) { + if (!p1) + p1 = ''; + + if (!p2) + p2 = ''; + + if (p1.endsWith('/')) + p1 = p1.slice(0, -1); + + if (p2.startsWith('/')) + p2 = p2.slice(1); + + if (!p1) + return p2; + + if (!p2) + return p1; + + return p1 + '/' + p2; +} + + function uricom_enc(txt, do_fb_enc) { try { return encodeURIComponent(txt);