diff --git a/copyparty/__main__.py b/copyparty/__main__.py index e68bde0c..38fb9d10 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -483,6 +483,7 @@ def run_argparse(argv: list[str], formatter: Any, retry: bool) -> argparse.Names ap2.add_argument("--no-dedup", action="store_true", help="disable symlink/hardlink creation; copy file contents instead") ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files") ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; 0 = off and warn if enabled, 1 = off, 2 = on, 3 = on and disable datecheck") + ap2.add_argument("--u2sort", metavar="TXT", type=u, default="s", help="upload order; s=smallest-first, n=alphabetical, fs=force-s, fn=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine") ap2 = ap.add_argument_group('network options') ap2.add_argument("-i", metavar="IP", type=u, default="0.0.0.0", help="ip to bind (comma-sep.)") @@ -755,6 +756,12 @@ def main(argv: Optional[list[str]] = None) -> None: except: raise Exception("invalid value for -p") + for arg, kname, okays in [["--u2sort", "u2sort", "s n fs fn"]]: + val = unicode(getattr(al, kname)) + if val not in okays.split(): + zs = "argument {} cannot be '{}'; try one of these: {}" + raise Exception(zs.format(arg, val, okays)) + if HAVE_SSL: if al.ssl_ver: configure_ssl_ver(al) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 094c1186..a54bce3e 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -2413,6 +2413,7 @@ class HttpCli(object): "dtheme": self.args.theme, "themes": self.args.themes, "turbolvl": self.args.turbo, + "u2sort": self.args.u2sort, } if self.args.js_browser: diff --git a/copyparty/web/browser.html b/copyparty/web/browser.html index e082a8b2..39285bae 100644 --- a/copyparty/web/browser.html +++ b/copyparty/web/browser.html @@ -148,7 +148,8 @@ have_del = {{ have_del|tojson }}, have_unpost = {{ have_unpost|tojson }}, have_zip = {{ have_zip|tojson }}, - turbolvl = {{ turbolvl|tojson }}, + turbolvl = {{ turbolvl }}, + u2sort = "{{ u2sort }}", have_emp = {{ have_emp|tojson }}, txt_ext = "{{ txt_ext }}", {% if no_prism %}no_prism = 1,{% endif %} diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 0ea105a5..cb54bc2c 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -113,6 +113,8 @@ var Ls = { "cut_flag": "ensure only one tab is uploading at a time $N -- other tabs must have this enabled too $N -- only affects tabs on the same domain", + "cut_az": "upload files in alphabetical order, rather than smallest-file-first$N$Nalphabetical order can make it easier to eyeball if something went wrong on the server, but it makes uploading slightly slower on fiber / LAN", + "cft_text": "favicon text (blank and refresh to disable)", "cft_fg": "foreground color", "cft_bg": "background color", @@ -438,6 +440,8 @@ var Ls = { "cut_flag": "samkjører nettleserfaner slik at bare én $N kan holde på med befaring / opplastning $N -- andre faner må også ha denne skrudd på $N -- fungerer kun innenfor samme domene", + "cut_az": "last opp filer i alfabetisk rekkefølge, istedenfor minste-fil-først$N$Nalfabetisk kan gjøre det lettere å anslå om alt gikk bra, men er bittelitt tregere på fiber / LAN", + "cft_text": "ikontekst (blank ut og last siden på nytt for å deaktivere)", "cft_fg": "farge", "cft_bg": "bakgrunnsfarge", @@ -824,6 +828,7 @@ ebi('op_cfg').innerHTML = ( ' turbo\n' + ' date-chk\n' + ' 💤\n' + + ' az\n' + ' \n' + ' \n' + '\n' + diff --git a/copyparty/web/md2.js b/copyparty/web/md2.js index 81ed2fdb..7bdadb72 100644 --- a/copyparty/web/md2.js +++ b/copyparty/web/md2.js @@ -510,14 +510,15 @@ function setsel(s) { // cut/copy current line -function md_cut() { +function md_cut(cut) { var s = linebounds(); if (s.car != s.cdr) return; dom_src.setSelectionRange(s.n1, s.n2 + 1, 'forward'); setTimeout(function () { - dom_src.setSelectionRange(s.n1, s.n1, 'forward'); + var i = cut ? s.n1 : s.car; + dom_src.setSelectionRange(i, i, 'forward'); }, 1); } @@ -969,7 +970,7 @@ var set_lno = (function () { return false; } if (ev.code == "KeyX" || ev.code == "KeyC") { - md_cut(); + md_cut(ev.code == "KeyX"); return true; //sic } } diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 5f042b59..8eb5e299 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -663,6 +663,7 @@ function up2k_init(subtle) { bcfg_bind(uc, 'fsearch', 'fsearch', false, set_fsearch, false); bcfg_bind(uc, 'turbo', 'u2turbo', turbolvl > 1, draw_turbo, false); bcfg_bind(uc, 'datechk', 'u2tdate', turbolvl < 3, null, false); + bcfg_bind(uc, 'az', 'u2sort', u2sort.indexOf('n') + 1, set_u2sort, false); var st = { "files": [], @@ -1018,6 +1019,13 @@ function up2k_init(subtle) { var evpath = get_evpath(), draw_each = good_files.length < 50; + if (!uc.az) + good_files.sort(function (a, b) { + a = a[0].size; + b = b[0].size; + return a < b ? -1 : a > b ? 1 : 0; + }); + for (var a = 0; a < good_files.length; a++) { var fobj = good_files[a][0], name = good_files[a][1], @@ -1066,9 +1074,9 @@ function up2k_init(subtle) { entry.purl + uricom_enc(entry.name)).join(' '), '📐 ' + L.u_hashing, '' - ], fobj.size, draw_each); + ], entry.size, draw_each); - st.bytes.total += fobj.size; + st.bytes.total += entry.size; st.files.push(entry); if (!entry.size) push_t(st.todo.handshake, entry); @@ -1203,6 +1211,9 @@ function up2k_init(subtle) { return false; if (uc.multitask) { + if (!uc.az) + return st.todo.handshake.length + st.busy.handshake.length < 2; + var ahead = st.bytes.hashed - st.bytes.finished, nmax = ahead < biggest_file / 8 ? 32 : 16; @@ -2117,6 +2128,14 @@ function up2k_init(subtle) { } } + function set_u2sort() { + if (u2sort.indexOf('f') < 0) + return; + + bcfg_set('u2sort', uc.az = u2sort.indexOf('n') + 1); + localStorage.removeItem('u2sort'); + } + function nop(e) { ev(e); this.click();