diff --git a/LICENSE b/LICENSE index 1e729fcc..45837e76 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 ed +Copyright (c) 2019 ed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/contrib/package/arch/PKGBUILD b/contrib/package/arch/PKGBUILD index db923e46..98c8854a 100644 --- a/contrib/package/arch/PKGBUILD +++ b/contrib/package/arch/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: icxes pkgname=copyparty -pkgver="1.9.30" +pkgver="1.9.31" pkgrel=1 pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, zeroconf, media indexer, thumbnails++" arch=("any") @@ -21,7 +21,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag ) source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") backup=("etc/${pkgname}.d/init" ) -sha256sums=("dd93fcc0f8c4885724f65d4c60d93af17bc8d6f55e5b4a00e8f75f40cc7d1552") +sha256sums=("a8ec1faf8cb224515355226882fdb2d1ab1de42d96ff78e148b930318867a71e") build() { cd "${srcdir}/${pkgname}-${pkgver}" diff --git a/contrib/package/nix/copyparty/pin.json b/contrib/package/nix/copyparty/pin.json index 58472070..6845ad7e 100644 --- a/contrib/package/nix/copyparty/pin.json +++ b/contrib/package/nix/copyparty/pin.json @@ -1,5 +1,5 @@ { - "url": "https://github.com/9001/copyparty/releases/download/v1.9.30/copyparty-sfx.py", - "version": "1.9.30", - "hash": "sha256-MUHlRrNF5DwEpnGIKjfry0pM26OlnrPgWiwPxfRXUT4=" + "url": "https://github.com/9001/copyparty/releases/download/v1.9.31/copyparty-sfx.py", + "version": "1.9.31", + "hash": "sha256-yp7qoiW5yzm2M7qVmYY7R+SyhZXlqL+JxsXV22aS+MM=" } \ No newline at end of file diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 30713076..7e5c42c0 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -893,7 +893,7 @@ def add_upload(ap): ap2.add_argument("--df", metavar="GiB", type=float, default=0, help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests") 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; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck") - ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good for low-latency (same-country) connections, 4-8 for android clients, 16-32 for cross-atlantic (max=64)") + ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good for low-latency (same-country) connections, 4-8 for android clients, 16 for cross-atlantic (max=64)") ap2.add_argument("--u2sort", metavar="TXT", type=u, default="s", help="upload order; [\033[32ms\033[0m]=smallest-first, [\033[32mn\033[0m]=alphabetical, [\033[32mfs\033[0m]=force-s, [\033[32mfn\033[0m]=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine") ap2.add_argument("--write-uplog", action="store_true", help="write POST reports to textfiles in working-directory") diff --git a/copyparty/__version__.py b/copyparty/__version__.py index 2d614181..0a1c5ec3 100644 --- a/copyparty/__version__.py +++ b/copyparty/__version__.py @@ -1,8 +1,8 @@ # coding: utf-8 -VERSION = (1, 9, 30) +VERSION = (1, 9, 31) CODENAME = "prometheable" -BUILD_DT = (2024, 1, 25) +BUILD_DT = (2024, 2, 3) S_VERSION = ".".join(map(str, VERSION)) S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT) diff --git a/copyparty/web/baguettebox.js b/copyparty/web/baguettebox.js index 3a173f8a..39a9c8d1 100644 --- a/copyparty/web/baguettebox.js +++ b/copyparty/web/baguettebox.js @@ -615,7 +615,43 @@ window.baguetteBox = (function () { documentLastFocus && documentLastFocus.focus(); isOverlayVisible = false; - }, 500); + unvid(); + unfig(); + }, 250); + } + + function unvid(keep) { + var vids = QSA('#bbox-overlay video'); + for (var a = vids.length - 1; a >= 0; a--) { + var v = vids[a]; + if (v == keep) + continue; + + v.src = ''; + v.load(); + + var p = v.parentNode; + p.removeChild(v); + p.parentNode.removeChild(p); + } + } + + function unfig(keep) { + var figs = QSA('#bbox-overlay figure'), + npre = options.preload || 0, + k = []; + + if (keep === undefined) + keep = -9; + + for (var a = keep - npre; a <= keep + npre; a++) + k.push('bbox-figure-' + a); + + for (var a = figs.length - 1; a >= 0; a--) { + var f = figs[a]; + if (!has(k, f.getAttribute('id'))) + f.parentNode.removeChild(f); + } } function loadImage(index, callback) { @@ -708,6 +744,7 @@ window.baguetteBox = (function () { } function show(index, gallery) { + gallery = gallery || currentGallery; if (!isOverlayVisible && index >= 0 && index < gallery.length) { prepareOverlay(gallery, options); showOverlay(index); @@ -720,12 +757,10 @@ window.baguetteBox = (function () { if (index >= imagesElements.length) return bounceAnimation('right'); - var v = vid(); - if (v) { - v.src = ''; - v.load(); - v.parentNode.removeChild(v); + try { + vid().pause(); } + catch (ex) { } currentIndex = index; loadImage(currentIndex, function () { @@ -734,6 +769,15 @@ window.baguetteBox = (function () { }); updateOffset(); + if (options.animation == 'none') + unvid(vid()); + else + setTimeout(function () { + unvid(vid()); + }, 100); + + unfig(index); + if (options.onChange) options.onChange(currentIndex, imagesElements.length); diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 9d045717..98c14d0c 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -332,6 +332,8 @@ var Ls = { "fp_confirm": "move these {0} items here?", "fp_etab": 'failed to read clipboard from other browser tab', + "mk_noname": "type a name into the text field on the left before you do that :p", + "tv_load": "Loading text document:\n\n{0}\n\n{1}% ({2} of {3} MiB loaded)", "tv_xe1": "could not load textfile:\n\nerror ", "tv_xe2": "404, file not found", @@ -463,6 +465,7 @@ var Ls = { "u_emtleakf": 'try the following:\n\nPS: firefox will hopefully have a bugfix at some point', "u_s404": "not found on server", "u_expl": "explain", + "u_maxconn": "most browsers limit this to 6, but firefox lets you raise it with connections-per-server in about:config", "u_tu": '

