Compare commits

...

20 Commits

Author SHA1 Message Date
ed
012bbcf770 v1.0.0 2021-09-07 23:18:54 +02:00
ed
b54cb47b2e listen for filedrops in all tabs/modes 2021-09-07 22:44:48 +02:00
ed
1b15f43745 crashpage: add github-issue link 2021-09-07 22:30:50 +02:00
ed
96771bf1bd linken 2021-09-07 22:12:28 +02:00
ed
580078bddb more readme stuff 2021-09-07 22:10:59 +02:00
ed
c5c7080ec6 more readme fixup 2021-09-07 21:57:33 +02:00
ed
408339b51d mention the new dropzones 2021-09-07 21:49:00 +02:00
ed
02e3d44998 fix move/delete without -e2d (thx exci) 2021-09-07 21:20:34 +02:00
ed
156f13ded1 add 10-minute indicators to seekbar 2021-09-07 21:10:50 +02:00
ed
d288467cb7 separate dropzones for upload/search 2021-09-07 20:52:06 +02:00
ed
21662c9f3f error-message cleanup 2021-09-07 20:51:07 +02:00
ed
9149fe6cdd lightmode fix 2021-09-07 00:44:09 +02:00
ed
9a146192b7 don't unwrap single folders in zip/tar downloads 2021-09-07 00:43:51 +02:00
ed
3a9d3b7b61 rip hls 2021-09-07 00:05:51 +02:00
ed
f03f0973ab Create branch-rename.md 2021-09-06 23:42:42 +02:00
ed
7ec0881e8c Create CODE_OF_CONDUCT.md 2021-09-06 23:31:57 +02:00
ed
59e1ab42ff Create CONTRIBUTING.md 2021-09-06 22:18:41 +02:00
ed
722216b901 Update issue templates 2021-09-06 22:11:06 +02:00
ed
bd8f3dc368 Update issue templates 2021-09-06 22:09:10 +02:00
ed
33cd94a141 update TOC 2021-09-06 08:36:18 +02:00
21 changed files with 388 additions and 77 deletions

40
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,40 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: '9001'
---
NOTE:
all of the below are optional, consider them as inspiration, delete and rewrite at will, thx md
**Describe the bug**
a description of what the bug is
**To Reproduce**
List of steps to reproduce the issue, or, if it's hard to reproduce, then at least a detailed explanation of what you did to run into it
**Expected behavior**
a description of what you expected to happen
**Screenshots**
if applicable, add screenshots to help explain your problem, such as the kickass crashpage :^)
**Server details**
if the issue is possibly on the server-side, then mention some of the following:
* server OS / version:
* python version:
* copyparty arguments:
* filesystem (`lsblk -f` on linux):
**Client details**
if the issue is possibly on the client-side, then mention some of the following:
* the device type and model:
* OS version:
* browser version:
**Additional context**
any other context about the problem here

View File

@@ -0,0 +1,22 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: '9001'
---
all of the below are optional, consider them as inspiration, delete and rewrite at will
**is your feature request related to a problem? Please describe.**
a description of what the problem is, for example, `I'm always frustrated when [...]` or `Why is it not possible to [...]`
**Describe the idea / solution you'd like**
a description of what you want to happen
**Describe any alternatives you've considered**
a description of any alternative solutions or features you've considered
**Additional context**
add any other context or screenshots about the feature request here

View File

@@ -0,0 +1,10 @@
---
name: Something else
about: "┐(゚∀゚)┌"
title: ''
labels: ''
assignees: ''
---

7
.github/branch-rename.md vendored Normal file
View File

@@ -0,0 +1,7 @@
modernize your local checkout of the repo like so,
```sh
git branch -m master hovudstraum
git fetch origin
git branch -u origin/hovudstraum hovudstraum
git remote set-head origin -a
```

