Merge commit '47e4220c70787a80ab79e518d5b77e544e608c7e' into hovudstraum

This commit is contained in:
Til Schmitter 2026-05-02 15:31:23 +02:00
commit ffb69a38fb
2 changed files with 72 additions and 70 deletions

View file

@ -659,11 +659,15 @@ the main tabs in the ui
* `[🔎]` [search](#searching) by size, date, path/name, mp3-tags ...
* `[🧯]` [unpost](#unpost): undo/delete accidental uploads
* `[🚀]` and `[🎈]` are the [uploaders](#uploading)
* `[📟]` send-msg: either to server-log or into textfiles if `--urlform save`
* `[⚙️]` client config options
## quick actions (+)
* `[📂]` mkdir: create directories
* `[📝]` new-file: create a new textfile
* `[📟]` send-msg: either to server-log or into textfiles if `--urlform save`
* `[🎺]` audio-player config options
* `[⚙️]` general client config options
* `[🚀]` upload: quick way to pick files for upload
## hotkeys
@ -732,9 +736,9 @@ the browser has the following hotkeys (always qwerty)
## navpane
switching between breadcrumbs or navpane
opening the navpane
click the `🌲` or pressing the `B` hotkey to toggle between breadcrumbs path (default), or a navpane (tree-browser sidebar thing)
clicking the `≡` or pressing the `B` hotkey toggles the navpane (tree-browser sidebar thing)
* `[+]` and `[-]` (or hotkeys `A`/`D`) adjust the size
* `[🎯]` jumps to the currently open folder
@ -747,7 +751,7 @@ click the `🌲` or pressing the `B` hotkey to toggle between breadcrumbs path (
## thumbnails
press `g` or `田` to toggle grid-view instead of the file listing and `t` toggles icons / thumbnails
press `g` or use the view mode buttons in the top left to toggle grid-view instead of the file listing and `t` toggles icons / thumbnails
* can be made default globally with `--grid` or per-volume with volflag `grid`
* enable by adding `?imgs` to a link, or disable with `?imgs=0`
@ -910,9 +914,7 @@ dropping files into the browser also lets you see if they exist on the server
![copyparty-fsearch-fs8](https://user-images.githubusercontent.com/241032/129635361-c79286f0-b8f1-440e-aaf4-6e929428fac9.png)
when you drag/drop files into the browser, you will see two dropzones: `Upload` and `Search`
> on a phone? toggle the `[🔎]` switch green before tapping the big yellow Search button to select your files
toggle the `[🔎]` switch in the upload options to search for files instead of uploading
the files will be hashed on the client-side, and each hash is sent to the server, which checks if that file exists somewhere
@ -982,6 +984,8 @@ file selection: click somewhere on the line (not the link itself), then:
you can copy/move files across browser tabs (cut/copy in one tab, paste in another)
you can drag/drop selected files into other folders
## shares
@ -1158,7 +1162,7 @@ some highlights:
click the `play` link next to an audio file, or copy the link target to [share it](https://a.ocv.me/pub/demo/music/Ubiktune%20-%20SOUNDSHOCK%202%20-%20FM%20FUNK%20TERRROR!!/#af-1fbfba61&t=18) (optionally with a timestamp to start playing from, like that example does)
open the `[🎺]` media-player-settings tab to configure it,
open the `[⚙]` configuration options and go to the `[🎵]` media player section to configure it,
* "switches":
* `[🔁]` repeats one single song forever
* `[🔀]` shuffles the files inside each folder
@ -1210,7 +1214,7 @@ you can use foobar2000, deadbeef, just about any standalone player should work -
alternatively, you can create the playlist using copyparty itself:
* open the `[🎺]` media-player-settings tab and enable the `[📻]` create-playlist feature -- this adds two new buttons in the bottom-right tray, `[📻add]` and `[📻copy]` which appear when you listen to music, or when you select a few audiofiles
* open the `[⚙]` configuration options, go to the `[🎵]` media player section and enable the `[📻]` create-playlist feature -- this adds two new buttons in the bottom-right tray, `[📻add]` and `[📻copy]` which appear when you listen to music, or when you select a few audiofiles
* click the `📻add` button while a song is playing (or when you've selected some songs) and they'll be added to "the list" (you can't see it yet)
@ -1299,6 +1303,12 @@ see [./srv/expand/](./srv/expand/) for usage and examples
search by size, date, path/name, mp3-tags, ...
by default, the `[🔍]` search button shows the folder search bar.
search for files within a folder and optionally its subfolders.
for extended search options, use the dropdown arrow to open the full search UI
![copyparty-search-fs8](https://user-images.githubusercontent.com/241032/129635365-c0ff2a9f-0ee5-4fc3-8bb6-006033cf67b8.png)
when started with `-e2dsa` copyparty will scan/index all your files. This avoids duplicates on upload, and also makes the volumes searchable through the web-ui:

View file

@ -2,6 +2,7 @@
var J_BRW = 1;
// disables emojis
var fun_tgl = sread('fun_tgl');
if( fun_tgl == null)
swrite('fun_tgl', 1);
@ -1350,7 +1351,6 @@ ebi('op_cfg').innerHTML = (
var s = subSettings.children[ii];
var info = tt.parse(s.getAttribute('tt'));
s.removeAttribute('tt');
//s.href = '#' + sId;
section += '<div id="' + subSettings.id + '" class="setting">' +
s.outerHTML +
((info != null && info.length > 0) ? '<p class="s_desc">' + info + '</p>' : '') +
@ -1528,9 +1528,6 @@ function goto(dest) {
clmod(obj[a], 'vis');
if (dest) {
if(dest == 'mkdir' || dest == 'new_md')
return;
var lnk = QS('#ops>a[data-dest=' + dest + ']'),
nps = lnk.getAttribute('data-perm');
@ -1569,6 +1566,7 @@ function goto(dest) {
ebi('srchfolder_div').style.display = dest == 'search' ? 'block' : 'none';
clmod(document.documentElement, 'op_open', dest);
// enables the use of keyboard page nav on modals
clmod(document.documentElement, 'noscroll', QS('.modal.vis'));
if (treectl)
@ -2471,6 +2469,7 @@ function auto_grad(can, color, color2) {
return g;
}
// buffer/position bar
var pbar = (function () {
var r = {},
@ -2586,22 +2585,21 @@ var pbar = (function () {
}
var step = sm > 1 ? 1 : sm > 0.4 ? 3 : sm > 0.05 ? 30 : 720;
if(false){
bctx.fillStyle = light && !dy ? 'rgba(0,0,0,0.15)' : 'rgba(255, 255, 255, 0.15)';
for (var p = step, mins = adur / 10; p <= mins; p += step)
bctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
//bctx.fillStyle = light && !dy ? 'rgba(0,0,0,0.15)' : 'rgba(255, 255, 255, 0.15)';
//for (var p = step, mins = adur / 10; p <= mins; p += step)
// bctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
step = sm > 0.15 ? 1 : sm > 0.05 ? 10 : 360;
bctx.fillStyle = light && !dy ? 'rgba(0, 0, 0, 0.5)' : 'rgba(255, 255, 255, 0.5)';
for (var p = step, mins = adur / 60; p <= mins; p += step)
bctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
//step = sm > 0.15 ? 1 : sm > 0.05 ? 10 : 360;
//bctx.fillStyle = light && !dy ? 'rgba(0, 0, 0, 0.5)' : 'rgba(255, 255, 255, 0.5)';
//for (var p = step, mins = adur / 60; p <= mins; p += step)
// bctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
step = sm > 0.33 ? 1 : sm > 0.15 ? 5 : sm > 0.05 ? 10 : sm > 0.01 ? 60 : 720;
bctx.fillStyle = dz ? '#0f0' : dy ? '#999' : light ? 'rgba(0, 0, 0, 0.9)' : 'rgb(255, 255, 255)';
for (var p = step, mins = adur / 60; p <= mins; p += step) {
bctx.fillText(p, Math.floor(sm * p * 60 + 3), pc.h / 3);
}
}
//step = sm > 0.33 ? 1 : sm > 0.15 ? 5 : sm > 0.05 ? 10 : sm > 0.01 ? 60 : 720;
//bctx.fillStyle = dz ? '#0f0' : dy ? '#999' : light ? 'rgba(0, 0, 0, 0.9)' : 'rgb(255, 255, 255)';
//for (var p = step, mins = adur / 60; p <= mins; p += step) {
// bctx.fillText(p, Math.floor(sm * p * 60 + 3), pc.h / 3);
//}
step = sm > 0.2 ? 10 : sm > 0.1 ? 30 : sm > 0.01 ? 60 : sm > 0.005 ? 720 : 1440;
bctx.fillStyle = light ? 'rgba(0,0,0,1)' : 'rgba(255,255,255,1)';
@ -5994,6 +5992,8 @@ var thegrid = (function () {
var ico2 = ebi('listicon_template').cloneNode(true);
clmod(ico1, 'on', 't');
clmod(ico2, 'on', 't');
// file list header
ebi('wtc').innerHTML = (
ico1.outerHTML +
ico2.outerHTML +
@ -6026,10 +6026,8 @@ var thegrid = (function () {
l = this.getAttribute('l'),
grdbtn = clgot(this, 'grdbtn');
if(grdbtn) {
ebi('griden').click();
if(grdbtn)
return;
}
if (z)
return setsz(z > 0 ? r.sz * z : r.sz / (-z));
@ -6135,11 +6133,8 @@ var thegrid = (function () {
function gselclick(e) {
var oth = ebi(this.closest('a').getAttribute('ref')),
td = oth.closest('td').nextSibling,
tr = td.parentNode;
//this.checked = !this.checked;
td = oth.closest('td').nextSibling;
td.onclick.call(td, e);
// clmod(this, 'sel', clgot(tr, 'sel'));
}
function gclick2(e) {
@ -6171,9 +6166,6 @@ var thegrid = (function () {
if (e.shiftKey)
return r.loadsel();
clmod(this, 'sel', clgot(tr, 'sel'));
var chk = this.getElementsByTagName('input')[0];
if(chk) chk.checked = clgot(tr, 'sel');
}
else if (in_tree && !have_sel)
in_tree.click();
@ -6337,7 +6329,7 @@ var thegrid = (function () {
}
else if (r.thumbs) {
ihref = addq(ihref, 'th=' + (
have_jxl ? 'x' :
have_jxl ? 'x' :
have_webp ? 'w' :
'j'
));
@ -6513,8 +6505,7 @@ var thegrid = (function () {
pbar.onresize();
vbar.onresize();
});
bcfg_bind(r, 'gaen', 'gauto', !!dgauto, function(v) {
bcfg_bind(r, 'gaen', 'gauto', !!dgauto, function (v) {
if (r.en && sread("griden") != 1) {
r.en = false;
r.setvis(true);
@ -6687,7 +6678,7 @@ function fselfunw(e, ae, d, rem) {
}
selfun();
}
var konmai = 0, konmak = (function() {
var konmai = 0, konmak = (function () {
var u = "arrowup",
d = "arrowdown",
l = "arrowleft",
@ -6719,7 +6710,7 @@ var ahotkeys = function (e) {
if (konmai < 0)
noop();
else if (konmak[konmai] != kl)
konmai = konmai && kl == konmak[0] ? (konmai<3?konmai:1):0;
konmai = konmai && kl == konmak[0] ? (konmai < 3 ? konmai : 1) : 0;
else if (++konmai >= konmak.length) {
konmai = -1;
document.documentElement.scrollTop = 0;
@ -6727,7 +6718,7 @@ var ahotkeys = function (e) {
start_actx();
sfx_nice();
toast.inf(9, 'omega clearance granted', null, 'top');
setTimeout(function() {
setTimeout(function () {
apply_perms(treectl.lsc);
fileman.render();
}, 573);
@ -7075,7 +7066,6 @@ var search_ui = (function () {
is_txt = id.slice(-1) == 'v',
is_chk = id.slice(-1) == 'c';
console.log(id);
if (is_txt) {
var chk = ebi(id.slice(0, -1) + 'c');
chk.checked = ((v + '').length > 0);
@ -7391,7 +7381,7 @@ function render_m3u() {
dur = 1,
artist = '',
title = '',
ret = {'hits': [], 'tag_order': ['artist', 'title', '.dur'], 'trunc': false};
ret = { 'hits': [], 'tag_order': ['artist', 'title', '.dur'], 'trunc': false };
for (var a = 0; a < lines.length; a++) {
var ln = lines[a].trim();
@ -7427,7 +7417,7 @@ function render_m3u() {
"ts": 946684800 + n,
"sz": 100000 + n,
"rp": url,
"tags": {".dur": dur, "artist": artist, "title": title}
"tags": { ".dur": dur, "artist": artist, "title": title }
});
dur = 1;
artist = title = '';
@ -7619,7 +7609,7 @@ var treectl = (function () {
get_tree("", get_evpath(), true);
r.show();
ebi('treeToggleBtn').classList.add('on');
clmod(ebi('treeToggleBtn'), 'on', true)
}
r.show = function () {
@ -7634,6 +7624,7 @@ var treectl = (function () {
clmod(ebi('wfp'), 'shifted', false);
window.addEventListener('scroll', onscroll);
window.addEventListener('resize', onresize);
// accounts for animation delay
setTimeout(function () {
onresize();
aligngriditems();
@ -7650,7 +7641,7 @@ var treectl = (function () {
if (!nonav)
ebi('path').style.display = '';
ebi('treeToggleBtn').classList.remove('on');
clmod(ebi('treeToggleBtn'), 'on', false)
};
r.toggleTree = function (e, nostore) {
@ -8184,7 +8175,7 @@ var treectl = (function () {
if (lg1 === Ls.eng.f_empty)
lg1 = L.f_empty;
sandbox(ebi('pro'), sb_lg, sba_lg,'', lg0);
sandbox(ebi('pro'), sb_lg, sba_lg, '', lg0);
if (dirchg)
sandbox(ebi('epi'), sb_lg, sba_lg, '', lg1);
@ -9123,10 +9114,10 @@ var settheme = (function () {
chldr = !SPINNER_CSS && SPINNER == tre;
r.ldr = {
'4':['🌴'],
'5':['🌭', 'padding:0 0 .7em .7em;filter:saturate(3)'],
'6':['📞', 'padding:0;filter:brightness(2) sepia(1) saturate(3) hue-rotate(60deg)'],
'7':['▲', 'font-size:3em'], //cp437
'4': ['🌴'],
'5': ['🌭', 'padding:0 0 .7em .7em;filter:saturate(3)'],
'6': ['📞', 'padding:0;filter:brightness(2) sepia(1) saturate(3) hue-rotate(60deg)'],
'7': ['▲', 'font-size:3em'], //cp437
};
// set default theme to flat on firefox mobile to avoid glitchy gradients (2026-04-26)
@ -9151,7 +9142,7 @@ var settheme = (function () {
var html = [],
cb = ebi('themes'),
itheme = ax.indexOf(theme[0]) * 2 + (light ? 1 : 0),
names = ['classic dark', 'classic light', 'flat dark', 'flat light', 'vice', 'hotdog stand', 'hacker', 'hi-con', 'phi95 dark', 'phi95', 'evil blue'];
names = ['classic dark', 'classic light', 'flat dark', 'flat light', 'vice', 'hotdog stand', 'hacker', 'hi-con', 'phi95 dark', 'phi95'];
for (var a = 0; a < themes; a++)
html.push('<option value="{0}">{0} ┃ {1}</option>'.format(a, names[a] || 'custom'));
@ -9296,7 +9287,7 @@ var arcfmt = (function () {
QS('#zip1 span').textContent = fmt.split('_')[0];
ebi('zip1').setAttribute("href",
get_evpath() + (dk ? '?k=' + dk + '&': '?') + arg);
get_evpath() + (dk ? '?k=' + dk + '&' : '?') + arg);
if (!have_zip) {
ebi('zip1').style.display = 'none';
@ -10355,8 +10346,9 @@ ebi('files').onclick = ebi('docul').onclick = function (e) {
if (sz < 1024 * 1024 || showfile.taildoc)
fun();
else
modal.confirm(L.f_bigtxt.format(f2f(sz / 1024 / 1024, 1)), fun, function() {
modal.confirm(L.f_bigtxt2, tfun, null)});
modal.confirm(L.f_bigtxt.format(f2f(sz / 1024 / 1024, 1)), fun, function () {
modal.confirm(L.f_bigtxt2, tfun, null)
});
return ev(e);
}
@ -10373,8 +10365,8 @@ ebi('files').onclick = ebi('docul').onclick = function (e) {
var rcm = (function () {
var r = {};
bcfg_bind(r, 'enabled', 'rcm_en', drcm.charAt(0)=='y');
bcfg_bind(r, 'double', 'rcm_db', drcm.charAt(1)=='y');
bcfg_bind(r, 'enabled', 'rcm_en', drcm.charAt(0) == 'y');
bcfg_bind(r, 'double', 'rcm_db', drcm.charAt(1) == 'y');
var menu = ebi('rcm');
var nsFile = {
@ -10391,7 +10383,7 @@ var rcm = (function () {
var opts = QSA('#rcm a');
for (var i = 0; i < opts.length; i++) {
opts[i].onclick = function(e) {
opts[i].onclick = function (e) {
ev(e);
switch(e.target.id.slice(1)) {
case 'opn':
@ -10404,7 +10396,7 @@ var rcm = (function () {
case 'pla': play('f-' + selFile.id); break;
case 'txt': showfile.show(selFile.name); break;
case 'md': location = selFile.path + (has(selFile.path, '?') ? '&v' : '?v'); break;
case 'cpl': cliptxt(selFile.url, function() {toast.ok(2, L.clipped)}); break;
case 'cpl': cliptxt(selFile.url, function () { toast.ok(2, L.clipped) }); break;
case 'dl': ebi('seldl').click(); break;
case 'zip': ebi('selzip').click(); break;
case 'del': fileman.delete(); break;
@ -10517,7 +10509,7 @@ var rcm = (function () {
menu.focus();
}
r.hide = function(force) {
r.hide = function (force) {
if (!menu.style.display || (!force && menu.contains(document.activeElement)))
return;
if (selFile.elem && !selFile.no_dsel) {
@ -10528,7 +10520,7 @@ var rcm = (function () {
menu.style.display = '';
}
ebi('wrap').oncontextmenu = function(e) {
ebi('wrap').oncontextmenu = function (e) {
if (!r.enabled || e.shiftKey || (r.double && menu.style.display) || /doc=/.exec(location.search)) {
r.hide(true);
return true;
@ -10543,7 +10535,7 @@ var rcm = (function () {
show(e.clientX, e.clientY, gfile || e.target, gfile);
return false;
};
menu.onblur = function() {setTimeout(r.hide)};
menu.onblur = function () { setTimeout(r.hide) };
return r;
})();
@ -10716,7 +10708,7 @@ function reload_browser() {
msel.render();
}
(function() {
(function () {
var is_selma = false;
var dragging = false;
@ -10785,7 +10777,7 @@ function reload_browser() {
ttimer = null;
if (e.type === 'touchstart') {
ttimer = setTimeout(function() {
ttimer = setTimeout(function () {
ttimer = null;
start_drag();
}, lpdelay);
@ -10859,7 +10851,7 @@ function reload_browser() {
window.addEventListener('touchmove', sel_move, { passive: false });
window.addEventListener('touchend', sel_end, { passive: true });
window.addEventListener('dragstart', function(e) {
window.addEventListener('dragstart', function (e) {
if (treectl.dsel && (is_selma || dragging)) {
e.preventDefault();
}
@ -10870,7 +10862,7 @@ function reload_browser() {
})();
var mpss = (function() {
var mpss = (function () {
var r = {}, config, ssint, npaint = 0;
r.load = function () {