WARNING: turbo enabled,  client may not detect and resume incomplete uploads; see turbo-button tooltip

', "u_ts": '

WARNING: turbo enabled,  search results can be incorrect; see turbo-button tooltip

', "u_turbo_c": "turbo is disabled in server config", @@ -821,6 +824,8 @@ var Ls = { "fp_confirm": "flytt disse {0} filene hit?", "fp_etab": 'kunne ikke lese listen med filer ifra den andre nettleserfanen', + "mk_noname": "skriv inn et navn i tekstboksen til venstre fΓΈrst :p", + "tv_load": "Laster inn tekstfil:\n\n{0}\n\n{1}% ({2} av {3} MiB lastet ned)", "tv_xe1": "kunne ikke laste tekstfil:\n\nfeil ", "tv_xe2": "404, Fil ikke funnet", @@ -952,6 +957,7 @@ var Ls = { "u_emtleakf": 'prΓΈver fΓΈlgende:\n\nPS: Firefox fikser forhΓ₯pentligvis feilen en eller annen gang', "u_s404": "ikke funnet pΓ₯ serveren", "u_expl": "forklar", + "u_maxconn": "de fleste nettlesere tillater ikke mer enn 6, men firefox lar deg ΓΈke grensen med connections-per-server in about:config", "u_tu": '

ADVARSEL: turbo er pΓ₯,  avbrutte opplastninger vil muligens ikke oppdages og gjenopptas; hold musepekeren over turbo-knappen for mer info

', "u_ts": '

ADVARSEL: turbo er pΓ₯,  sΓΈkeresultater kan vΓ¦re feil; hold musepekeren over turbo-knappen for mer info

