mirror of
https://github.com/9001/copyparty.git
synced 2025-11-24 07:23:22 -07:00
Compare commits
44 commits
v1.19.17
...
hovudstrau
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb9f0441c9 | ||
|
|
a359b89edd | ||
|
|
77f74ddb2f | ||
|
|
f7e7b03f6f | ||
|
|
7a291403ca | ||
|
|
b427d7802a | ||
|
|
c424a55d6f | ||
|
|
7d62335c13 | ||
|
|
9385daeae8 | ||
|
|
79e1078671 | ||
|
|
cad15fbf60 | ||
|
|
9f08efcabd | ||
|
|
ac085b8149 | ||
|
|
1c15c0d5d1 | ||
|
|
904c984bda | ||
|
|
3242145e52 | ||
|
|
dff6aa2435 | ||
|
|
450cd86dc1 | ||
|
|
db60951d9f | ||
|
|
c00314a292 | ||
|
|
2cc53ea151 | ||
|
|
e9ab040ce8 | ||
|
|
e005930cd0 | ||
|
|
4fcd2c4193 | ||
|
|
cec44aa1dd | ||
|
|
e3524d85bd | ||
|
|
1963ed1795 | ||
|
|
f0297777eb | ||
|
|
36ab77e0bf | ||
|
|
db87ea5ce1 | ||
|
|
b1efc0065c | ||
|
|
a325353b1b | ||
|
|
1c17b63b76 | ||
|
|
d3dd34569a | ||
|
|
cdd5e78adf | ||
|
|
fff7291dcf | ||
|
|
7f5810f1a7 | ||
|
|
b624a38747 | ||
|
|
c9e45c12d8 | ||
|
|
5c42ad1c78 | ||
|
|
547a7ab1cc | ||
|
|
a04570ff5e | ||
|
|
93eb862c60 | ||
|
|
81881a449b |
26
README.md
26
README.md
|
|
@ -21,6 +21,7 @@ made in Norway 🇳🇴
|
|||
|
||||
* top
|
||||
* [quickstart](#quickstart) - just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉
|
||||
* [mirrors](#mirrors) - other places to download copyparty from
|
||||
* [at home](#at-home) - make it accessible over the internet
|
||||
* [on servers](#on-servers) - you may also want these, especially on servers
|
||||
* [features](#features) - also see [comparison to similar software](./docs/versus.md)
|
||||
|
|
@ -157,7 +158,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
|
|||
|
||||
* or install through [pypi](https://pypi.org/project/copyparty/): `python3 -m pip install --user -U copyparty`
|
||||
* or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
|
||||
* or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
|
||||
* or install [on arch](#arch-package) / [homebrew](#homebrew-formulae) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
|
||||
* or if you are on android, [install copyparty in termux](#install-on-android)
|
||||
* or maybe an iPhone or iPad? [install in a-Shell on iOS](#install-on-iOS)
|
||||
* or maybe you have a [synology nas / dsm](./docs/synology-dsm.md)
|
||||
|
|
@ -195,6 +196,18 @@ some recommended options:
|
|||
* see [accounts and volumes](#accounts-and-volumes) (or `--help-accounts`) for the syntax and other permissions
|
||||
|
||||
|
||||
### mirrors
|
||||
|
||||
other places to download copyparty from (non-github links):
|
||||
|
||||
* https://copyparty.eu/ (hetzner, finland, official mirror):
|
||||
* https://copyparty.eu/py = https://copyparty.eu/copyparty-sfx.py = the sfx
|
||||
* https://copyparty.eu/en = https://copyparty.eu/copyparty-en.py = the english-only sfx
|
||||
* https://copyparty.eu/pyz = https://copyparty.eu/copyparty.pyz = the zipapp
|
||||
* https://copyparty.eu/enz = https://copyparty.eu/copyparty-en.pyz = the enterprise pyz
|
||||
* https://copyparty.eu/cli = online cli helptext
|
||||
|
||||
|
||||
### at home
|
||||
|
||||
make it accessible over the internet by starting a [cloudflare quicktunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) like so:
|
||||
|
|
@ -309,7 +322,7 @@ small collection of user feedback
|
|||
|
||||
project goals / philosophy
|
||||
|
||||
* inverse linux philosophy -- do all the things, and do an *okay* job
|
||||
* inverse unix philosophy -- do all the things, and do an *okay* job
|
||||
* quick drop-in service to get a lot of features in a pinch
|
||||
* some of [the alternatives](./docs/versus.md) might be a better fit for you
|
||||
* run anywhere, support everything
|
||||
|
|
@ -621,7 +634,7 @@ the main tabs in the ui
|
|||
* `[🧯]` [unpost](#unpost): undo/delete accidental uploads
|
||||
* `[🚀]` and `[🎈]` are the [uploaders](#uploading)
|
||||
* `[📂]` mkdir: create directories
|
||||
* `[📝]` new-md: create a new markdown document
|
||||
* `[📝]` 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
|
||||
|
|
@ -2969,7 +2982,9 @@ enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
|
|||
|
||||
enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
|
||||
|
||||
`pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
|
||||
`pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram
|
||||
* to install `pyvips` on Linux: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
|
||||
* to install `pyvips` on windows: `pip install --user -U "pyvips[binary]"`
|
||||
|
||||
to install FFmpeg on Windows, grab [a recent build](https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z) -- you need `ffmpeg.exe` and `ffprobe.exe` from inside the `bin` folder; copy them into `C:\Windows\System32` or any other folder that's in your `%PATH%`
|
||||
|
||||
|
|
@ -3066,7 +3081,8 @@ another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty
|
|||
run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails
|
||||
|
||||
it is a python [zipapp](https://docs.python.org/3/library/zipapp.html) meaning it doesn't have to unpack its own python code anywhere to run, so if the filesystem is busted it has a better chance of getting somewhere
|
||||
* but note that it currently still needs to extract the web-resources somewhere (they'll land in the default TEMP-folder of your OS)
|
||||
|
||||
> there is also [copyparty-en.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty-en.pyz), english-only and without smb support (enterprise-friendly)
|
||||
|
||||
|
||||
# install on android
|
||||
|
|
|
|||
|
|
@ -68,3 +68,8 @@ instead of affecting all volumes, you can set the options for just one volume li
|
|||
* `:c,mtp=key=f,audio-key.py`
|
||||
* `:c,mtp=.bpm=f,audio-bpm.py`
|
||||
* `:c,mtp=ahash,vhash=f,media-hash.py`
|
||||
|
||||
|
||||
# tips & tricks
|
||||
|
||||
* to delete tags for all files below `blog*` and rescan that, `sqlite3 .hist/up2k.db "delete from mt where w in (select substr(w,1,16) from up where rd like 'blog%')";`
|
||||
|
|
|
|||
53
bin/mtag/geotag.py
Executable file
53
bin/mtag/geotag.py
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
from copyparty.util import fsenc, runcmd
|
||||
|
||||
|
||||
"""
|
||||
uses exiftool to geotag images based on embedded gps coordinates in exif data
|
||||
|
||||
adds four new metadata keys:
|
||||
.gps_lat = latitute
|
||||
.gps_lon = longitude
|
||||
.masl = meters above sea level
|
||||
city = "city, subregion, region"
|
||||
|
||||
usage: -mtp .masl,.gps_lat,.gps_lon,city=ad,t10,bin/mtag/geotag.py
|
||||
|
||||
example: https://a.ocv.me/pub/blog/j7/8/?grid=0
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
cmd = b"exiftool -api geolocation -n".split(b" ")
|
||||
rc, so, se = runcmd(cmd + [fsenc(sys.argv[1])])
|
||||
ptn = re.compile("([^:]*[^ :]) *: (.*)")
|
||||
city = ["", "", ""]
|
||||
ret = {}
|
||||
for ln in so.split("\n"):
|
||||
m = ptn.match(ln)
|
||||
if not m:
|
||||
continue
|
||||
k, v = m.groups()
|
||||
if k == "Geolocation City":
|
||||
city[2] = v
|
||||
elif k == "Geolocation Subregion":
|
||||
city[1] = v
|
||||
elif k == "Geolocation Region":
|
||||
city[0] = v
|
||||
elif k == "GPS Latitude":
|
||||
ret[".gps_lat"] = "%.04f" % (float(v),)
|
||||
elif k == "GPS Longitude":
|
||||
ret[".gps_lon"] = "%.04f" % (float(v),)
|
||||
elif k == "GPS Altitude":
|
||||
ret[".masl"] = str(int(float(v)))
|
||||
v = ", ".join(city).strip(", ")
|
||||
if v:
|
||||
ret["city"] = v
|
||||
print(json.dumps(ret))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
16
bin/u2c.py
16
bin/u2c.py
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
S_VERSION = "2.13"
|
||||
S_BUILD_DT = "2025-09-05"
|
||||
S_VERSION = "2.15"
|
||||
S_BUILD_DT = "2025-10-25"
|
||||
|
||||
"""
|
||||
u2c.py: upload to copyparty
|
||||
|
|
@ -232,6 +232,7 @@ class HCli(object):
|
|||
|
||||
MJ = "application/json"
|
||||
MO = "application/octet-stream"
|
||||
MM = "application/x-www-form-urlencoded"
|
||||
CLEN = "Content-Length"
|
||||
|
||||
web = None # type: HCli
|
||||
|
|
@ -979,6 +980,7 @@ class Ctl(object):
|
|||
self.nfiles, self.nbytes = self.stats
|
||||
self.filegen = walkdirs([], ar.files, ar.x)
|
||||
self.recheck = [] # type: list[File]
|
||||
self.last_file = None
|
||||
|
||||
if ar.safe:
|
||||
self._safe()
|
||||
|
|
@ -1015,6 +1017,11 @@ class Ctl(object):
|
|||
|
||||
self._fancy()
|
||||
|
||||
file = self.last_file
|
||||
if self.up_br and file:
|
||||
zs = quotep(file.name.encode("utf-8", WTF8))
|
||||
web.req("POST", file.url, {}, b"msg=upload-queue-empty;" + zs, MM)
|
||||
|
||||
self.ok = not self.errs
|
||||
|
||||
def _safe(self):
|
||||
|
|
@ -1225,9 +1232,7 @@ class Ctl(object):
|
|||
while req:
|
||||
print("DELETING ~%s#%s" % (srd, len(req)))
|
||||
body = json.dumps(req).encode("utf-8")
|
||||
sc, txt = web.req(
|
||||
"POST", self.ar.url + "?delete", {}, body, MJ
|
||||
)
|
||||
sc, txt = web.req("POST", "/?delete", {}, body, MJ)
|
||||
if sc == 413 and "json 2big" in txt:
|
||||
print(" (delete request too big; slicing...)")
|
||||
req = req[: len(req) // 2]
|
||||
|
|
@ -1455,6 +1460,7 @@ class Ctl(object):
|
|||
|
||||
file = fsl.file
|
||||
cids = fsl.cids
|
||||
self.last_file = file
|
||||
|
||||
with self.mutex:
|
||||
if not self.uploader_busy:
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ let
|
|||
|
||||
accountsWithPlaceholders = mapAttrs (name: attrs: passwordPlaceholder name);
|
||||
|
||||
volumesWithoutVariables = filterAttrs (k: v: !(hasInfix "\${" v.path)) cfg.volumes;
|
||||
|
||||
configStr = ''
|
||||
${mkSection "global" cfg.settings}
|
||||
${cfg.globalExtraConfig}
|
||||
|
|
@ -325,7 +327,7 @@ in
|
|||
BindPaths =
|
||||
(if cfg.settings ? hist then [ cfg.settings.hist ] else [ ])
|
||||
++ [ externalStateDir ]
|
||||
++ (mapAttrsToList (k: v: v.path) cfg.volumes);
|
||||
++ (mapAttrsToList (k: v: v.path) volumesWithoutVariables);
|
||||
# ProtectSystem = "strict";
|
||||
# Note that unlike what 'ro' implies,
|
||||
# this actually makes it impossible to read anything in the root FS,
|
||||
|
|
@ -364,10 +366,20 @@ in
|
|||
#: in front of things means it wont change it if the directory already exists.
|
||||
group = ":${cfg.group}";
|
||||
user = ":${cfg.user}";
|
||||
mode = ":755";
|
||||
mode = ":${
|
||||
# Use volume permissions if set
|
||||
if (value.flags ? chmod_d) then
|
||||
value.flags.chmod_d
|
||||
# Else, use global permission if set
|
||||
else if (cfg.settings ? chmod-d) then
|
||||
cfg.settings.chmod-d
|
||||
# Else, use the default permission
|
||||
else
|
||||
"755"
|
||||
}";
|
||||
};
|
||||
}
|
||||
) cfg.volumes
|
||||
) volumesWithoutVariables
|
||||
);
|
||||
|
||||
users.groups = lib.mkIf (cfg.group == "copyparty") {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead.
|
||||
|
||||
pkgname=copyparty
|
||||
pkgver="1.19.16"
|
||||
pkgver="1.19.20"
|
||||
pkgrel=1
|
||||
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
||||
arch=("any")
|
||||
|
|
@ -23,7 +23,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}/copyparty.conf" )
|
||||
sha256sums=("d8cc10d3623eaccc8acaebdd3b0102a1ebf878a03ffe6e737d132c66f799d682")
|
||||
sha256sums=("050ccc34554e59210aca7a67d87a186e69b3f4dbe013d5ee2f11a22c259a82a6")
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
pkgname=copyparty
|
||||
pkgver=1.19.16
|
||||
pkgver=1.19.20
|
||||
pkgrel=1
|
||||
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
||||
arch=("any")
|
||||
|
|
@ -20,7 +20,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=("d8cc10d3623eaccc8acaebdd3b0102a1ebf878a03ffe6e737d132c66f799d682")
|
||||
sha256sums=("050ccc34554e59210aca7a67d87a186e69b3f4dbe013d5ee2f11a22c259a82a6")
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"url": "https://github.com/9001/copyparty/releases/download/v1.19.16/copyparty-1.19.16.tar.gz",
|
||||
"version": "1.19.16",
|
||||
"hash": "sha256-2MwQ02I+rMyKyuvdOwECoev4eKA//m5zfRMsZveZ1oI="
|
||||
"url": "https://github.com/9001/copyparty/releases/download/v1.19.20/copyparty-1.19.20.tar.gz",
|
||||
"version": "1.19.20",
|
||||
"hash": "sha256-BQzMNFVOWSEKynpn2HoYbmmz9NvgE9XuLxGiLCWagqY="
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ except:
|
|||
zs = """
|
||||
web/a/partyfuse.py
|
||||
web/a/u2c.py
|
||||
web/a/webdav-cfg.bat
|
||||
web/a/webdav-cfg.txt
|
||||
web/baguettebox.js
|
||||
web/browser.css
|
||||
web/browser.html
|
||||
|
|
@ -125,6 +125,11 @@ web/util.js
|
|||
web/w.hash.js
|
||||
"""
|
||||
RES = set(zs.strip().split("\n"))
|
||||
RESM = {
|
||||
"web/a/partyfuse.txt": "web/a/partyfuse.py",
|
||||
"web/a/u2c.txt": "web/a/u2c.py",
|
||||
"web/a/webdav-cfg.bat": "web/a/webdav-cfg.txt",
|
||||
}
|
||||
|
||||
|
||||
class EnvParams(object):
|
||||
|
|
|
|||
|
|
@ -1160,7 +1160,6 @@ def add_general(ap, nc, srvname):
|
|||
ap2 = ap.add_argument_group("general options")
|
||||
ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="\033[34mREPEATABLE:\033[0m add config file")
|
||||
ap2.add_argument("-nc", metavar="NUM", type=int, default=nc, help="max num clients")
|
||||
ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores, 0=all")
|
||||
ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]")
|
||||
ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
|
||||
ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
|
||||
|
|
@ -1175,6 +1174,7 @@ def add_general(ap, nc, srvname):
|
|||
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="\033[34mREPEATABLE:\033[0m map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
||||
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
||||
ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)")
|
||||
ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="num cpu-cores for uploads/downloads (0=all); keeping the default is almost always best")
|
||||
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
||||
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
||||
ap2.add_argument("--versionb", action="store_true", help="show version and exit")
|
||||
|
|
@ -1491,6 +1491,7 @@ def add_hooks(ap):
|
|||
def add_stats(ap):
|
||||
ap2 = ap.add_argument_group("grafana/prometheus metrics endpoint")
|
||||
ap2.add_argument("--stats", action="store_true", help="enable openmetrics at /.cpr/metrics for admin accounts")
|
||||
ap2.add_argument("--stats-u", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to access /.cpr/metrics even if they aren't admin")
|
||||
ap2.add_argument("--nos-hdd", action="store_true", help="disable disk-space metrics (used/free space)")
|
||||
ap2.add_argument("--nos-vol", action="store_true", help="disable volume size metrics (num files, total bytes, vmaxb/vmaxn)")
|
||||
ap2.add_argument("--nos-vst", action="store_true", help="disable volume state metrics (indexing, analyzing, activity)")
|
||||
|
|
@ -1796,6 +1797,7 @@ def add_ui(ap, retry: int):
|
|||
ap2.add_argument("--ufavico", metavar="TXT", type=u, default="", help="URL to .ico/png/gif/svg file; \033[33m--favico\033[0m takes precedence unless disabled (volflag=ufavico)")
|
||||
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="\033[34mREPEATABLE:\033[0m use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
|
||||
ap2.add_argument("--mpmc", type=u, default="", help=argparse.SUPPRESS)
|
||||
ap2.add_argument("--notooltips", action="store_true", help="tooltips disabled as default")
|
||||
ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]")
|
||||
ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html")
|
||||
ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# coding: utf-8
|
||||
|
||||
VERSION = (1, 19, 17)
|
||||
VERSION = (1, 19, 20)
|
||||
CODENAME = "usernames"
|
||||
BUILD_DT = (2025, 10, 17)
|
||||
BUILD_DT = (2025, 11, 2)
|
||||
|
||||
S_VERSION = ".".join(map(str, VERSION))
|
||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||
|
|
|
|||
|
|
@ -398,6 +398,9 @@ class VFS(object):
|
|||
self.vpath = vpath # absolute path in the virtual filesystem
|
||||
self.vpath0 = vpath0 # original vpath (before idp expansion)
|
||||
self.axs = axs
|
||||
self.uaxs: dict[
|
||||
str, tuple[bool, bool, bool, bool, bool, bool, bool, bool, bool]
|
||||
] = {}
|
||||
self.flags = flags # config options
|
||||
self.root = self
|
||||
self.dev = 0 # st_dev
|
||||
|
|
@ -555,29 +558,19 @@ class VFS(object):
|
|||
|
||||
def can_access(
|
||||
self, vpath: str, uname: str
|
||||
) -> tuple[bool, bool, bool, bool, bool, bool, bool, bool]:
|
||||
"""can Read,Write,Move,Delete,Get,Upget,Admin,Dot"""
|
||||
) -> tuple[bool, bool, bool, bool, bool, bool, bool, bool, bool]:
|
||||
"""can Read,Write,Move,Delete,Get,Upget,Html,Admin,Dot"""
|
||||
# NOTE: only used by get_perms, which is only used by hooks; the lowest of fruits
|
||||
if vpath:
|
||||
vn, _ = self._find(undot(vpath))
|
||||
else:
|
||||
vn = self
|
||||
|
||||
c = vn.axs
|
||||
return (
|
||||
uname in c.uread,
|
||||
uname in c.uwrite,
|
||||
uname in c.umove,
|
||||
uname in c.udel,
|
||||
uname in c.uget,
|
||||
uname in c.upget,
|
||||
uname in c.uadmin,
|
||||
uname in c.udot,
|
||||
)
|
||||
# skip uhtml because it's rarely needed
|
||||
return vn.uaxs[uname]
|
||||
|
||||
def get_perms(self, vpath: str, uname: str) -> str:
|
||||
zbl = self.can_access(vpath, uname)
|
||||
ret = "".join(ch for ch, ok in zip("rwmdgGa.", zbl) if ok)
|
||||
ret = "".join(ch for ch, ok in zip("rwmdgGha.", zbl) if ok)
|
||||
if "rwmd" in ret and "a." in ret:
|
||||
ret += "A"
|
||||
return ret
|
||||
|
|
@ -772,19 +765,16 @@ class VFS(object):
|
|||
virt_vis[name] = vn2
|
||||
continue
|
||||
|
||||
ok = False
|
||||
zx = vn2.axs
|
||||
axs = [zx.uread, zx.uwrite, zx.umove, zx.udel, zx.uget]
|
||||
u_has = vn2.uaxs.get(uname) or [False] * 9
|
||||
for pset in permsets:
|
||||
ok = True
|
||||
for req, lst in zip(pset, axs):
|
||||
if req and uname not in lst:
|
||||
for req, zb in zip(pset, u_has):
|
||||
if req and not zb:
|
||||
ok = False
|
||||
if ok:
|
||||
break
|
||||
|
||||
if ok:
|
||||
virt_vis[name] = vn2
|
||||
break
|
||||
|
||||
if ".hist" in abspath:
|
||||
p = abspath.replace("\\", "/") if WINDOWS else abspath
|
||||
|
|
@ -1822,6 +1812,15 @@ class AuthSrv(object):
|
|||
derive_args(self.args)
|
||||
self.setup_auth_ord()
|
||||
|
||||
if self.args.ipu:
|
||||
# syntax (CIDR=UNAME) is verified in load_ipu
|
||||
zsl = [x.split("=", 1)[1] for x in self.args.ipu]
|
||||
zsl = [x for x in zsl if x not in acct]
|
||||
if zsl:
|
||||
t = "ERROR: unknown users in ipu: %s" % (zsl,)
|
||||
self.log(t, 1)
|
||||
raise Exception(t)
|
||||
|
||||
self.setup_pwhash(acct)
|
||||
defpw = acct.copy()
|
||||
self.setup_chpw(acct)
|
||||
|
|
@ -1995,6 +1994,23 @@ class AuthSrv(object):
|
|||
umap[usr].sort()
|
||||
setattr(vfs, "a" + perm, umap)
|
||||
|
||||
for vol in vfs.all_nodes.values():
|
||||
za = vol.axs
|
||||
vol.uaxs = {
|
||||
un: (
|
||||
un in za.uread,
|
||||
un in za.uwrite,
|
||||
un in za.umove,
|
||||
un in za.udel,
|
||||
un in za.uget,
|
||||
un in za.upget,
|
||||
un in za.uhtml,
|
||||
un in za.uadmin,
|
||||
un in za.udot,
|
||||
)
|
||||
for un in unames
|
||||
}
|
||||
|
||||
all_users = {}
|
||||
missing_users = {}
|
||||
associated_users = {}
|
||||
|
|
@ -2328,6 +2344,10 @@ class AuthSrv(object):
|
|||
free_umask = False
|
||||
have_reflink = False
|
||||
for vol in vfs.all_nodes.values():
|
||||
if os.path.isfile(vol.realpath):
|
||||
vol.flags["is_file"] = True
|
||||
vol.flags["d2d"] = True
|
||||
|
||||
if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
|
||||
vol.flags["e2ds"] = True
|
||||
|
||||
|
|
@ -2642,7 +2662,14 @@ class AuthSrv(object):
|
|||
errors = True
|
||||
|
||||
for vol in vfs.all_nodes.values():
|
||||
if not vol.realpath or os.path.isfile(vol.realpath):
|
||||
if not vol.flags.get("is_file"):
|
||||
continue
|
||||
zs = "og opds xlink"
|
||||
for zs in zs.split():
|
||||
vol.flags.pop(zs, None)
|
||||
|
||||
for vol in vfs.all_nodes.values():
|
||||
if not vol.realpath or vol.flags.get("is_file"):
|
||||
continue
|
||||
ccs = vol.flags["casechk"][:1].lower()
|
||||
if ccs in ("y", "n"):
|
||||
|
|
@ -3033,6 +3060,7 @@ class AuthSrv(object):
|
|||
"lifetime": vf.get("lifetime") or 0,
|
||||
"unlist": vf.get("unlist") or "",
|
||||
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
|
||||
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
||||
}
|
||||
if "ufavico_h" in vf:
|
||||
vn.js_ls["ufavico"] = vf["ufavico_h"]
|
||||
|
|
@ -3054,7 +3082,8 @@ class AuthSrv(object):
|
|||
"have_emp": int(self.args.emp),
|
||||
"md_no_br": int(vf.get("md_no_br") or 0),
|
||||
"ext_th": vf.get("ext_th_d") or {},
|
||||
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
||||
"sb_lg": vn.js_ls["sb_lg"],
|
||||
"sb_md": vn.js_ls["sb_md"],
|
||||
"sba_md": vf.get("md_sba") or "",
|
||||
"sba_lg": vf.get("lg_sba") or "",
|
||||
"txt_ext": self.args.textfiles.replace(",", " "),
|
||||
|
|
@ -3088,6 +3117,10 @@ class AuthSrv(object):
|
|||
for zs in zs.split():
|
||||
if vf.get(zs):
|
||||
js_htm[zs] = 1
|
||||
zs = "notooltips"
|
||||
for zs in zs.split():
|
||||
if getattr(self.args, zs, False):
|
||||
js_htm[zs] = 1
|
||||
vn.js_htm = json_hesc(json.dumps(js_htm))
|
||||
|
||||
vols = list(vfs.all_nodes.values())
|
||||
|
|
@ -3436,7 +3469,7 @@ class AuthSrv(object):
|
|||
raise Exception("volume not found: " + zs)
|
||||
|
||||
self.log(str({"users": users, "vols": vols, "flags": flags}))
|
||||
t = "/{}: read({}) write({}) move({}) del({}) dots({}) get({}) upGet({}) uadmin({})"
|
||||
t = "/{}: read({}) write({}) move({}) del({}) dots({}) get({}) upGet({}) html({}) uadmin({})"
|
||||
for k, zv in self.vfs.all_vols.items():
|
||||
vc = zv.axs
|
||||
vs = [
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ class FtpFs(AbstractedFS):
|
|||
if not avfs:
|
||||
raise FSE(t.format(vpath), 1)
|
||||
|
||||
cr, cw, cm, cd, _, _, _, _ = avfs.can_access("", self.h.uname)
|
||||
cr, cw, cm, cd, _, _, _, _, _ = avfs.uaxs[self.h.uname]
|
||||
if r and not cr or w and not cw or m and not cm or d and not cd:
|
||||
raise FSE(t.format(vpath), 1)
|
||||
|
||||
|
|
@ -250,6 +250,7 @@ class FtpFs(AbstractedFS):
|
|||
td = 0
|
||||
|
||||
if w and need_unlink:
|
||||
assert td # type: ignore # !rm
|
||||
if td >= -1 and td <= self.args.ftp_wt:
|
||||
# within permitted timeframe; allow overwrite or resume
|
||||
do_it = True
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ try:
|
|||
except:
|
||||
pass
|
||||
|
||||
from .__init__ import ANYWIN, RES, TYPE_CHECKING, EnvParams, unicode
|
||||
from .__init__ import ANYWIN, RES, RESM, TYPE_CHECKING, EnvParams, unicode
|
||||
from .__version__ import S_VERSION
|
||||
from .authsrv import LEELOO_DALLAS, VFS # typechk
|
||||
from .bos import bos
|
||||
|
|
@ -124,7 +124,17 @@ from .util import (
|
|||
|
||||
if True: # pylint: disable=using-constant-test
|
||||
import typing
|
||||
from typing import Any, Generator, Iterable, Match, Optional, Pattern, Type, Union
|
||||
from typing import (
|
||||
Any,
|
||||
Generator,
|
||||
Iterable,
|
||||
Match,
|
||||
Optional,
|
||||
Pattern,
|
||||
Sequence,
|
||||
Type,
|
||||
Union,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .httpconn import HttpConn
|
||||
|
|
@ -165,6 +175,24 @@ RE_MDV = re.compile(r"(.*)\.([0-9]+\.[0-9]{3})(\.[Mm][Dd])$")
|
|||
|
||||
UPARAM_CC_OK = set("doc move tree".split())
|
||||
|
||||
PERMS_rwh = [
|
||||
[True, False],
|
||||
[False, True],
|
||||
[False, False, False, False, False, False, True],
|
||||
]
|
||||
|
||||
|
||||
def _build_zip_xcode() -> Sequence[str]:
|
||||
ret = "opus mp3 flac wav p".split()
|
||||
for codec in ("w", "j"):
|
||||
for suf in ("", "f", "f3", "3"):
|
||||
ret.append("%s%s" % (codec, suf))
|
||||
return ret
|
||||
|
||||
|
||||
ZIP_XCODE_L = _build_zip_xcode()
|
||||
ZIP_XCODE_S = set(ZIP_XCODE_L)
|
||||
|
||||
|
||||
class HttpCli(object):
|
||||
"""
|
||||
|
|
@ -229,6 +257,7 @@ class HttpCli(object):
|
|||
self.can_delete = False
|
||||
self.can_get = False
|
||||
self.can_upget = False
|
||||
self.can_html = False
|
||||
self.can_admin = False
|
||||
self.can_dot = False
|
||||
self.out_headerlist: list[tuple[str, str]] = []
|
||||
|
|
@ -737,6 +766,7 @@ class HttpCli(object):
|
|||
if "bcasechk" in vn.flags and not vn.casechk(rem, True):
|
||||
return self.tx_404() and False
|
||||
|
||||
try:
|
||||
(
|
||||
self.can_read,
|
||||
self.can_write,
|
||||
|
|
@ -744,11 +774,13 @@ class HttpCli(object):
|
|||
self.can_delete,
|
||||
self.can_get,
|
||||
self.can_upget,
|
||||
self.can_html,
|
||||
self.can_admin,
|
||||
self.can_dot,
|
||||
) = (
|
||||
avn.can_access("", self.uname) if avn else [False] * 8
|
||||
)
|
||||
) = avn.uaxs[self.uname]
|
||||
except:
|
||||
pass # default is all-false
|
||||
|
||||
self.avn = avn
|
||||
self.vn = vn # note: do not dbv due to walk/zipgen
|
||||
self.rem = rem
|
||||
|
|
@ -775,7 +807,7 @@ class HttpCli(object):
|
|||
guess = "modifying" if (origin and host) else "stripping"
|
||||
t = "cors-reject %s because request-header Origin=%r does not match request-protocol %r and host %r based on request-header Host=%r (note: if this request is not malicious, check if your reverse-proxy is accidentally %s request headers, in particular 'Origin', for example by running copyparty with --ihead='*' to show all request headers)"
|
||||
self.log(t % (self.mode, origin, proto, self.host, host, guess), 3)
|
||||
raise Pebkac(403, "rejected by cors-check")
|
||||
raise Pebkac(403, "rejected by cors-check (see serverlog)")
|
||||
|
||||
# getattr(self.mode) is not yet faster than this
|
||||
if self.mode == "POST":
|
||||
|
|
@ -921,7 +953,7 @@ class HttpCli(object):
|
|||
return False
|
||||
|
||||
self.log("banned for {:.0f} sec".format(rt), 6)
|
||||
self.terse_reply(b"thank you for playing", 403)
|
||||
self.terse_reply(b"thank you for playing (see serverlog and readme)", 403)
|
||||
return True
|
||||
|
||||
def permit_caching(self) -> None:
|
||||
|
|
@ -1275,6 +1307,20 @@ class HttpCli(object):
|
|||
else:
|
||||
return self.tx_res(res_path)
|
||||
|
||||
if res_path in RESM:
|
||||
ap = self.E.mod_ + RESM[res_path]
|
||||
if (
|
||||
"txt" not in self.uparam
|
||||
and "mime" not in self.uparam
|
||||
and not self.ouparam.get("dl")
|
||||
):
|
||||
# return mimetype matching request extension
|
||||
self.ouparam["dl"] = res_path.split("/")[-1]
|
||||
if bos.path.exists(ap) or bos.path.exists(ap + ".gz"):
|
||||
return self.tx_file(ap)
|
||||
else:
|
||||
return self.tx_res(res_path)
|
||||
|
||||
self.tx_404()
|
||||
return False
|
||||
|
||||
|
|
@ -3284,9 +3330,9 @@ class HttpCli(object):
|
|||
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
||||
self._assert_safe_rem(rem)
|
||||
|
||||
ext = "" if "." not in new_file else new_file.split(".")[-1]
|
||||
if not ext or len(ext) > 5 or not self.can_delete:
|
||||
new_file += ".md"
|
||||
if not self.can_delete and not new_file.lower().endswith(".md"):
|
||||
t = "you can only create .md files because you don't have the delete-permission"
|
||||
raise Pebkac(400, t)
|
||||
|
||||
sanitized = sanitize_fn(new_file, "")
|
||||
fdir = vfs.canonical(rem)
|
||||
|
|
@ -3325,7 +3371,6 @@ class HttpCli(object):
|
|||
raise Pebkac(500, "that file exists already")
|
||||
|
||||
with open(fsenc(fn), "wb") as f:
|
||||
f.write(b"`GRUNNUR`\n")
|
||||
if "fperms" in vfs.flags:
|
||||
set_fperms(f, vfs.flags)
|
||||
|
||||
|
|
@ -4179,8 +4224,11 @@ class HttpCli(object):
|
|||
# force download
|
||||
|
||||
if "dl" in self.ouparam:
|
||||
cdis = gen_content_disposition(os.path.basename(req_path))
|
||||
self.out_headers["Content-Disposition"] = cdis
|
||||
cdis = self.ouparam["dl"] or req_path
|
||||
zs = gen_content_disposition(os.path.basename(cdis))
|
||||
self.out_headers["Content-Disposition"] = zs
|
||||
else:
|
||||
cdis = req_path
|
||||
|
||||
#
|
||||
# if-modified
|
||||
|
|
@ -4246,7 +4294,7 @@ class HttpCli(object):
|
|||
elif "mime" in self.uparam:
|
||||
mime = str(self.uparam.get("mime"))
|
||||
else:
|
||||
mime = guess_mime(req_path)
|
||||
mime = guess_mime(cdis)
|
||||
|
||||
logmsg += unicode(status) + logtail
|
||||
|
||||
|
|
@ -4354,8 +4402,11 @@ class HttpCli(object):
|
|||
# force download
|
||||
|
||||
if "dl" in self.ouparam:
|
||||
cdis = gen_content_disposition(os.path.basename(req_path))
|
||||
self.out_headers["Content-Disposition"] = cdis
|
||||
cdis = self.ouparam["dl"] or req_path
|
||||
zs = gen_content_disposition(os.path.basename(cdis))
|
||||
self.out_headers["Content-Disposition"] = zs
|
||||
else:
|
||||
cdis = req_path
|
||||
|
||||
#
|
||||
# if-modified
|
||||
|
|
@ -4483,7 +4534,7 @@ class HttpCli(object):
|
|||
elif "rmagic" in self.vn.flags:
|
||||
mime = guess_mime(req_path, fs_path)
|
||||
else:
|
||||
mime = guess_mime(req_path)
|
||||
mime = guess_mime(cdis)
|
||||
|
||||
if "nohtml" in self.vn.flags and "html" in mime:
|
||||
mime = "text/plain; charset=utf-8"
|
||||
|
|
@ -4913,8 +4964,11 @@ class HttpCli(object):
|
|||
# for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]}))
|
||||
cfmt = ""
|
||||
if self.thumbcli and not self.args.no_bacode:
|
||||
for zs in ("opus", "mp3", "flac", "wav", "w", "j", "p"):
|
||||
if zs in self.ouparam or uarg == zs:
|
||||
if uarg in ZIP_XCODE_S:
|
||||
cfmt = uarg
|
||||
else:
|
||||
for zs in ZIP_XCODE_L:
|
||||
if zs in self.ouparam:
|
||||
cfmt = zs
|
||||
|
||||
if cfmt:
|
||||
|
|
@ -5261,7 +5315,7 @@ class HttpCli(object):
|
|||
dls.append((perc, hsent, spd, eta, idle, usr, erd, rds, fn))
|
||||
|
||||
if self.args.have_unlistc:
|
||||
allvols = self.asrv.vfs.all_vols
|
||||
allvols = self.asrv.vfs.all_nodes
|
||||
rvol = [x for x in rvol if "unlistcr" not in allvols[x[1:-1]].flags]
|
||||
wvol = [x for x in wvol if "unlistcw" not in allvols[x[1:-1]].flags]
|
||||
|
||||
|
|
@ -5540,7 +5594,7 @@ class HttpCli(object):
|
|||
rem,
|
||||
self.uname,
|
||||
not self.args.no_scandir,
|
||||
[[True, False], [False, True]],
|
||||
PERMS_rwh,
|
||||
)
|
||||
dots = self.uname in vn.axs.udot
|
||||
dk_sz = vn.flags.get("dk")
|
||||
|
|
@ -5572,7 +5626,13 @@ class HttpCli(object):
|
|||
for x in vfs_virt:
|
||||
if x != excl:
|
||||
try:
|
||||
dvn, drem = vfs.get(vjoin(top, x), self.uname, True, False)
|
||||
dvn, drem = vfs.get(vjoin(top, x), self.uname, False, False)
|
||||
if (
|
||||
self.uname not in dvn.axs.uread
|
||||
and self.uname not in dvn.axs.uwrite
|
||||
and self.uname not in dvn.axs.uhtml
|
||||
):
|
||||
raise Exception()
|
||||
bos.stat(dvn.canonical(drem, False))
|
||||
except:
|
||||
x += "\n"
|
||||
|
|
@ -5978,6 +6038,15 @@ class HttpCli(object):
|
|||
if self.uname != self.args.shr_adm:
|
||||
rows = [x for x in rows if x[5] == self.uname]
|
||||
|
||||
q = "select vp from sf where k=? limit 99"
|
||||
for r in rows:
|
||||
if not r[4]:
|
||||
r[4] = "---"
|
||||
else:
|
||||
zstl = cur.execute(q, (r[0],)).fetchall()
|
||||
zsl = [html_escape(zst[0]) for zst in zstl]
|
||||
r[4] = "<br />".join(zsl)
|
||||
|
||||
html = self.j2s(
|
||||
"shares", this=self, shr=self.args.shr, rows=rows, now=int(time.time())
|
||||
)
|
||||
|
|
@ -6498,8 +6567,7 @@ class HttpCli(object):
|
|||
return self.tx_svg("upload\nonly")
|
||||
|
||||
if not self.can_read and self.can_get and self.avn:
|
||||
axs = self.avn.axs
|
||||
if self.uname not in axs.uhtml:
|
||||
if not self.can_html:
|
||||
pass
|
||||
elif is_dir:
|
||||
for fn in ("index.htm", "index.html"):
|
||||
|
|
@ -6520,6 +6588,7 @@ class HttpCli(object):
|
|||
|
||||
fk_pass = True
|
||||
is_dir = False
|
||||
add_og = False
|
||||
rem = vjoin(rem, fn)
|
||||
vrem = vjoin(vrem, fn)
|
||||
abspath = ap2
|
||||
|
|
@ -6713,7 +6782,7 @@ class HttpCli(object):
|
|||
rem,
|
||||
self.uname,
|
||||
not self.args.no_scandir,
|
||||
[[True, False], [False, True]],
|
||||
PERMS_rwh,
|
||||
lstat="lt" in self.uparam,
|
||||
throw=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -383,8 +383,8 @@ class HttpSrv(object):
|
|||
if nloris < nconn / 2:
|
||||
continue
|
||||
|
||||
t = "slowloris (idle-conn): {} banned for {} min"
|
||||
self.log(self.name, t.format(ip, self.args.loris, nclose), 1)
|
||||
t = "slow%s (idle-conn): %s banned for %d min" # slowloris
|
||||
self.log(self.name, t % ("loris", ip, self.args.loris), 1)
|
||||
self.bans[ip] = int(time.time() + self.args.loris * 60)
|
||||
|
||||
if self.args.log_conn:
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ class Metrics(object):
|
|||
self.hsrv = hsrv
|
||||
|
||||
def tx(self, cli: "HttpCli") -> bool:
|
||||
if not cli.avol:
|
||||
args = cli.args
|
||||
if not cli.avol and cli.uname.lower() not in args.stats_u_set:
|
||||
raise Pebkac(403, "'stats' not allowed for user " + cli.uname)
|
||||
|
||||
args = cli.args
|
||||
if not args.stats:
|
||||
raise Pebkac(403, "the stats feature is not enabled in server config")
|
||||
|
||||
|
|
|
|||
|
|
@ -1081,7 +1081,7 @@ class SvcHub(object):
|
|||
vs = os.path.expandvars(os.path.expanduser(vs))
|
||||
setattr(al, k, vs)
|
||||
|
||||
for k in "idp_adm".split(" "):
|
||||
for k in "idp_adm stats_u".split(" "):
|
||||
vs = getattr(al, k)
|
||||
vsa = [x.strip() for x in vs.split(",")]
|
||||
vsa = [x.lower() for x in vsa if x]
|
||||
|
|
|
|||
|
|
@ -270,6 +270,9 @@ class ThumbSrv(object):
|
|||
|
||||
def shutdown(self) -> None:
|
||||
self.stopping = True
|
||||
Daemon(self._fire_sentinels, "thumbstopper")
|
||||
|
||||
def _fire_sentinels(self):
|
||||
for _ in range(self.nthr):
|
||||
self.q.put(None)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
# which should help on really slow connections
|
||||
# but then why are you using copyparty in the first place
|
||||
|
||||
pk: $(addsuffix .gz, $(wildcard tl/*.js *.js *.css))
|
||||
un: $(addsuffix .un, $(wildcard tl/*.gz *.gz))
|
||||
pk: $(addsuffix .gz, $(wildcard tl/*.js *.js *.css) \
|
||||
a/webdav-cfg.txt )
|
||||
un: $(addsuffix .un, $(wildcard tl/*.gz *.gz a/*.gz))
|
||||
|
||||
%.gz: %
|
||||
pigz -11 -J 34 -I 573 $<
|
||||
pigz -c11 -J 34 -I 573 <$< >$@
|
||||
touch -r $< $@
|
||||
rm $<
|
||||
|
||||
%.un: %
|
||||
pigz -d $<
|
||||
|
|
|
|||
|
|
@ -1036,6 +1036,7 @@ html.dz #flogout {
|
|||
box-shadow: 0 .1em 1.2em var(--g-play-sh);
|
||||
}
|
||||
#files tbody tr.sel td,
|
||||
#files tbody tr.sel span,
|
||||
#ggrid>a.sel,
|
||||
#ggrid>a[tt].sel {
|
||||
color: var(--g-sel-fg);
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@
|
|||
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="{{ url_suf }}">
|
||||
<input type="hidden" name="act" value="new_md" />
|
||||
📝<input type="text" name="name" class="i" placeholder="weekend-plans">
|
||||
<input type="submit" value="new markdown doc">
|
||||
<input type="submit" value="new file">
|
||||
</form>
|
||||
<span id="new_mdi"></p>
|
||||
</div>
|
||||
|
||||
<div id="op_msg" class="opview opbox {% if not ls0 %}act{% endif %}">
|
||||
|
|
@ -137,7 +138,6 @@
|
|||
lang = "{{ lang }}",
|
||||
dfavico = "{{ favico }}",
|
||||
have_tags_idx = {{ have_tags_idx }},
|
||||
sb_lg = "{{ sb_lg }}",
|
||||
logues = {{ logues|tojson if sb_lg else "[]" }},
|
||||
ls0 = {{ ls0|tojson }};
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ if (1)
|
|||
"ot_unpost": "unpost: delete your recent uploads, or abort unfinished ones",
|
||||
"ot_bup": "bup: basic uploader, even supports netscape 4.0",
|
||||
"ot_mkdir": "mkdir: create a new directory",
|
||||
"ot_md": "new-md: create a new markdown document",
|
||||
"ot_md": "new-file: create a new textfile",
|
||||
"ot_msg": "msg: send a message to the server log",
|
||||
"ot_mp": "media player options",
|
||||
"ot_cfg": "configuration options",
|
||||
|
|
@ -128,7 +128,7 @@ if (1)
|
|||
"ot_noie": 'Please use Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "make directory",
|
||||
"ab_mkdoc": "new markdown doc",
|
||||
"ab_mkdoc": "new textfile",
|
||||
"ab_msg": "send msg to srv log",
|
||||
|
||||
"ay_path": "skip to folders",
|
||||
|
|
@ -440,6 +440,8 @@ if (1)
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Copy</a><a href="#" id="modal-ng">Upload</a>',
|
||||
|
||||
"mk_noname": "type a name into the text field on the left before you do that :p",
|
||||
"nmd_i1": "also add the file extension you want, for example <code>.md</code>",
|
||||
"nmd_i2": "you can only create <code>.md</code> files because you don't have the delete-permission",
|
||||
|
||||
"tv_load": "Loading text document:\n\n{0}\n\n{1}% ({2} of {3} MiB loaded)",
|
||||
"tv_xe1": "could not load textfile:\n\nerror ",
|
||||
|
|
@ -7148,6 +7150,8 @@ var treectl = (function () {
|
|||
if (res.files[a].tags === undefined)
|
||||
res.files[a].tags = {};
|
||||
|
||||
sb_lg = res.sb_lg;
|
||||
sb_md = res.sb_md;
|
||||
dnsort = res.dnsort;
|
||||
read_dsort(res.dsort);
|
||||
dcrop = res.dcrop;
|
||||
|
|
@ -7741,6 +7745,8 @@ function apply_perms(res) {
|
|||
if (up2k)
|
||||
up2k.set_fsearch();
|
||||
|
||||
ebi('new_mdi').innerHTML = has(perms, "delete") ? L.nmd_i1 : L.nmd_i2;
|
||||
|
||||
widget.setvis();
|
||||
thegrid.setvis();
|
||||
if (!have_read && have_write)
|
||||
|
|
@ -8797,7 +8803,7 @@ function show_md(md, name, div, url, depth) {
|
|||
var els = QSA('#epi a');
|
||||
for (var a = 0, aa = els.length; a < aa; a++) {
|
||||
var href = els[a].getAttribute('href');
|
||||
if (!href.startsWith('#') || href.startsWith('#md-'))
|
||||
if (!href || !href.startsWith('#') || href.startsWith('#md-'))
|
||||
continue;
|
||||
|
||||
els[a].setAttribute('href', '#md-' + href.slice(1));
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<script>
|
||||
setTimeout(function() {
|
||||
location.replace("{{ redir }}");
|
||||
}, 1000);
|
||||
}, 600);
|
||||
</script>
|
||||
{%- endif %}
|
||||
{%- if js %}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ th {
|
|||
#wrap th {
|
||||
padding: .3em .6em;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#wrap td+td+td+td+td+td+td+td {
|
||||
|
|
@ -71,7 +72,10 @@ th {
|
|||
#wrap td:last-child {
|
||||
border-radius: 0 .5em .5em 0;
|
||||
}
|
||||
|
||||
#wrap.terse td div {
|
||||
height: 2.3em;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
|
||||
html.z {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="wrap" class="terse">
|
||||
<a href="{{ r }}/?shares">refresh</a>
|
||||
<a id="xpnd" href="#">files</a>
|
||||
<a href="{{ r }}/?h">control-panel</a>
|
||||
|
||||
<span>axs = perms (read,write,move,delet)</span>
|
||||
|
|
@ -46,7 +47,7 @@
|
|||
<td>{{ "yes" if pw else "--" }}</td>
|
||||
<td><a href="{{ r }}/{{ vp|e }}">/{{ vp|e }}</a></td>
|
||||
<td>{{ pr }}</td>
|
||||
<td>{{ st }}</td>
|
||||
<td><div>{{ st }}</div></td>
|
||||
<td>{{ un|e }}</td>
|
||||
<td>{{ t0 }}</td>
|
||||
<td>{{ t1 }}</td>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ function cb() {
|
|||
location = '?shares';
|
||||
}
|
||||
|
||||
ebi('xpnd').onclick = function (e) {
|
||||
ev(e);
|
||||
clmod(ebi('wrap'), 'terse', 't');
|
||||
};
|
||||
|
||||
function qr(e) {
|
||||
ev(e);
|
||||
var href = this.href,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<thead><tr><th>%</th><th>speed</th><th>eta</th><th>idle</th><th>dir</th><th>file</th></tr></thead>
|
||||
<tbody>
|
||||
{%- for u in ups %}
|
||||
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td><a href="{{ u[4] }}">{{ u[5]|e }}</a></td><td>{{ u[6]|e }}</td></tr>
|
||||
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td><a href="{{ r }}/{{ u[4] }}">{{ u[5]|e }}</a></td><td>{{ u[6]|e }}</td></tr>
|
||||
{%- endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
<thead><tr><th>%</th><th>sent</th><th>speed</th><th>eta</th><th>idle</th><th></th><th>dir</th><th>file</th></tr></thead>
|
||||
<tbody>
|
||||
{%- for u in dls %}
|
||||
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td>{{ u[4] }}</td><td>{{ u[5] }}</td><td><a href="{{ u[6] }}">{{ u[7]|e }}</a></td><td>{{ u[8] }}</td></tr>
|
||||
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td>{{ u[4] }}</td><td>{{ u[5] }}</td><td><a href="{{ r }}/{{ u[6] }}">{{ u[7]|e }}</a></td><td>{{ u[8] }}</td></tr>
|
||||
{%- endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -120,7 +120,11 @@
|
|||
</form>
|
||||
</div>
|
||||
{%- else %}
|
||||
{%- if this.uname == '*' %}
|
||||
<h1 id="l">login for more:</h1>
|
||||
{%- else %}
|
||||
<h1 id="l">change account:</h1>
|
||||
{%- endif %}
|
||||
<div>
|
||||
{%- if this.args.idp_login %}
|
||||
<ul><li>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
<li>old version of rclone? replace all <code>=</code> with <code> </code> (space)</li>
|
||||
</ul>
|
||||
|
||||
<p>if you want to use the native WebDAV client in windows instead (slow and buggy), first run <a href="{{ r }}/.cpr/a/webdav-cfg.bat">webdav-cfg.bat</a> to remove the 47 MiB filesize limit (also fixes latency and password login), then connect:</p>
|
||||
<p>if you want to use the native WebDAV client in windows instead (slow and buggy), first run <a href="{{ r }}/.cpr/a/webdav-cfg.txt?dl=webdav-cfg.bat">webdav-cfg.bat</a> to remove the 47 MiB filesize limit (also fixes latency and password login), then connect:</p>
|
||||
<pre>
|
||||
{%- if un %}
|
||||
net use <b>w:</b> http{{ s }}://{{ ep }}/{{ rvp }}{% if accs %} <b>{{ pw }}</b> /user:{{ b_un }}{% endif %}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.chi = {
|
|||
"ot_unpost": "取消发布:删除最近上传的内容,或中止未完成的内容",
|
||||
"ot_bup": "bup:基础上传器,甚至支持 Netscape 4.0",
|
||||
"ot_mkdir": "mkdir:创建新目录",
|
||||
"ot_md": "new-md:创建新 Markdown 文档",
|
||||
"ot_md": "new-file:创建新的文本文件", //m
|
||||
"ot_msg": "msg:向服务器日志发送消息",
|
||||
"ot_mp": "媒体播放器选项",
|
||||
"ot_cfg": "配置选项",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.chi = {
|
|||
"ot_noie": '请使用 Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "创建目录",
|
||||
"ab_mkdoc": "新建 Markdown 文档",
|
||||
"ab_mkdoc": "新建文本文件", //m
|
||||
"ab_msg": "发送消息到服务器日志",
|
||||
|
||||
"ay_path": "跳转到文件夹",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.chi = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">复制</a><a href="#" id="modal-ng">上传</a>', //m
|
||||
|
||||
"mk_noname": "在左侧文本框中输入名称,然后再执行此操作 :p",
|
||||
"nmd_i1": "还可以添加需要的文件扩展名,例如 <code>.txt</code>", //m
|
||||
"nmd_i2": "由于没有删除权限,你只能创建 <code>.md</code> 文件", //m
|
||||
|
||||
"tv_load": "加载文本文件:\n\n{0}\n\n{1}% ({2} 的 {3} MiB 已加载)",
|
||||
"tv_xe1": "无法加载文本文件:\n\n错误 ",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ Ls.cze = {
|
|||
"ot_unpost": "unpost: smazat vaše nedávné nahrání nebo zrušit nedokončené",
|
||||
"ot_bup": "bup: základní nahrávač, podporuje i netscape 4.0",
|
||||
"ot_mkdir": "mkdir: vytvořit nový adresář",
|
||||
"ot_md": "new-md: vytvořit nový markdown dokument",
|
||||
"ot_md": "new-file: vytvořit nový textový soubor", //m
|
||||
"ot_msg": "msg: poslat zprávu do logu serveru",
|
||||
"ot_mp": "možnosti přehrávače médií",
|
||||
"ot_cfg": "možnosti konfigurace",
|
||||
|
|
@ -129,7 +129,7 @@ Ls.cze = {
|
|||
"ot_noie": 'Prosím použijte Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "vytvořit adresář",
|
||||
"ab_mkdoc": "nový markdown dokument",
|
||||
"ab_mkdoc": "nový textový soubor", //m
|
||||
"ab_msg": "poslat zprávu do logu serveru",
|
||||
|
||||
"ay_path": "přejít na složky",
|
||||
|
|
@ -441,6 +441,8 @@ Ls.cze = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopírovat</a><a href="#" id="modal-ng">Nahrát</a>',
|
||||
|
||||
"mk_noname": "napište název do textového pole vlevo předtím než to uděláte :p",
|
||||
"nmd_i1": "můžeš také přidat příponu souboru, například <code>.txt</code>", //m
|
||||
"nmd_i2": "můžeš vytvářet pouze <code>.md</code> soubory, protože nemáš oprávnění mazat", //m
|
||||
|
||||
"tv_load": "Načítání textového dokumentu:\n\n{0}\n\n{1}% ({2} z {3} MiB načteno)",
|
||||
"tv_xe1": "nelze načíst textový soubor:\n\nchyba ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.deu = {
|
|||
"ot_unpost": "unpost: lösche deine letzten Uploads oder breche unvollständige ab",
|
||||
"ot_bup": "bup: Basic Uploader, unterstützt sogar Neuheiten wie Netscape 4.0",
|
||||
"ot_mkdir": "mkdir: Neuen Ordner erstellen",
|
||||
"ot_md": "new-md: Neues Markdown-Dokument erstellen",
|
||||
"ot_md": "new-file: Neues Textdokument erstellen", //m
|
||||
"ot_msg": "msg: Eine Nachricht an das Server-Log schicken",
|
||||
"ot_mp": "Media Player-Optionen",
|
||||
"ot_cfg": "Konfigurationsoptionen",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.deu = {
|
|||
"ot_noie": 'Bitte benutze Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "Ordner erstellen",
|
||||
"ab_mkdoc": "Markdown Doc erstellen",
|
||||
"ab_mkdoc": "Textdatei erstellen", //m
|
||||
"ab_msg": "Nachricht an Server Log senden",
|
||||
|
||||
"ay_path": "zu Ordnern springen",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.deu = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopieren</a><a href="#" id="modal-ng">Hochladen</a>',
|
||||
|
||||
"mk_noname": "Tipp' mal vorher lieber einen Namen in das Textfeld links, bevor du das machst :p",
|
||||
"nmd_i1": "Fügen Sie auch die gewünschte Dateiendung hinzu, z. B. <code>.txt</code>", //m
|
||||
"nmd_i2": "Sie können nur <code>.md</code>-Dateien erstellen, da Ihnen die Löschberechtigung fehlt", //m
|
||||
|
||||
"tv_load": "Textdatei wird geladen:\n\n{0}\n\n{1}% ({2} von {3} MiB geladen)",
|
||||
"tv_xe1": "Konnte Textdatei nicht laden:\n\nFehler ",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
// Linioj finiĝantaj per //m estas nekontrolitaj maŝinaj tradukoj
|
||||
// Linioj, finiĝantaj per "//m", estas nekontrolitaj maŝinaj tradukoj
|
||||
|
||||
Ls.epo = {
|
||||
"tt": "Esperanto",
|
||||
|
|
@ -116,7 +116,7 @@ Ls.epo = {
|
|||
"ot_unpost": "unpost: forigi viaj plej lastaj alŝutoj, aŭ ĉesigi nefinigitajn",
|
||||
"ot_bup": "bup: fundamenta alŝutilo, funkias eĉ kun netscape 4.0",
|
||||
"ot_mkdir": "mkdir: krei novan dosierujon",
|
||||
"ot_md": "new-md: krei novan markdown-dosieron",
|
||||
"ot_md": "new-file: krei novan tekstodosieron", //m
|
||||
"ot_msg": "msg: sendi mesaĝon al servila protokolo",
|
||||
"ot_mp": "agordoj de medialudilo",
|
||||
"ot_cfg": "aliaj agordoj",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.epo = {
|
|||
"ot_noie": 'Bonvolu uzi retumilojn Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "krei dosierujon",
|
||||
"ab_mkdoc": "krei markdown-dosieron",
|
||||
"ab_mkdoc": "krei tekstodosieron", //m
|
||||
"ab_msg": "sendi mesaĝon al protokolo",
|
||||
|
||||
"ay_path": "iri al dosierujoj",
|
||||
|
|
@ -204,7 +204,7 @@ Ls.epo = {
|
|||
"u_nav_b": '<a href="#" id="modal-ok">Dosierojn</a><a href="#" id="modal-ng">Unu dosierujo</a>',
|
||||
|
||||
"cl_opts": "ŝaltiloj",
|
||||
"cl_hfsz": "Dosiergrando", //m
|
||||
"cl_hfsz": "dosiergrando",
|
||||
"cl_themes": "etoso",
|
||||
"cl_langs": "lingvo",
|
||||
"cl_ziptype": "elŝutado de dosieroj",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.epo = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopii</a><a href="#" id="modal-ng">Alŝuti</a>',
|
||||
|
||||
"mk_noname": "tajpu nomon en tekstokampo maldekstre antaŭ vi faras ĉi tion :p",
|
||||
"nmd_i1": "vi povas aldoni la deziratan sufikson, ekzemple <code>.txt</code>", //m
|
||||
"nmd_i2": "vi povas krei nur <code>.md</code>-dosierojn ĉar vi ne havas forigan permeson", //m
|
||||
|
||||
"tv_load": "Ŝargado de teksto-dokumento:\n\n{0}\n\n{1}% ({2} da {3} MiB ŝargita)",
|
||||
"tv_xe1": "ne povas ŝargi teksto-dosieron:\n\neraro ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.fin = {
|
|||
"ot_unpost": "unpost: poista viimeaikaiset tai keskeytä keskeneräiset lataukset",
|
||||
"ot_bup": "bup: tiedostojen 'perus'lähetysohjelma, tukee jopa netscape 4.0",
|
||||
"ot_mkdir": "mkdir: luo uusi hakemisto",
|
||||
"ot_md": "new-md: luo uusi markdown-dokumentti",
|
||||
"ot_md": "new-file: luo uusi tekstitiedosto", //m
|
||||
"ot_msg": "msg: lähetä viesti palvelinlokiin",
|
||||
"ot_mp": "mediasoittimen asetukset",
|
||||
"ot_cfg": "asetukset",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.fin = {
|
|||
"ot_noie": 'Suosittelemme käyttämään uudempaa selainta.',
|
||||
|
||||
"ab_mkdir": "luo hakemisto",
|
||||
"ab_mkdoc": "luo markdown-tiedosto",
|
||||
"ab_mkdoc": "luo tekstitiedosto", //m
|
||||
"ab_msg": "lähetä viesti palvelinlokiin",
|
||||
|
||||
"ay_path": "siirry hakemistoihin",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.fin = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopioi</a><a href="#" id="modal-ng">Lähetä</a>',
|
||||
|
||||
"mk_noname": "kirjoita nimi vasemmalla olevaan tekstikenttään ennen kuin teet tuon :p",
|
||||
"nmd_i1": "voit myös lisätä haluamasi tiedostopäätteen, esimerkiksi <code>.txt</code>", //m
|
||||
"nmd_i2": "voit luoda vain <code>.md</code>-tiedostoja, koska sinulla ei ole poistolupaa", //m
|
||||
|
||||
"tv_load": "Ladataan tekstidokumenttia:\n\n{0}\n\n{1}% ({2} / {3} Mt ladattu)",
|
||||
"tv_xe1": "tekstitiedoston lataaminen epäonnistui:\n\nvirhe ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.fra = {
|
|||
"ot_unpost": "unpost: supprimer vos téléchargements récents, ou annuler ceux en cours",
|
||||
"ot_bup": "bup: téléverseur de base, prend même en charge netscape 4.0",
|
||||
"ot_mkdir": "mkdir: créer un nouveau répertoire",
|
||||
"ot_md": "new-md: créer un nouveau document markdown",
|
||||
"ot_md": "new-file: créer un nouveau fichier texte", //m
|
||||
"ot_msg": "msg: envoyer un message au journal du serveur",
|
||||
"ot_mp": "options du lecteur multimedia",
|
||||
"ot_cfg": "options de configuration",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.fra = {
|
|||
"ot_noie": 'Utilisez Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "créer un nouveau répertoire",
|
||||
"ab_mkdoc": "faire un nouveau document markdown",
|
||||
"ab_mkdoc": "nouveau fichier texte", //m
|
||||
"ab_msg": "envoyer un message au journal du serveur",
|
||||
|
||||
"ay_path": "passer aux dossiers",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.fra = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Copier</a><a href="#" id="modal-ng">Téléverser</a>',
|
||||
|
||||
"mk_noname": "entrez un nom dans le champ de texte à gauche avant de faire ça :p",
|
||||
"nmd_i1": "ajoutez aussi l’extension souhaitée, par exemple <code>.txt</code>", //m
|
||||
"nmd_i2": "vous ne pouvez créer que des fichiers <code>.md</code> car vous n’avez pas la permission d’effacer", //m
|
||||
|
||||
"tv_load": "Chargement du document texte:\n\n{0}\n\n{1}% ({2} de {3} MiB chargés)",
|
||||
"tv_xe1": "impossible de charger le fichier texte:\n\nerreur",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.grc = {
|
|||
"ot_unpost": "unpost: διαγραφή πρόσφατων μεταφορτώσεων ή ακύρωση ανολοκλήρωτων",
|
||||
"ot_bup": "bup: βασικός uploader, υποστηρίζει μέχρι και netscape 4.0",
|
||||
"ot_mkdir": "mkdir: δημιουργία νέου φακέλου",
|
||||
"ot_md": "new-md: δημιουργία νέου markdown εγγράφου",
|
||||
"ot_md": "new-file: δημιουργία νέου αρχείου κειμένου", //m
|
||||
"ot_msg": "msg: αποστολή μηνύματος στο server log",
|
||||
"ot_mp": "επιλογές media player",
|
||||
"ot_cfg": "επιλογές ρυθμίσεων",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.grc = {
|
|||
"ot_noie": 'Χρησιμοποίησε Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "δημιουργία φακέλου",
|
||||
"ab_mkdoc": "νέο markdown έγγραφο",
|
||||
"ab_mkdoc": "νέο αρχείο κειμένου", //m
|
||||
"ab_msg": "στείλε μήνυμα στο server log",
|
||||
|
||||
"ay_path": "πήγαινε σε φακέλους",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.grc = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Αντιγραφή</a><a href="#" id="modal-ng">Μεταφόρτωση</a>',
|
||||
|
||||
"mk_noname": "γράψε ένα όνομα στο πεδίο κειμένου αριστερά πριν το κάνεις :p",
|
||||
"nmd_i1": "μπορείτε επίσης να προσθέσετε την κατάληξη που θέλετε, όπως <code>.txt</code>", //m
|
||||
"nmd_i2": "μπορείτε να δημιουργήσετε μόνο αρχεία <code>.md</code> επειδή δεν έχετε δικαίωμα διαγραφής", //m
|
||||
|
||||
"tv_load": "Φόρτωση αρχείου κειμένου:\n\n{0}\n\n{1}% ({2} από {3} MiB φορτωμένα)",
|
||||
"tv_xe1": "αδυναμία φόρτωσης αρχείου κειμένου:\n\nσφάλμα ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.ita = {
|
|||
"ot_unpost": "unpost: elimina i tuoi caricamenti recenti, o interrompi quelli non completati",
|
||||
"ot_bup": "bup: uploader di base, supporta anche netscape 4.0",
|
||||
"ot_mkdir": "mkdir: crea una nuova directory",
|
||||
"ot_md": "new-md: crea un nuovo documento markdown",
|
||||
"ot_md": "new-file: crea un nuovo file di testo", //m
|
||||
"ot_msg": "msg: invia un messaggio al log del server",
|
||||
"ot_mp": "opzioni lettore multimediale",
|
||||
"ot_cfg": "opzioni di configurazione",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.ita = {
|
|||
"ot_noie": 'Perfavore usa Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "crea directory",
|
||||
"ab_mkdoc": "nuovo doc markdown",
|
||||
"ab_mkdoc": "nuovo file di testo", //m
|
||||
"ab_msg": "invia msg al log srv",
|
||||
|
||||
"ay_path": "salta alle cartelle",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.ita = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Copia</a><a href="#" id="modal-ng">Carica</a>',
|
||||
|
||||
"mk_noname": "scrivi un nome nel campo di testo a sinistra prima di farlo :p",
|
||||
"nmd_i1": "puoi anche aggiungere l’estensione che vuoi, per esempio <code>.txt</code>", //m
|
||||
"nmd_i2": "puoi creare solo file <code>.md</code> perché non hai il permesso di eliminare", //m
|
||||
|
||||
"tv_load": "Caricando documento di testo:\n\n{0}\n\n{1}% ({2} di {3} MiB caricati)",
|
||||
"tv_xe1": "impossibile caricare file di testo:\n\nerrore ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.kor = {
|
|||
"ot_unpost": "주워담기: 최근 업로드한 항목을 삭제하거나 미완료된 업로드를 중단합니다",
|
||||
"ot_bup": "bup: 기본 업로더. 넷스케이프 4.0도 지원합니다",
|
||||
"ot_mkdir": "mkdir: 새 디렉터리를 만듭니다",
|
||||
"ot_md": "new-md: 새 마크다운 문서를 만듭니다",
|
||||
"ot_md": "new-file: 새 텍스트 파일을 만듭니다", //m
|
||||
"ot_msg": "msg: 서버 로그에 메시지를 보냅니다",
|
||||
"ot_mp": "미디어 플레이어 옵션",
|
||||
"ot_cfg": "구성 옵션",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.kor = {
|
|||
"ot_noie": 'Chrome / Firefox / Edge를 사용해주세요',
|
||||
|
||||
"ab_mkdir": "디렉터리 만들기",
|
||||
"ab_mkdoc": "새 마크다운 문서",
|
||||
"ab_mkdoc": "새 텍스트 파일", //m
|
||||
"ab_msg": "서버 로그에 메시지 보내기",
|
||||
|
||||
"ay_path": "폴더로 건너뛰기",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.kor = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">복사</a><a href="#" id="modal-ng">업로드</a>',
|
||||
|
||||
"mk_noname": "왼쪽 텍스트 필드에 이름을 먼저 입력해주세요 :p",
|
||||
"nmd_i1": "원하는 파일 확장자를 추가할 수 있습니다. 예: <code>.txt</code>", //m
|
||||
"nmd_i2": "삭제 권한이 없어서 <code>.md</code> 파일만 만들 수 있습니다", //m
|
||||
|
||||
"tv_load": "텍스트 문서 불러오는 중:\n\n{0}\n\n{1}% ({3} MiB 중 {2} MiB 로드됨)",
|
||||
"tv_xe1": "텍스트 파일을 불러올 수 없습니다:\n\n오류 ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.nld = {
|
|||
"ot_unpost": "unpost: verwijder je recente uploads, of onvoltooide uploads afbreken",
|
||||
"ot_bup": "bup: Basisuploader, supports zelfs netscape 4.0",
|
||||
"ot_mkdir": "mkdir: Maak een nieuwe map",
|
||||
"ot_md": "new-md: Maak een nieuwe markdown bestand",
|
||||
"ot_md": "new-file: Maak een nieuw tekstbestand", //m
|
||||
"ot_msg": "msg: Verstuur een bericht naar de server logs",
|
||||
"ot_mp": "Media speler opties",
|
||||
"ot_cfg": "Configuratie opties",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.nld = {
|
|||
"ot_noie": 'Gebruik alstublieft Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "maak map",
|
||||
"ab_mkdoc": "nieuw markdown doc",
|
||||
"ab_mkdoc": "nieuw tekstbestand", //m
|
||||
"ab_msg": "verstuur msg naar srv log",
|
||||
|
||||
"ay_path": "skip naar mappen",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.nld = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopieer</a><a href="#" id="modal-ng">Upload</a>',
|
||||
|
||||
"mk_noname": "Voer een naam in het tekstveld aan de linkerkant voordat je verder gaat :p",
|
||||
"nmd_i1": "Voeg ook de gewenste extensie toe, bijvoorbeeld <code>.txt</code>", //m
|
||||
"nmd_i2": "Je kunt alleen <code>.md</code>-bestanden maken omdat je geen verwijderrechten hebt", //m
|
||||
|
||||
"tv_load": "Tekstdocument laden:\n\n{0}\n\n{1}% ({2} van de {3} MiB geladen)",
|
||||
"tv_xe1": "Kon tekstbestand niet laden:\n\nfout ",
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ Ls.nno = {
|
|||
"ot_unpost": "unpost: slett filer som du nyleg har lastet opp; «angre-knappen»",
|
||||
"ot_bup": "bup: tradisjonell / primitiv filopplasting,$N$Nfungerar i om lag samtlege nettlesarar",
|
||||
"ot_mkdir": "mkdir: lag ei ny mappe",
|
||||
"ot_md": "new-md: lag eit nytt markdown-dokument",
|
||||
"ot_md": "new-file: lag ein ny tekstfil",
|
||||
"ot_msg": "msg: send ein beskjed åt serverloggen",
|
||||
"ot_mp": "musikkspelarinstillinger",
|
||||
"ot_cfg": "andre innstillinger",
|
||||
|
|
@ -123,7 +123,7 @@ Ls.nno = {
|
|||
"ot_noie": 'Fungerer mye betre i Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "lag mappe",
|
||||
"ab_mkdoc": "nytt dokument",
|
||||
"ab_mkdoc": "ny tekstfil",
|
||||
"ab_msg": "send melding",
|
||||
|
||||
"ay_path": "gå videre åt mapper",
|
||||
|
|
@ -435,6 +435,8 @@ Ls.nno = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopiér</a><a href="#" id="modal-ng">Last opp</a>',
|
||||
|
||||
"mk_noname": "skriv inn eit namn i tekstboksa åt venstre først :p",
|
||||
"nmd_i1": "leggja også til filendinga du vil, til dømes <code>.txt</code>", //m
|
||||
"nmd_i2": "du kan berre laga <code>.md</code>-filer fordi du ikkje har delete-tilgang", //m
|
||||
|
||||
"tv_load": "Lastar inn tekstfil:\n\n{0}\n\n{1}% ({2} av {3} MiB lasta ned)",
|
||||
"tv_xe1": "kunne ikkje laste tekstfil:\n\nfeil ",
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ Ls.nor = {
|
|||
"ot_unpost": "unpost: slett filer som du nylig har lastet opp; «angre-knappen»",
|
||||
"ot_bup": "bup: tradisjonell / primitiv filopplastning,$N$Nfungerer i omtrent samtlige nettlesere",
|
||||
"ot_mkdir": "mkdir: lag en ny mappe",
|
||||
"ot_md": "new-md: lag et nytt markdown-dokument",
|
||||
"ot_md": "new-file: lag en ny tekstfil",
|
||||
"ot_msg": "msg: send en beskjed til serverloggen",
|
||||
"ot_mp": "musikkspiller-instillinger",
|
||||
"ot_cfg": "andre innstillinger",
|
||||
|
|
@ -123,7 +123,7 @@ Ls.nor = {
|
|||
"ot_noie": 'Fungerer mye bedre i Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "lag mappe",
|
||||
"ab_mkdoc": "nytt dokument",
|
||||
"ab_mkdoc": "ny tekstfil",
|
||||
"ab_msg": "send melding",
|
||||
|
||||
"ay_path": "gå videre til mapper",
|
||||
|
|
@ -435,6 +435,8 @@ Ls.nor = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopiér</a><a href="#" id="modal-ng">Last opp</a>',
|
||||
|
||||
"mk_noname": "skriv inn et navn i tekstboksen til venstre først :p",
|
||||
"nmd_i1": "legg også til ønsket filtype, for eksempel <code>.txt</code>", //m
|
||||
"nmd_i2": "du kan bare lage <code>.md</code>-filer fordi du ikke har delete-tilgang", //m
|
||||
|
||||
"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 ",
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ Ls.pol = {
|
|||
"ot_unpost": "unpost: usuń ostatnio przesłane pliki lub przerwij przesyłanie",
|
||||
"ot_bup": "bup: podstawowe przesyłanie danych, wspiera nawet netscape 4.0",
|
||||
"ot_mkdir": "mkdir: tworzy nowy folder",
|
||||
"ot_md": "new-md: tworzy nowy dokument markdown",
|
||||
"ot_md": "new-file: tworzy nowy plik tekstowy", //m
|
||||
"ot_msg": "msg: wysyła wiadomość do loga serwera",
|
||||
"ot_mp": "opcje odtwarzacza multimediów",
|
||||
"ot_cfg": "opcje konfiguracji",
|
||||
|
|
@ -128,7 +128,7 @@ Ls.pol = {
|
|||
"ot_noie": 'Użyj przeglądarki Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "stwórz folder",
|
||||
"ab_mkdoc": "stwórz dok. markdown",
|
||||
"ab_mkdoc": "nowy plik tekstowy", //m
|
||||
"ab_msg": "wyślij wiad. do logów serwera",
|
||||
|
||||
"ay_path": "przejdź do folderów",
|
||||
|
|
@ -440,6 +440,8 @@ Ls.pol = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopiuj</a><a href="#" id="modal-ng">Prześlij</a>',
|
||||
|
||||
"mk_noname": "wpisz nazwę do pola po lewej zanim to zrobisz :p",
|
||||
"nmd_i1": "możesz też dodać wybrane rozszerzenie, np. <code>.txt</code>", //m
|
||||
"nmd_i2": "możesz tworzyć tylko pliki <code>.md</code>, ponieważ nie masz uprawnień do usuwania", //m
|
||||
|
||||
"tv_load": "Wczytywanie pliku tekstowego:\n\n{0}\n\n{1}% (wczytano {2} z {3} MiB)",
|
||||
"tv_xe1": "nie udało się wczytać pliku:\n\nbłąd ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.por = {
|
|||
"ot_unpost": "despublicar: excluir seus uploads recentes, ou abortar os que não foram concluídos",
|
||||
"ot_bup": "bup: uploader básico, até suporta netscape 4.0",
|
||||
"ot_mkdir": "mkdir: criar um novo diretório",
|
||||
"ot_md": "new-md: criar um novo documento markdown",
|
||||
"ot_md": "new-file: criar um novo ficheiro de texto", //m
|
||||
"ot_msg": "msg: enviar uma mensagem para o log do servidor",
|
||||
"ot_mp": "opções do reprodutor de mídia",
|
||||
"ot_cfg": "opções de configuração",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.por = {
|
|||
"ot_noie": 'Por favor, use Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "criar diretório",
|
||||
"ab_mkdoc": "novo documento markdown",
|
||||
"ab_mkdoc": "novo ficheiro de texto", //m
|
||||
"ab_msg": "enviar msg para o log do srv",
|
||||
|
||||
"ay_path": "pular para pastas",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.por = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Copiar</a><a href="#" id="modal-ng">Enviar</a>',
|
||||
|
||||
"mk_noname": "digite um nome no campo de texto à esquerda antes de fazer isso :p",
|
||||
"nmd_i1": "também pode adicionar a extensão desejada, por exemplo <code>.txt</code>", //m
|
||||
"nmd_i2": "só pode criar ficheiros <code>.md</code> porque não tem permissão para apagar", //m
|
||||
|
||||
"tv_load": "Carregando documento de texto:\n\n{0}\n\n{1}% ({2} de {3} MiB carregados)",
|
||||
"tv_xe1": "não foi possível carregar o arquivo de texto:\n\nerro ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.rus = {
|
|||
"ot_unpost": "unpost: удалить ваши недавние загрузки и отменить незавершённые",
|
||||
"ot_bup": "bup: легковесный загрузчик файлов, поддерживает даже netscape 4.0",
|
||||
"ot_mkdir": "mkdir: создать новую папку",
|
||||
"ot_md": "new-md: создать новый markdown-документ",
|
||||
"ot_md": "new-file: создать новый текстовый файл", //m
|
||||
"ot_msg": "msg: отправить сообщение в лог сервера",
|
||||
"ot_mp": "настройка медиаплеера",
|
||||
"ot_cfg": "остальные настройки",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.rus = {
|
|||
"ot_noie": 'Пожалуйста, используйте Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "создать папку",
|
||||
"ab_mkdoc": "создать markdown-документ",
|
||||
"ab_mkdoc": "создать текстовый файл", //m
|
||||
"ab_msg": "отправить сообщение в лог сервера",
|
||||
|
||||
"ay_path": "перейти к папкам",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.rus = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Скопировать</a><a href="#" id="modal-ng">Загрузить</a>',
|
||||
|
||||
"mk_noname": "введите имя в текстовое поле слева перед тем, как это делать :p",
|
||||
"nmd_i1": "вы также можете указать нужное расширение, например <code>.txt</code>", //m
|
||||
"nmd_i2": "вы можете создавать только файлы <code>.md</code>, так как у вас нет разрешения на удаление", //m
|
||||
|
||||
"tv_load": "Загружаю текстовый документ:\n\n{0}\n\n{1}% ({2} из {3} МиБ загружено)",
|
||||
"tv_xe1": "не удалось загрузить текстовый файл:\n\nошибка ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.spa = {
|
|||
"ot_unpost": "dessubir: elimina tus subidas recientes, o aborta las inacabadas",
|
||||
"ot_bup": "bup: uploader básico, soporta hasta netscape 4.0",
|
||||
"ot_mkdir": "mkdir: crear un nuevo directorio",
|
||||
"ot_md": "new-md: crear un nuevo documento markdown",
|
||||
"ot_md": "new-file: crear un nuevo archivo de texto", //m
|
||||
"ot_msg": "msg: enviar un mensaje al registro del servidor",
|
||||
"ot_mp": "opciones del reproductor multimedia",
|
||||
"ot_cfg": "opciones de configuración",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.spa = {
|
|||
"ot_noie": "Por favor, usa Chrome / Firefox / Edge",
|
||||
|
||||
"ab_mkdir": "crear directorio",
|
||||
"ab_mkdoc": "nuevo documento markdown",
|
||||
"ab_mkdoc": "nuevo archivo de texto", //m
|
||||
"ab_msg": "enviar msg al registro del servidor",
|
||||
|
||||
"ay_path": "saltar a carpetas",
|
||||
|
|
@ -436,6 +436,8 @@ Ls.spa = {
|
|||
"fcp_both_b": "<a href=\"#\" id=\"modal-ok\">Copiar</a><a href=\"#\" id=\"modal-ng\">Subir</a>",
|
||||
|
||||
"mk_noname": "escribe un nombre en el campo de texto de la izquierda antes de hacer eso :p",
|
||||
"nmd_i1": "también puedes añadir la extensión que quieras, por ejemplo <code>.txt</code>", //m
|
||||
"nmd_i2": "solo puedes crear archivos <code>.md</code> porque no tienes permiso para borrar", //m
|
||||
|
||||
"tv_load": "Cargando documento de texto:\n\n{0}\n\n{1}% ({2} de {3} MiB cargados)",
|
||||
"tv_xe1": "no se pudo cargar el archivo de texto:\n\nerror ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.swe = {
|
|||
"ot_unpost": "unpost: radera dina senaste uppladdningar, eller avbryt pågående sådana",
|
||||
"ot_bup": "bup: enkel uppladdare, stödjer t o m netscape 4.0",
|
||||
"ot_mkdir": "mkdir: skapa en ny mapp",
|
||||
"ot_md": "new-md: skapa ett nytt markdown-dokument",
|
||||
"ot_md": "new-file: skapa en ny textfil",
|
||||
"ot_msg": "msg: skicka ett meddelande till serverloggen",
|
||||
"ot_mp": "mediaspelarinställningar",
|
||||
"ot_cfg": "konfigurationsinställningar",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.swe = {
|
|||
"ot_noie": 'Var vänlig använd Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "skapa mapp",
|
||||
"ab_mkdoc": "nytt markdown-dokument",
|
||||
"ab_mkdoc": "ny textfil",
|
||||
"ab_msg": "skicka medd. till serverlogg",
|
||||
|
||||
"ay_path": "hoppa till mappar",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.swe = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopiera</a><a href="#" id="modal-ng">Ladda upp</a>',
|
||||
|
||||
"mk_noname": "skriv ett namn i fältet till vänster först :p",
|
||||
"nmd_i1": "lägg också till filändelsen du vill ha, till exempel <code>.txt</code>", //m
|
||||
"nmd_i2": "du kan bara skapa <code>.md</code>-filer eftersom du inte har borttagningsbehörighet", //m
|
||||
|
||||
"tv_load": "Laddar textfil:\n\n{0}\n\n{1}% ({2} av {3} MiB laddat)",
|
||||
"tv_xe1": "kunde ej ladda textfil:\n\nfel ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.tur = {
|
|||
"ot_unpost": "unpost: son yüklemelerinizi silin veya tamamlanmamış olanları iptal edin",
|
||||
"ot_bup": "bup: temel yükleyici, hatta netscape 4.0'ı destekler",
|
||||
"ot_mkdir": "mkdir: yeni bir dizin oluştur",
|
||||
"ot_md": "new-md: yeni bir markdown belgesi oluştur",
|
||||
"ot_md": "new-file: yeni bir metin dosyası oluştur", //m
|
||||
"ot_msg": "msg: sunucu günlüğüne bir mesaj gönder",
|
||||
"ot_mp": "medya oynatıcı seçenekleri",
|
||||
"ot_cfg": "konfigürasyon seçenekleri",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.tur = {
|
|||
"ot_noie": 'Lütfen Chrome / Firefox / Edge kullanın',
|
||||
|
||||
"ab_mkdir": "dizin oluştur",
|
||||
"ab_mkdoc": "yeni markdown belgesi",
|
||||
"ab_mkdoc": "yeni metin dosyası", //m
|
||||
"ab_msg": "sunucu günlüğüne mesaj gönder",
|
||||
|
||||
"ay_path": "klasörlere atla",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.tur = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Kopyala</a><a href="#" id="modal-ng">Yükle</a>',
|
||||
|
||||
"mk_noname": "bunu yapmadan önce soldaki boşluğa bir şeyler yazsana :p",
|
||||
"nmd_i1": "ayrıca istediğin dosya uzantısını ekleyebilirsin, örneğin <code>.txt</code>", //m
|
||||
"nmd_i2": "silme iznin olmadığı için yalnızca <code>.md</code> dosyaları oluşturabilirsin", //m
|
||||
|
||||
"tv_load": "Metin belgesi yükleniyor:\n\n{0}\n\n{1}% ({2} of {3} MiB yüklendi)",
|
||||
"tv_xe1": "metin dosyası yüklenemedi:\n\nhata ",
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Ls.ukr = {
|
|||
"ot_unpost": "скасувати: видалити недавні завантаження або перервати незавершені",
|
||||
"ot_bup": "bup: основний завантажувач, підтримує навіть netscape 4.0",
|
||||
"ot_mkdir": "mkdir: створити нову папку",
|
||||
"ot_md": "new-md: створити новий markdown документ",
|
||||
"ot_md": "new-file: створити новий текстовий файл", //m
|
||||
"ot_msg": "msg: надіслати повідомлення в лог сервера",
|
||||
"ot_mp": "налаштування медіаплеєра",
|
||||
"ot_cfg": "параметри конфігурації",
|
||||
|
|
@ -125,7 +125,7 @@ Ls.ukr = {
|
|||
"ot_noie": 'Будь ласка, використовуйте Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "створити папку",
|
||||
"ab_mkdoc": "новий markdown документ",
|
||||
"ab_mkdoc": "новий текстовий файл", //m
|
||||
"ab_msg": "надіслати повідомлення в лог сервера",
|
||||
|
||||
"ay_path": "перейти до папок",
|
||||
|
|
@ -437,6 +437,8 @@ Ls.ukr = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Скопіювати</a><a href="#" id="modal-ng">Завантажити</a>',
|
||||
|
||||
"mk_noname": "введіть ім'я в текстове поле зліва перед тим, як робити це :p",
|
||||
"nmd_i1": "ви також можете додати потрібне розширення, наприклад <code>.txt</code>", //m
|
||||
"nmd_i2": "ви можете створювати тільки файли <code>.md</code>, оскільки не маєте дозволу на видалення", //m
|
||||
|
||||
"tv_load": "Завантаження текстового документа:\n\n{0}\n\n{1}% ({2} з {3} MiB завантажено)",
|
||||
"tv_xe1": "не вдалося завантажити текстовий файл:\n\nпомилка ",
|
||||
|
|
|
|||
|
|
@ -1999,6 +1999,18 @@ function up2k_init(subtle) {
|
|||
|
||||
if (pvis.act == 'bz')
|
||||
pvis.changecard('bz');
|
||||
|
||||
var n = st.files.length - 1,
|
||||
f = n >= 0 && st.files[n];
|
||||
if (f && !f.srch) {
|
||||
var xhr = new XHR(),
|
||||
ct = 'application/x-www-form-urlencoded;charset=UTF-8';
|
||||
xhr.open('POST', f.purl, true);
|
||||
xhr.setRequestHeader('Content-Type', ct);
|
||||
if (xhr.overrideMimeType)
|
||||
xhr.overrideMimeType('Content-Type', ct);
|
||||
xhr.send('msg=upload-queue-empty;' + uricom_enc(f.name));
|
||||
}
|
||||
}
|
||||
|
||||
function chill(t) {
|
||||
|
|
@ -2671,8 +2683,6 @@ function up2k_init(subtle) {
|
|||
f2f(spd1, 2), !isNum(spd2) ? '--' : f2f(spd2, 2)));
|
||||
|
||||
pvis.move(t.n, 'ok');
|
||||
if (!pvis.ctr.bz && !pvis.ctr.q)
|
||||
uptoast();
|
||||
}
|
||||
else {
|
||||
if (t.t_uploaded)
|
||||
|
|
|
|||
|
|
@ -1487,7 +1487,7 @@ var tt = (function () {
|
|||
var r = {
|
||||
"tt": mknod("div", 'tt'),
|
||||
"th": mknod("div", 'tth'),
|
||||
"en": true,
|
||||
"en": !window.notooltips,
|
||||
"el": null,
|
||||
"skip": false,
|
||||
"lvis": 0
|
||||
|
|
|
|||
|
|
@ -1,3 +1,82 @@
|
|||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
# 2025-1025-1918 `v1.19.19` copyparty.eu マークII
|
||||
|
||||
## 🩹 bugfixes
|
||||
|
||||
* fix building the archlinux package e3524d85
|
||||
* otherwise identical to [v1.19.18](https://github.com/9001/copyparty/releases/tag/v1.19.18)
|
||||
|
||||
|
||||
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
# 2025-1025-1434 `v1.19.18` copyparty.eu
|
||||
|
||||
## 🧪 new features
|
||||
|
||||
* #949 when all uploads have finished, the client (both the browser and u2c) sends a message to the server saying it's done db87ea5c
|
||||
* #941 [copyparty-en.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty-en.pyz), yet another copyparty variant, with enterprise-friendly tweaks:
|
||||
* does not include the smb-server, so antivirus doesn't think it's malware 7f5810f1
|
||||
* english-only, because antivirus apparently hates certain translations too 7f5810f1
|
||||
* renamed the webdav-config `.bat` to `.txt` because clearly only one of those are "dangerous" b624a387
|
||||
* show volumes with permssion `h` in the navpane fff7291d
|
||||
* #937 global-option `--notooltips` to default-disable tooltips a325353b
|
||||
|
||||
## 🩹 bugfixes
|
||||
|
||||
* #948 fix the u2c `--dr` option when the server is running on windows d3dd3456
|
||||
* fix crash on startup when using volflags `unlistc*` and the parent folder is not a volume cdd5e78a
|
||||
* `og` / opengraph / discord-embed fixes:
|
||||
* using the `h` permission could result in unexpected 404 c9e45c12
|
||||
* a single-file volume could make filenames in its parent volume unintentionally visible 36ab77e0
|
||||
* this would only happen when combined with `--og`
|
||||
* fix some harmless warnings from single-file volumes b1efc006
|
||||
* fix filesize-colors in selected rows 1c17b63b
|
||||
|
||||
## 🔧 other changes
|
||||
|
||||
* releases can now also be downloaded from https://copyparty.eu/ 547a7ab1
|
||||
|
||||
|
||||
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
# 2025-1017-2313 `v1.19.17` read:cbz + re:ftp
|
||||
|
||||
## 🧪 new features
|
||||
|
||||
* #916 view cbz manga/comics in the browser (thx @Scotsguy!) 8ef6dda7
|
||||
* #845 users/groups can be subtracted from a broader access grant b4fda5f1
|
||||
* for example `*,-@acct` hides a volume from everyone who's logged in
|
||||
* [reflink dedup](https://github.com/9001/copyparty/#file-deduplication) is now available in most python versions, not just 3.14 and newer f2caab61
|
||||
* much better and safer than symlink/hardlink-based dedup, but only works with a few filesystems
|
||||
* #905 option to magnify images/videos to fill the screen 66dc8b5c
|
||||
* #921 #685 `xm` hooks can see the selected files (thx @carson-coder!) 6c024dbf 33644488
|
||||
* #927 textfiles can now be viewed with the `?doc=` suffix with just the `g` permission dbb78705
|
||||
* #742 new volflag `nodupem` to prevent dupes from being moved into a volume; the stronger alternative to `nodupe` which only prevents uploads f55d8341
|
||||
* audioplayer: show embedded coverart as fallback for cover.jpg in OS widgets 9746b4e2
|
||||
* #928 option to [hide certain ui-elements](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#hide-ui-elements), either with volflags or url-params 98da5cc5
|
||||
* #911 users can now avoid autoban according to permissions 6f02812a
|
||||
* verbosity and permssion options for `?stack` 677fd8ee
|
||||
* default is now admin-only; previously it was "admin or read+write"
|
||||
|
||||
## 🩹 bugfixes
|
||||
|
||||
* #914 ftp-server: resuming interrupted uploads (thx @Audionut!) 33b0cd5a
|
||||
* race-the-beam didn't work in non-toplevel shares d9cd7ec3
|
||||
|
||||
## 🔧 other changes
|
||||
|
||||
* #904 new example hook [wget-i.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/wget-i.py); import-safe fork of [wget.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/wget.py) dbd8f837
|
||||
* hide the search-ui while viewing a share because searching in shares is not possible cca1f9b2
|
||||
* config-parser now prevents invalid values for the lifetime volflag 5d96862c
|
||||
* translations are now [separate files](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/web/tl) instead of all chilling inside browser.js d099e5e8 d6433b78 a7840beb a7cdc5de 98086948 a85ad201 c2e03bf6 b9d7ede3 5a29df6b 52446bb5 bb166c98 0fa862e1 6de6aa4b 748aaa95 07ace416 b61b910e 28b93238 14bd4cf5 50109f76 3b009d97 f5425a88 5232ce6a 02ba9ea7 ff01723c d099e5e8
|
||||
|
||||
## 🌠 fun facts
|
||||
|
||||
* looks like i'll be in Japan november 7~26 and then at CCC for newyears!
|
||||
* wait, I never made stickers... orz
|
||||
|
||||
|
||||
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
# 2025-1005-2259 `v1.19.16` FULLBURST
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ copyparty = [
|
|||
"web/*.xml",
|
||||
"web/tl/*.js",
|
||||
"web/tl/*.gz",
|
||||
"web/a/*.bat",
|
||||
"web/a/*.txt",
|
||||
"web/a/*.gz",
|
||||
"web/deps/*.gz",
|
||||
"web/deps/*.woff*",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -33,10 +33,11 @@ i'm not very familiar with containers, so let me know if this section could be b
|
|||
|
||||
the container has the same default config as the sfx and the pypi module, meaning it will listen on port 3923 and share the "current folder" (`/w` inside the container) as read-write for anyone
|
||||
|
||||
the recommended way to configure copyparty inside a container is to mount a folder which has one or more [config files](https://github.com/9001/copyparty/blob/hovudstraum/docs/example.conf) inside; `-v /your/config/folder:/cfg`
|
||||
the recommended way to configure copyparty inside a container is to mount a folder which has one or more [config files](https://github.com/9001/copyparty/blob/hovudstraum/docs/examples/docker/basic-docker-compose/copyparty.conf) inside; `-v /your/config/folder:/cfg`
|
||||
|
||||
* but you can also provide arguments to the docker command if you prefer that
|
||||
* config files must be named `something.conf` to get picked up
|
||||
* there are [more extensive config examples](https://github.com/9001/copyparty/blob/hovudstraum/docs/example.conf) but those are not made for docker so the paths are wrong (`/home/ed/Music` should be `/w/something` and so on)
|
||||
|
||||
also see [docker-specific recommendations](#docker-specific-recommendations)
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@ filt=
|
|||
wget https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py -O $fp
|
||||
}
|
||||
|
||||
# enable arm32 crossbuild from aarch64 (macbook or whatever)
|
||||
[ $(uname -m) = aarch64 ] && [ ! -e /proc/sys/fs/binfmt_misc/qemu-arm ] &&
|
||||
echo ":qemu-arm:M:0:\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:F" |
|
||||
sudo tee >/dev/null /proc/sys/fs/binfmt_misc/register
|
||||
|
||||
# kill abandoned builders
|
||||
ps aux | awk '/bin\/qemu-[^-]+-static/{print$2}' | xargs -r kill -9
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ gtar=$(command -v gtar || command -v gnutar) || true
|
|||
sed() { gsed "$@"; }
|
||||
find() { gfind "$@"; }
|
||||
sort() { gsort "$@"; }
|
||||
nproc() { gnproc; }
|
||||
command -v grealpath >/dev/null &&
|
||||
realpath() { grealpath "$@"; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,10 @@ rm -rf pyz
|
|||
mkdir -p pyz
|
||||
cd pyz
|
||||
|
||||
cp -pR ../sfx/{copyparty,partftpy} .
|
||||
cp -pR ../sfx/{ftp,j2}/* .
|
||||
cp -pR ../sfx/copyparty .
|
||||
cp -pR ../sfx/j2/* .
|
||||
[ -e ../sfx/partftpy ] && cp -pR ../sfx/partftpy .
|
||||
[ -e ../sfx/ftp ] && cp -pR ../sfx/ftp/* .
|
||||
|
||||
true && {
|
||||
rm -rf copyparty/web/mde.* copyparty/web/deps/easymde*
|
||||
|
|
|
|||
|
|
@ -445,14 +445,27 @@ iawk '/^class _Base/{s=1}!s' ftp/pyftpdlib/authorizers.py
|
|||
iawk '/^ {0,4}[a-zA-Z]/{s=0}/^ {4}def (serve_forever|_loop)/{s=1}!s' ftp/pyftpdlib/servers.py
|
||||
rm -f ftp/pyftpdlib/{__main__,prefork}.py
|
||||
|
||||
[ $no_ftp ] &&
|
||||
unhelp() {
|
||||
iawk '!/add_argument\("--'$1'/{print;next}
|
||||
/ent\("--'$1'"/{print gensub(/(help=")[^"]+/,"\\1not available in this build","1");next}
|
||||
{sub(/help=.*/,"help=argparse.SUPPRESS)")}1' copyparty/__main__.py
|
||||
}
|
||||
|
||||
[ $no_ftp ] && {
|
||||
unhelp ftp
|
||||
rm -rf copyparty/ftpd.py ftp
|
||||
}
|
||||
|
||||
[ $no_tfp ] &&
|
||||
[ $no_tfp ] && {
|
||||
unhelp tftp
|
||||
rm -rf copyparty/tftpd.py partftpy
|
||||
}
|
||||
|
||||
[ $no_smb ] &&
|
||||
[ $no_smb ] && {
|
||||
unhelp smb
|
||||
rm -f copyparty/smbd.py
|
||||
ised 's/^( {8}elif )record\.name.*"impacket".*/\10:/' copyparty/util.py
|
||||
}
|
||||
|
||||
[ $no_zm ] &&
|
||||
rm -rf copyparty/mdns.py copyparty/stolen/dnslib
|
||||
|
|
@ -571,7 +584,7 @@ gzres() {
|
|||
$pk "$f" &
|
||||
done < <(
|
||||
find -printf '%s %p\n' |
|
||||
grep -E '\.(js|css)$' |
|
||||
grep -E '\.(js|css)$|/web/a/.*\.txt$' |
|
||||
grep -vF /deps/ |
|
||||
sort -nr
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ set -e
|
|||
# general housekeeping before a release
|
||||
|
||||
self=$(cd -- "$(dirname "$BASH_SOURCE")"; pwd -P)
|
||||
ver=$(awk '/^VERSION/{gsub(/[^0-9]/," ");printf "%d.%d.%d\n",$1,$2,$3}' copyparty/__version__.py)
|
||||
ver=$(awk '/^VERSION/{gsub(/[^0-9]/," ");printf "%d.%d.%d\n",$1,$2,$3}' $self/../copyparty/__version__.py)
|
||||
|
||||
update_arch_pkgbuild() {
|
||||
cd "$self/../contrib/package/arch"
|
||||
|
|
|
|||
|
|
@ -49,14 +49,23 @@ while [ "$1" ]; do
|
|||
done
|
||||
|
||||
./make-pyz.sh
|
||||
mv ../dist/copyparty{,-int}.pyz
|
||||
|
||||
./make-sfx.sh re lang eng "$@"
|
||||
mv ../dist/copyparty-{sfx,en}.py
|
||||
|
||||
rm -rf /tmp/pe-copyparty* ../sfx
|
||||
../dist/copyparty-en.py --version >/dev/null 2>&1
|
||||
|
||||
./make-sfx.sh re no-smb "$@"
|
||||
./make-pyz.sh
|
||||
mv ../dist/copyparty{,-en}.pyz
|
||||
mv ../dist/copyparty{-int,}.pyz
|
||||
mv ../dist/copyparty-{int,sfx}.py
|
||||
|
||||
./genhelp.sh
|
||||
|
||||
[ $rls ] || exit # ----------------------------------------------------
|
||||
[ $rls ] || exit 0 # ----------------------------------------------------
|
||||
|
||||
./prep.sh
|
||||
git add ../contrib/package/arch/PKGBUILD ../contrib/package/makedeb-mpr/PKGBUILD ../contrib/package/nix/copyparty/pin.json
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ copyparty/web/a,
|
|||
copyparty/web/a/__init__.py,
|
||||
copyparty/web/a/partyfuse.py,
|
||||
copyparty/web/a/u2c.py,
|
||||
copyparty/web/a/webdav-cfg.bat,
|
||||
copyparty/web/a/webdav-cfg.txt,
|
||||
copyparty/web/baguettebox.js,
|
||||
copyparty/web/browser.css,
|
||||
copyparty/web/browser.html,
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ Ls.hmn = {
|
|||
"ot_unpost": "unpost: delete your recent uploads, or abort unfinished ones",
|
||||
"ot_bup": "bup: basic uploader, even supports netscape 4.0",
|
||||
"ot_mkdir": "mkdir: create a new directory",
|
||||
"ot_md": "new-md: create a new markdown document",
|
||||
"ot_md": "new-file: create a new textfile",
|
||||
"ot_msg": "msg: send a message to the server log",
|
||||
"ot_mp": "media player options",
|
||||
"ot_cfg": "configuration options",
|
||||
|
|
@ -154,7 +154,7 @@ Ls.hmn = {
|
|||
"ot_noie": 'Please use Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "make directory",
|
||||
"ab_mkdoc": "new markdown doc",
|
||||
"ab_mkdoc": "new textfile",
|
||||
"ab_msg": "send msg to srv log",
|
||||
|
||||
"ay_path": "skip to folders",
|
||||
|
|
@ -466,6 +466,8 @@ Ls.hmn = {
|
|||
"fcp_both_b": '<a href="#" id="modal-ok">Copy</a><a href="#" id="modal-ng">Upload</a>',
|
||||
|
||||
"mk_noname": "type a name into the text field on the left before you do that :p",
|
||||
"nmd_i1": "also add the file extension you want, for example <code>.md</code>",
|
||||
"nmd_i2": "you can only create <code>.md</code> files because you don't have the delete-permission",
|
||||
|
||||
"tv_load": "Loading text document:\n\n{0}\n\n{1}% ({2} of {3} MiB loaded)",
|
||||
"tv_xe1": "could not load textfile:\n\nerror ",
|
||||
|
|
|
|||
|
|
@ -187,9 +187,9 @@ class TestVFS(unittest.TestCase):
|
|||
self.assertEqual(n.realpath, os.path.join(td, "a"))
|
||||
self.assertAxs(n.axs.uread, ["*", "k"])
|
||||
self.assertAxs(n.axs.uwrite, [])
|
||||
perm_na = (False, False, False, False, False, False, False, False)
|
||||
perm_rw = (True, True, False, False, False, False, False, False)
|
||||
perm_ro = (True, False, False, False, False, False, False, False)
|
||||
perm_na = (False, False, False, False, False, False, False, False, False)
|
||||
perm_rw = (True, True, False, False, False, False, False, False, False)
|
||||
perm_ro = (True, False, False, False, False, False, False, False, False)
|
||||
self.assertEqual(vfs.can_access("/", "*"), perm_na)
|
||||
self.assertEqual(vfs.can_access("/", "k"), perm_rw)
|
||||
self.assertEqual(vfs.can_access("/a", "*"), perm_ro)
|
||||
|
|
|
|||
Loading…
Reference in a new issue