24
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,24 @@
in the words of Abraham Lincoln:
> Be excellent to each other... and... PARTY ON, DUDES!
more specifically I'll paraphrase some examples from a german automotive corporation as they cover all the bases without being too wordy
## Examples of unacceptable behavior
* intimidation, harassment, trolling
* insulting, derogatory, harmful or prejudicial comments
* posting private information without permission
* political or personal attacks
## Examples of expected behavior
* being nice, friendly, welcoming, inclusive, mindful and empathetic
* acting considerate, modest, respectful
* using polite and inclusive language
* criticize constructively and accept constructive criticism
* respect different points of view
## finally and even more specifically,
* parse opinions and feedback objectively without prejudice
* it's the message that matters, not who said it
aaand that's how you say `be nice` in a way that fills half a floppy w

3
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,3 @@
* do something cool
really tho, send a PR or an issue or whatever, all appreciated, anything goes, just behave aight

View File

@@ -20,6 +20,7 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* top
* **[quickstart](#quickstart)** - download **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** and you're all set!
* [on servers](#on-servers) - you may also want these, especially on servers
* [on debian](#on-debian) - recommended additional steps on debian
* [notes](#notes) - general notes
* [status](#status) - feature summary
@@ -34,8 +35,8 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* [navpane](#navpane) - switching between breadcrumbs or navpane
* [thumbnails](#thumbnails) - press `g` to toggle grid-view instead of the file listing
* [zip downloads](#zip-downloads) - download folders (or file selections) as `zip` or `tar` files
* [uploading](#uploading) - web-browsers can upload using `bup` and `up2k`
* [file-search](#file-search) - drop files/folders into up2k to see if they exist on the server
* [uploading](#uploading) - drag files/folders into the web-browser to upload
* [file-search](#file-search) - dropping files into the browser also lets you see if they exist on the server
* [unpost](#unpost) - undo/delete accidental uploads
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
@@ -55,6 +56,8 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* [up2k](#up2k) - quick outline of the up2k protocol, see [uploading](#uploading) for the web-client
* [why chunk-hashes](#why-chunk-hashes) - a single sha512 would be better, right?
* [performance](#performance) - defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
* [security](#security) - some notes on hardening
* [gotchas](#gotchas) - behavior that might be unexpected
* [dependencies](#dependencies) - mandatory deps
* [optional dependencies](#optional-dependencies) - install these to enable bonus features
* [install recommended deps](#install-recommended-deps)
@@ -84,8 +87,13 @@ some recommended options:
* see [accounts and volumes](#accounts-and-volumes) for the syntax and other access levels (`r`ead, `w`rite, `m`ove, `d`elete)
* `--ls '**,*,ln,p,r'` to crash on startup if any of the volumes contain a symlink which point outside the volume, as that could give users unintended access
### on servers
you may also want these, especially on servers:
* [contrib/systemd/copyparty.service](contrib/systemd/copyparty.service) to run copyparty as a systemd service
* [contrib/systemd/prisonparty.service](contrib/systemd/prisonparty.service) to run it in a chroot (for extra security)
* [contrib/nginx/copyparty.conf](contrib/nginx/copyparty.conf) to reverse-proxy behind nginx (for better https)
@@ -331,11 +339,13 @@ you can also zip a selection of files or folders by clicking them in the browser
## uploading
web-browsers can upload using `bup` and `up2k`:
drag files/folders into the web-browser to upload
this initiates an upload using `up2k`; there are two uploaders available:
* `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
* `[🚀] up2k`, the fancy one
you can undo/delete uploads using `[🧯]` [unpost](#unpost)
you can also undo/delete uploads by using `[🧯]` [unpost](#unpost)
up2k has several advantages:
* you can drop folders into the browser (files are added recursively)
@@ -359,6 +369,7 @@ the up2k UI is the epitome of polished inutitive experiences:
* `[💭]` ask for confirmation before files are added to the queue
* `[💤]` sync uploading between other copyparty browser-tabs so only one is active
* `[🔎]` switch between upload and [file-search](#file-search) mode
* ignore `[🔎]` if you add files by dragging them into the browser
and then theres the tabs below it,
* `[ok]` is the files which completed successfully
@@ -368,18 +379,22 @@ and then theres the tabs below it,
* plus up to 3 entries each from `[done]` and `[que]` for context
* `[que]` is all the files that are still queued
note that since up2k has to read each file twice, `[🎈 bup]` can be up to 2x faster in some extreme cases (huge files combined with internet connection faster than the read-speed of your HDD)
note that since up2k has to read each file twice, `[🎈 bup]` can *theoretically* be up to 2x faster in some extreme cases (files bigger than your ram, combined with an internet connection faster than the read-speed of your HDD)
if you are resuming a massive upload and want to skip hashing the files which already finished, you can enable `turbo` in the `[⚙️] config` tab, but please read the tooltip on that button
### file-search
drop files/folders into up2k to see if they exist on the server
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)
in the `[🚀 up2k]` tab, after toggling the `[🔎]` switch green, any files/folders you drop onto the dropzone will be hashed on the client-side. Each hash is sent to the server which checks if that file exists somewhere
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
the files will be hashed on the client-side, and each hash is sent to the server, which checks if that file exists somewhere
files go into `[ok]` if they exist (and you get a link to where it is), otherwise they land in `[ng]`
* the main reason filesearch is combined with the uploader is cause the code was too spaghetti to separate it out somewhere else, this is no longer the case but now i've warmed up to the idea too much
@@ -601,7 +616,7 @@ but instead of using `-mte`, `-mth` is a better way to hide tags in the browser:
tags that start with a `.` such as `.bpm` and `.dur`(ation) indicate numeric value
see the beautiful mess of a dictionary in [mtag.py](https://github.com/9001/copyparty/blob/master/copyparty/mtag.py) for the default mappings (should cover mp3,opus,flac,m4a,wav,aif,)
see the beautiful mess of a dictionary in [mtag.py](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/mtag.py) for the default mappings (should cover mp3,opus,flac,m4a,wav,aif,)
`--no-mutagen` disables Mutagen and uses FFprobe instead, which...
* is about 20x slower than Mutagen
@@ -908,7 +923,7 @@ in the `scripts` folder:
roughly sorted by priority
* hls framework for Someone Else to drop code into :^)
* nothing! currently
## discarded ideas
@@ -936,3 +951,5 @@ roughly sorted by priority
* indexedDB for hashes, cfg enable/clear/sz, 2gb avail, ~9k for 1g, ~4k for 100m, 500k items before autoeviction
* blank hashlist when up-ok to skip handshake
* too many confusing side-effects
* hls framework for Someone Else to drop code into :^)
* probably not, too much stuff to consider -- seeking, start at offset, task stitching (probably np-hard), conditional passthru, rate-control (especially multi-consumer), session keepalive, cache mgmt...

View File

@@ -22,7 +22,7 @@ dependencies:
note:
you probably want to run this on windows clients:
https://github.com/9001/copyparty/blob/master/contrib/explorer-nothumbs-nofoldertypes.reg
https://github.com/9001/copyparty/blob/hovudstraum/contrib/explorer-nothumbs-nofoldertypes.reg
get server cert:
awk '/-BEGIN CERTIFICATE-/ {a=1} a; /-END CERTIFICATE-/{exit}' <(openssl s_client -connect 127.0.0.1:3923 </dev/null 2>/dev/null) >cert.pem

View File

@@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (0, 13, 14)
CODENAME = "future-proof"
BUILD_DT = (2021, 9, 6)
VERSION = (1, 0, 0)
CODENAME = "sufficient"
BUILD_DT = (2021, 9, 7)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -434,7 +434,11 @@ class VFS(object):
f2a = os.sep + "dir.txt"
f2b = "{0}.hist{0}".format(os.sep)
g = self.walk("", vrem, [], uname, [[True]], dots, scandir, False)
# if multiselect: add all items to archive root
# if single folder: the folder itself is the top-level item
folder = "" if flt else (vrem.split("/")[-1] or "top")
g = self.walk(folder, vrem, [], uname, [[True]], dots, scandir, False)
for _, _, vpath, apath, files, rd, vd in g:
if flt:
files = [x for x in files if x[0] in flt]

View File

@@ -505,7 +505,7 @@ class HttpCli(object):
if "get" in opt:
return self.handle_get()
raise Pebkac(405, "POST({}) is disabled".format(ctype))
raise Pebkac(405, "POST({}) is disabled in server config".format(ctype))
raise Pebkac(405, "don't know how to handle POST({})".format(ctype))
@@ -1614,7 +1614,7 @@ class HttpCli(object):
raise Pebkac(403, "not allowed for user " + self.uname)
if self.args.no_rescan:
raise Pebkac(403, "disabled by argv")
raise Pebkac(403, "the rescan feature is disabled in server config")
vn, _ = self.asrv.vfs.get(self.vpath, self.uname, True, True)
@@ -1633,7 +1633,7 @@ class HttpCli(object):
raise Pebkac(403, "not allowed for user " + self.uname)
if self.args.no_stack:
raise Pebkac(403, "disabled by argv")
raise Pebkac(403, "the stackdump feature is disabled in server config")
ret = "<pre>{}\n{}".format(time.time(), alltrace())
self.reply(ret.encode("utf-8"))
@@ -1697,7 +1697,7 @@ class HttpCli(object):
def tx_ups(self):
if not self.args.unpost:
raise Pebkac(400, "the unpost feature was disabled by server config")
raise Pebkac(400, "the unpost feature is disabled in server config")
filt = self.uparam.get("filter")
lm = "ups [{}]".format(filt)
@@ -1735,7 +1735,7 @@ class HttpCli(object):
raise Pebkac(403, "not allowed for user " + self.uname)
if self.args.no_del:
raise Pebkac(403, "disabled by argv")
raise Pebkac(403, "the delete feature is disabled in server config")
if not req:
req = [self.vpath]
@@ -1748,7 +1748,7 @@ class HttpCli(object):
raise Pebkac(403, "not allowed for user " + self.uname)
if self.args.no_mv:
raise Pebkac(403, "disabled by argv")
raise Pebkac(403, "the rename/move feature is disabled in server config")
# full path of new loc (incl filename)
dst = self.uparam.get("move")

View File

@@ -1405,7 +1405,7 @@ class Up2k(object):
except:
# unpost with missing permissions? try read+write and verify with db
if not self.args.unpost:
raise Pebkac(400, "the unpost feature was disabled by server config")
raise Pebkac(400, "the unpost feature is disabled in server config")
unpost = True
permsets = [[True, True]]
@@ -1455,11 +1455,13 @@ class Up2k(object):
self.log("rm {}\n {}".format(vpath, abspath))
_ = dbv.get(volpath, uname, *permsets[0])
with self.mutex:
cur = None
try:
ptop = dbv.realpath
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, volpath)
self._forget_file(ptop, volpath, cur, wark, True)
finally:
if cur:
cur.connection.commit()
bos.unlink(abspath)
@@ -1520,13 +1522,13 @@ class Up2k(object):
dabs = dvn.canonical(drem)
drd, dfn = vsplit(drem)
n1 = svp.split('/')[-1]
n2 = dvp.split('/')[-1]
if n1.startswith('.') or n2.startswith('.'):
n1 = svp.split("/")[-1]
n2 = dvp.split("/")[-1]
if n1.startswith(".") or n2.startswith("."):
if self.args.no_dot_mv:
raise Pebkac(400, "moving dotfiles was disabled by server config")
raise Pebkac(400, "moving dotfiles is disabled in server config")
elif self.args.no_dot_ren and n1 != n2:
raise Pebkac(400, "renaming dotfiles was disabled by server config")
raise Pebkac(400, "renaming dotfiles is disabled in server config")
if bos.path.exists(dabs):
raise Pebkac(400, "mv2: target file exists")
@@ -1583,7 +1585,7 @@ class Up2k(object):
def _find_from_vpath(self, ptop, vrem):
cur = self.cur.get(ptop)
if not cur:
return None, None
return [None] * 6
rd, fn = vsplit(vrem)
q = "select w, mt, sz, ip, at from up where rd=? and fn=? limit 1"

View File

@@ -392,13 +392,14 @@ html.light #ggrid>a.sel {
#wzip, #wnp {
margin-right: .2em;
padding-right: .2em;
border-right: .1em solid #555;
border: 1px solid #555;
border-width: 0 .1em 0 0;
}
#wfm.act+#wzip,
#wfm.act+#wzip+#wnp {
margin-left: .2em;
padding-left: .2em;
border-left: .1em solid #555;
border-left-width: .1em;
}
#wfm.act {
display: inline-block;
@@ -1545,6 +1546,86 @@ html.light #bbox-overlay figcaption a {
min-height: 0;
transition: min-height .2s;
}
#drops {
display: none;
z-index: 3;
background: rgba(48, 48, 48, 0.7);
}
#drops.vis,
#drops .dropzone {
display: block;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#drops .dropdesc {
position: fixed;
display: table;
left: 10%;
width: 78%;
height: 30%;
margin: 0;
font-size: 3em;
font-weight: bold;
text-shadow: .05em .05em .1em #000;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 0 0 #999;
border: .5em solid #999;
border-radius: .5em;
border-width: 1vw;
color: #fff;
transition: all 0.2s;
}
#drops .dropdesc.hl.ok {
border-color: #fff;
box-shadow: 0 0 1em #cf5;
background: rgba(24, 24, 24, 0.7);
left: 8%;
width: 82%;
height: 32%;
margin: -1vh 0;
}
#drops .dropdesc.hl.err {
background: rgba(224, 32, 65, 0.2);
box-shadow: 0 0 1em #f26;
border-color: #fab;
}
#drops .dropdesc>div {
display: table-cell;
vertical-align: middle;
text-align: center;
}
#drops .dropzone {
z-index: 80386;
height: 50%;
}
#drops #up_dz {
bottom: 50%;
}
#drops #srch_dz {
top: 50%;
}
#up_zd {
top: 12%;
}
#srch_zd {
bottom: 12%;
}
.dropdesc span {
color: #fff;
background: #490;
border-bottom: .3em solid #6d2;
text-shadow: 1px 1px 1px #000;
border-radius: .3em;
padding: .4em .8em;
font-size: .4em;
}
.dropdesc.err span {
background: #904;
border-color: #d26;
}
#u2form {
position: absolute;
top: 0;

View File

@@ -133,6 +133,20 @@ ebi('op_up2k').innerHTML = (
);
(function () {
var o = mknod('div');
o.innerHTML = (
'<div id="drops">\n' +
' <div class="dropdesc" id="up_zd"><div>🚀 Upload<br /><span></span></div></div>\n' +
' <div class="dropdesc" id="srch_zd"><div>🔎 Search<br /><span></span></div></div>\n' +
' <div class="dropzone" id="up_dz" v="up_zd"></div>\n' +
' <div class="dropzone" id="srch_dz" v="srch_zd"></div>\n' +
'</div>'
);
document.body.appendChild(o);
})();
// config panel
ebi('op_cfg').innerHTML = (
'<div>\n' +
@@ -718,6 +732,10 @@ var pbar = (function () {
for (var p = 1, mins = adur / 60; p <= mins; p++)
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
pctx.fillStyle = light ? 'rgba(0,0,0,1)' : 'rgba(255,255,255,1)';
for (var p = 1, mins = adur / 600; p <= mins; p++)
pctx.fillRect(Math.floor(sm * p * 600), 0, 2, pc.h);
var w = 8,
x = sm * apos;

View File

@@ -633,20 +633,98 @@ function up2k_init(subtle) {
function nav() {
ebi('file' + fdom_ctr).click();
}
ebi('u2btn').addEventListener('click', nav, false);
ebi('u2btn').onclick = nav;
var nenters = 0;
function ondrag(e) {
e.stopPropagation();
e.preventDefault();
if (++nenters <= 0)
nenters = 1;
//console.log(nenters, Date.now(), 'enter', this, e.target);
if (onover.bind(this)(e))
return true;
var mup, up = QS('#up_zd');
var msr, sr = QS('#srch_zd');
if (!has(perms, 'write'))
mup = 'you do not have write-access to this folder';
if (!has(perms, 'read'))
msr = 'you do not have read-access to this folder';
if (!have_up2k_idx)
msr = 'file-search is not enabled in server config';
up.querySelector('span').textContent = mup || 'drop it here';
sr.querySelector('span').textContent = msr || 'drop it here';
clmod(up, 'err', mup);
clmod(sr, 'err', msr);
clmod(up, 'ok', !mup);
clmod(sr, 'ok', !msr);
ebi('up_dz').setAttribute('err', mup || '');
ebi('srch_dz').setAttribute('err', msr || '');
}
function onover(e) {
try {
var ok = false, dt = e.dataTransfer.types;
for (var a = 0; a < dt.length; a++)
if (dt[a] == 'Files')
ok = true;
if (!ok)
return true;
}
catch (ex) { }
ev(e);
e.dataTransfer.dropEffect = 'copy';
e.dataTransfer.effectAllowed = 'copy';
clmod(ebi('drops'), 'vis', 1);
var v = this.getAttribute('v');
if (v)
clmod(ebi(v), 'hl', 1);
}
ebi('u2btn').addEventListener('dragover', ondrag, false);
ebi('u2btn').addEventListener('dragenter', ondrag, false);
function offdrag(e) {
ev(e);
var v = this.getAttribute('v');
if (v)
clmod(ebi(v), 'hl');
if (--nenters <= 0) {
clmod(ebi('drops'), 'vis');
clmod(ebi('up_dz'), 'hl');
clmod(ebi('srch_dz'), 'hl');
}
//console.log(nenters, Date.now(), 'leave', this, e && e.target);
}
document.body.ondragenter = ondrag;
document.body.ondragleave = offdrag;
var drops = [ebi('up_dz'), ebi('srch_dz')];
for (var a = 0; a < 2; a++) {
drops[a].ondragenter = ondrag;
drops[a].ondragover = onover;
drops[a].ondragleave = offdrag;
drops[a].ondrop = gotfile;
}
ebi('drops').onclick = offdrag; // old ff
function gotfile(e) {
e.stopPropagation();
e.preventDefault();
ev(e);
nenters = 0;
offdrag.bind(this)();
var dz = (this && this.getAttribute('id'));
if ((dz == 'up_dz' && fsearch) || (dz == 'srch_dz' && !fsearch)) {
var err = this.getAttribute('err');
if (err)
return modal.alert('sorry, ' + err);
tgl_fsearch();
}
if (!QS('#op_up2k.act'))
goto('up2k');
var files,
is_itemlist = false;
@@ -877,14 +955,13 @@ function up2k_init(subtle) {
pvis.changecard(pvis.act);
}
}
ebi('u2btn').addEventListener('drop', gotfile, false);
function more_one_file() {
fdom_ctr++;
var elm = mknod('div');
elm.innerHTML = '<input id="file{0}" type="file" name="file{0}[]" multiple="multiple" />'.format(fdom_ctr);
ebi('u2form').appendChild(elm);
ebi('file' + fdom_ctr).addEventListener('change', gotfile, false);
ebi('file' + fdom_ctr).onchange = gotfile;
}
more_one_file();
@@ -1905,7 +1982,7 @@ function up2k_init(subtle) {
ebi('u2tdate').onclick = tgl_datechk;
var o = ebi('fsearch');
if (o)
o.addEventListener('click', tgl_fsearch, false);
o.onclick = tgl_fsearch;
ebi('u2etas').onclick = function (e) {
ev(e);

View File

@@ -72,7 +72,7 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
var html = [
'<h1>you hit a bug!</h1>',
'<p style="font-size:1.3em;margin:0">try to <a href="#" onclick="localStorage.clear();location.reload();">reset copyparty settings</a> if you are stuck here, or <a href="#" onclick="ignex();">ignore this</a> / <a href="#" onclick="ignex(true);">ignore all</a></p>',
'<p style="color:#fff">please send me a screenshot arigathanks gozaimuch: <code>ed/irc.rizon.net</code> or <code>ed#2644</code></p>',
'<p style="color:#fff">please send me a screenshot arigathanks gozaimuch: <a href="<ghi>" target="_blank">github issue</a> or <code>ed#2644</code></p>',
'<p class="b">' + esc(url + ' @' + lineNo + ':' + columnNo), '<br />' + esc(String(msg)) + '</p>',
'<p><b>UA:</b> ' + esc(navigator.userAgent + '')
];
@@ -142,7 +142,7 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
);
document.head.appendChild(s);
}
exbox.innerHTML = html.join('\n').replace(/https?:\/\/[^ \/]+\//g, '/').replace(/js\?_=[a-zA-Z]{4}/g, 'js');
exbox.innerHTML = html.join('\n').replace(/https?:\/\/[^ \/]+\//g, '/').replace(/js\?_=[a-zA-Z]{4}/g, 'js').replace(/<ghi>/, 'https://github.com/9001/copyparty/issues/new?labels=bug&template=bug_report.md');
exbox.style.display = 'block';
}
catch (e) {

View File

@@ -1,11 +1,21 @@
# example `.epilogue.html`
**NOTE:** there's more stuff (sharex config, service scripts, nginx configs, ...) in [`/contrib/`](/contrib/)
# example resource files
can be provided to copyparty to tweak things
## example `.epilogue.html`
save one of these as `.epilogue.html` inside a folder to customize it:
* [`minimal-up2k.html`](minimal-up2k.html) will [simplify the upload ui](https://user-images.githubusercontent.com/241032/118311195-dd6ca380-b4ef-11eb-86f3-75a3ff2e1332.png)
# example browser-css
## example browser-css
point `--css-browser` to one of these by URL:
* [`browser.css`](browser.css) changes the background
@@ -19,4 +29,23 @@ point `--css-browser` to one of these by URL:
* notes on using rclone as a fuse client/server
## [`example.conf`](example.conf)
* example config file for `-c` which never really happened
* example config file for `-c` (supports accounts, volumes, and volume-flags)
# junk
alphabetical list of the remaining files
| what | why |
| -- | -- |
| [biquad.html](biquad.html) | bruteforce calibrator for the audio equalizer since im not that good at maths |
| [design.txt](design.txt) | initial brainstorming of the copyparty design, unmaintained, incorrect, sentimental value only |
| [hls.html](hls.html) | experimenting with hls playback using `hls.js`, works p well, almost became a thing |
| [music-analysis.sh](music-analysis.sh) | testing various bpm/key detection libraries before settling on the ones used in [`/bin/mtag/`](/bin/mtag/) |
| [notes.sh](notes.sh) | notepad, just scraps really |
| [nuitka.txt](nuitka.txt) | how to build a copyparty exe using nuitka (not maintained) |
| [pretend-youre-qnap.patch](pretend-youre-qnap.patch) | simulate a NAS which keeps returning old cached data even though you just modified the file yourself |
| [tcp-debug.sh](tcp-debug.sh) | looks like this was to debug stuck tcp connections? |
| [unirange.py](unirange.py) | uhh |
| [up2k.txt](up2k.txt) | initial ideas for how up2k should work, another unmaintained sentimental-value-only thing |

View File

@@ -1,26 +0,0 @@
method = self.s.recv(4)
self.s.unrecv(method)
print("xxx unrecv'd [{}]".format(method))
# jython used to do this, they stopped since it's broken
# but reimplementing sendall is out of scope for now
if not getattr(self.s.s, "sendall", None):
self.s.s.sendall = self.s.s.send
# TODO this is also pretty bad
have = dir(self.s)
for k in self.s.s.__dict__:
if k not in have and not k.startswith("__"):
if k == "recv":
raise Exception("wait what")
self.s.__dict__[k] = self.s.s.__dict__[k]
have = dir(self.s)
for k in dir(self.s.s):
if k not in have and not k.startswith("__"):
if k == "recv":
raise Exception("wait what")
setattr(self.s, k, getattr(self.s.s, k))

View File

@@ -67,6 +67,7 @@ pybin=$(command -v python3 || command -v python) || {
use_gz=
do_sh=1
do_py=1
zopf=2560
while [ ! -z "$1" ]; do
case $1 in
clean) clean=1 ; ;;
@@ -78,6 +79,7 @@ while [ ! -z "$1" ]; do
no-cm) no_cm=1 ; ;;
no-sh) do_sh= ; ;;
no-py) do_py= ; ;;
fast) zopf=100 ; ;;
*) help ; ;;
esac
shift
@@ -136,7 +138,7 @@ tmpdir="$(
# msys2 tar is bad, make the best of it
echo collecting source
[ $clean ] && {
(cd .. && git archive master >tar) && tar -xf ../tar copyparty
(cd .. && git archive hovudstraum >tar) && tar -xf ../tar copyparty
(cd .. && tar -cf tar copyparty/web/deps) && tar -xf ../tar
}
[ $clean ] || {
@@ -271,7 +273,7 @@ done
gzres() {
command -v pigz &&
pk='pigz -11 -I 2560' ||
pk="pigz -11 -I $zopf" ||
pk='gzip'
np=$(nproc)

View File

@@ -61,7 +61,7 @@ rls_dir="$tmp/copyparty-$ver"
mkdir "$rls_dir"
echo ">>> export from git"
git archive master | tar -xC "$rls_dir"
git archive hovudstraum | tar -xC "$rls_dir"
echo ">>> export untracked deps"
tar -c copyparty/web/deps | tar -xC "$rls_dir"
@@ -122,5 +122,5 @@ echo " $zip_path"
echo " $tgz_path"
echo
# function alr() { ls -alR copyparty-$1 | sed -r "s/copyparty-$1/copyparty/" | sed -r 's/[A-Z][a-z]{2} [0-9 ]{2} [0-9]{2}:[0-9]{2}//' > $1; }; for x in master rls src ; do alr $x; done
# function alr() { ls -alR copyparty-$1 | sed -r "s/copyparty-$1/copyparty/" | sed -r 's/[A-Z][a-z]{2} [0-9 ]{2} [0-9]{2}:[0-9]{2}//' > $1; }; for x in hovudstraum rls src ; do alr $x; done

View File

@@ -61,7 +61,7 @@ class clean2(Command):
pass
nuke = []
for (dirpath, dirnames, filenames) in os.walk("."):
for (dirpath, _, filenames) in os.walk("."):
for fn in filenames:
if (
fn.startswith("MANIFEST")
@@ -86,7 +86,7 @@ args = {
"url": "https://github.com/9001/copyparty",
"license": "MIT",
"classifiers": [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
@@ -101,6 +101,7 @@ args = {
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: Jython",
"Programming Language :: Python :: Implementation :: PyPy",
"Environment :: Console",
"Environment :: No Input/Output (Daemon)",