', "u_turbo_c": "turbo er deaktivert i serverkonfigurasjonen", @@ -7267,6 +7273,28 @@ var msel = (function () { })(); +(function () { + if (!window.FormData) + return; + + var form = QS('#op_new_md>form'), + tb = QS('#op_new_md input[name="name"]'); + + form.onsubmit = function (e) { + if (tb.value) { + if (toast.tag == L.mk_noname) + toast.hide(); + + return true; + } + + ev(e); + toast.err(10, L.mk_noname, L.mk_noname); + return false; + }; +})(); + + (function () { if (!window.FormData) return; @@ -7280,8 +7308,16 @@ var msel = (function () { form.onsubmit = function (e) { ev(e); - clmod(sf, 'vis', 1); var dn = tb.value; + if (!dn) { + toast.err(10, L.mk_noname, L.mk_noname); + return false; + } + + if (toast.tag == L.mk_noname || toast.tag == L.fd_xe1) + toast.hide(); + + clmod(sf, 'vis', 1); sf.textContent = 'creating "' + dn + '"...'; var fd = new FormData(); diff --git a/copyparty/web/ui.css b/copyparty/web/ui.css index 72b36a1d..e27030ec 100644 --- a/copyparty/web/ui.css +++ b/copyparty/web/ui.css @@ -147,6 +147,10 @@ html { #toast.err #toastc { background: #d06; } +#toast code { + padding: 0 .2em; + background: rgba(0,0,0,0.2); +} #tth { color: #fff; background: #111; diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index aa831248..5386d5eb 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -895,6 +895,7 @@ function up2k_init(subtle) { "bytes": { "total": 0, "hashed": 0, + "inflight": 0, "uploaded": 0, "finished": 0 }, @@ -1543,17 +1544,21 @@ function up2k_init(subtle) { if (uc.fsearch) t.push(['u2etat', st.bytes.hashed, st.bytes.hashed, st.time.hashing]); } + + var b_up = st.bytes.inflight + st.bytes.uploaded, + b_fin = st.bytes.inflight + st.bytes.finished; + if (nsend) { st.time.uploading += td; - t.push(['u2etau', st.bytes.uploaded, st.bytes.finished, st.time.uploading]); + t.push(['u2etau', b_up, b_fin, st.time.uploading]); } if ((nhash || nsend) && !uc.fsearch) { - if (!st.bytes.finished) { + if (!b_fin) { ebi('u2etat').innerHTML = L.u_etaprep; } else { st.time.busy += td; - t.push(['u2etat', st.bytes.finished, st.bytes.finished, st.time.busy]); + t.push(['u2etat', b_fin, b_fin, st.time.busy]); } } for (var a = 0; a < t.length; a++) { @@ -2539,6 +2544,7 @@ function up2k_init(subtle) { cdr = t.size; var orz = function (xhr) { + st.bytes.inflight -= xhr.bsent; var txt = unpre((xhr.response && xhr.response.err) || xhr.responseText); if (txt.indexOf('upload blocked by x') + 1) { apop(st.busy.upload, upt); @@ -2583,7 +2589,10 @@ function up2k_init(subtle) { btot = Math.floor(st.bytes.total / 1024 / 1024); xhr.upload.onprogress = function (xev) { - pvis.prog(t, npart, xev.loaded); + var nb = xev.loaded; + st.bytes.inflight += nb - xhr.bsent; + xhr.bsent = nb; + pvis.prog(t, npart, nb); }; xhr.onload = function (xev) { try { orz(xhr); } catch (ex) { vis_exh(ex + '', 'up2k.js', '', '', ex); } @@ -2592,6 +2601,8 @@ function up2k_init(subtle) { if (crashed) return; + st.bytes.inflight -= (xhr.bsent || 0); + if (!toast.visible) toast.warn(9.98, L.u_cuerr.format(npart, Math.ceil(t.size / chunksize), t.name), t); @@ -2608,6 +2619,7 @@ function up2k_init(subtle) { if (xhr.overrideMimeType) xhr.overrideMimeType('Content-Type', 'application/octet-stream'); + xhr.bsent = 0; xhr.responseType = 'text'; xhr.send(t.fobj.slice(car, cdr)); } @@ -2708,6 +2720,9 @@ function up2k_init(subtle) { if (parallel_uploads > 16) parallel_uploads = 16; + if (parallel_uploads > 7) + toast.warn(10, L.u_maxconn); + obj.value = parallel_uploads; bumpthread({ "target": 1 }); } diff --git a/copyparty/web/util.js b/copyparty/web/util.js index dc548cab..6ea920b2 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -1455,7 +1455,9 @@ var toast = (function () { } r.hide = function (e) { - ev(e); + if (this === ebi('toastc')) + ev(e); + unscroll(); clearTimeout(te); clmod(obj, 'vis'); @@ -1985,6 +1987,9 @@ function xhrchk(xhr, prefix, e404, lvl, tag) { if (xhr.status < 400 && xhr.status >= 200) return true; + if (tag === undefined) + tag = prefix; + var errtxt = (xhr.response && xhr.response.err) || xhr.responseText, fun = toast[lvl || 'err'], is_cf = /[Cc]loud[f]lare|>Just a mo[m]ent|#cf-b[u]bbles|Chec[k]ing your br[o]wser|\/chall[e]nge-platform|"chall[e]nge-error|nable Ja[v]aScript and cook/.test(errtxt); diff --git a/docs/changelog.md b/docs/changelog.md index 545a8e26..8ce72ec8 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,33 @@ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +# 2024-0125-2252 `v1.9.30` retime + +probably last release before v1.10 (IdP), please watch warmly + +## new features + +* option to replace serverside last-modified timestamps to match uploader's local files 55eb6921 + * requires uploader to have write+delete permissions because it tampers with existing files + * in the browser-UI, enable with the `reπŸ“…` button in the settings tab `βš™οΈ` + * u2c (commandline uploader): `--touch` +* media player can shuffle songs now 01c82b54 + * click `πŸ”€` in the media-player settings tab `🎺` to enable +* windows: retry deleting busy files 3313503e aa3a9719 + * to support webdav-clients that upload and then immediately delete files (clonezilla) +* options in batch-rename UI to ensure filenames are windows-safe b4e0a341 +* more support for older browsers 4ef31060 + * ie9: gridview, navpane, text-viewer, text-editor + * ie9, firefox10: make sure toasts are properly closed + +## bugfixes + +* older chromes (and current iPhones) could randomly panic in incognito mode b32d6520 +* errormessage filepath sanitizer didn't catch histpaths in non-default locations 0f386c4b +* now possible to mount the entire filesystem as a volume (please don't) 14bccbe4 +* on 32bit machines, disable sendfile when necessary to avoid python bug b9d0c853 +* `-q` would still print filesystem-indexing progress to STDOUT 6dbfcddc + + + β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ # 2024-0114-0629 `v1.9.29` RAM friendly diff --git a/docs/notes.md b/docs/notes.md index 9f4a9733..7aa0cc39 100644 --- a/docs/notes.md +++ b/docs/notes.md @@ -1,3 +1,19 @@ +this file accidentally got committed at some point, so let's put it to use + +# trivia / lore + +copyparty started as [three separate php projects](https://a.ocv.me/pub/stuff/old-php-projects/); an nginx custom directory listing (which became a php script), and a php music/picture viewer, and an additional php project for resumable uploads: + +* findex -- directory browser / gallery with thumbnails and a music player which sometime back in 2009 had a canvas visualizer grabbing fft data from a flash audio player +* findex.mini -- plain-listing fork of findex with streaming zip-download of folders (the js and design should look familiar) +* upper and up2k -- up2k being the star of the show and where copyparty's chunked resumable uploads came from + +the first link has screenshots but if that doesn't work there's also a [tar here](https://ocv.me/dev/old-php-projects.tgz) + +---- + +below this point is misc useless scribbles + # up2k.js ## potato detection