mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
Merge branch 'hovudstraum' into hovudstraum
Signed-off-by: ed <s@ocv.me>
This commit is contained in:
commit
99bf800b73
26
README.md
26
README.md
|
@ -437,6 +437,7 @@ upgrade notes
|
|||
|
||||
* can I link someone to a password-protected volume/file by including the password in the URL?
|
||||
* yes, by adding `?pw=hunter2` to the end; replace `?` with `&` if there are parameters in the URL already, meaning it contains a `?` near the end
|
||||
* if you have enabled `--accounts` then do `?pw=username:password` instead
|
||||
|
||||
* how do I stop `.hist` folders from appearing everywhere on my HDD?
|
||||
* by default, a `.hist` folder is created inside each volume for the filesystem index, thumbnails, audio transcodes, and markdown document history. Use the `--hist` global-option or the `hist` volflag to move it somewhere else; see [database location](#database-location)
|
||||
|
@ -1016,6 +1017,7 @@ a feed example: https://cd.ocv.me/a/d2/d22/?rss&fext=mp3
|
|||
url parameters:
|
||||
|
||||
* `pw=hunter2` for password auth
|
||||
* if you enabled `--usernames` then do `pw=username:password` instead
|
||||
* `recursive` to also include subfolders
|
||||
* `title=foo` changes the feed title (default: folder name)
|
||||
* `fext=mp3,opus` only include mp3 and opus files (default: all)
|
||||
|
@ -1301,6 +1303,7 @@ an FTP server can be started using `--ftp 3921`, and/or `--ftps` for explicit T
|
|||
* if you enable both `ftp` and `ftps`, the port-range will be divided in half
|
||||
* some older software (filezilla on debian-stable) cannot passive-mode with TLS
|
||||
* login with any username + your password, or put your password in the username field
|
||||
* unless you enabled `--usernames`
|
||||
|
||||
some recommended FTP / FTPS clients; `wark` = example password:
|
||||
* https://winscp.net/eng/download.php
|
||||
|
@ -1318,6 +1321,7 @@ click the [connect](http://127.0.0.1:3923/?hc) button in the control-panel to se
|
|||
|
||||
general usage:
|
||||
* login with any username + your password, or put your password in the username field (password field can be empty/whatever)
|
||||
* unless you enabled `--usernames`
|
||||
|
||||
on macos, connect from finder:
|
||||
* [Go] -> [Connect to Server...] -> http://192.168.123.1:3923/
|
||||
|
@ -1333,6 +1337,7 @@ using the GUI (winXP or later):
|
|||
* rightclick [my computer] -> [map network drive] -> Folder: `http://192.168.123.1:3923/`
|
||||
* on winXP only, click the `Sign up for online storage` hyperlink instead and put the URL there
|
||||
* providing your password as the username is recommended; the password field can be anything or empty
|
||||
* unless you enabled `--usernames`
|
||||
|
||||
the webdav client that's built into windows has the following list of bugs; you can avoid all of these by connecting with rclone instead:
|
||||
* win7+ doesn't actually send the password to the server when reauthenticating after a reboot unless you first try to login with an incorrect password and then switch to the correct password
|
||||
|
@ -1390,6 +1395,7 @@ some **BIG WARNINGS** specific to SMB/CIFS, in decreasing importance:
|
|||
* the smb backend is not fully integrated with vfs, meaning there could be security issues (path traversal). Please use `--smb-port` (see below) and [prisonparty](./bin/prisonparty.sh) or [bubbleparty](./bin/bubbleparty.sh)
|
||||
* account passwords work per-volume as expected, and so does account permissions (read/write/move/delete), but `--smbw` must be given to allow write-access from smb
|
||||
* [shadowing](#shadowing) probably works as expected but no guarantees
|
||||
* not compatible with pw-hashing or `--usernames`
|
||||
|
||||
and some minor issues,
|
||||
* clients only see the first ~400 files in big folders;
|
||||
|
@ -2058,7 +2064,11 @@ you can either:
|
|||
* or do location-based proxying, using `--rp-loc=/stuff` to tell copyparty where it is mounted -- has a slight performance cost and higher chance of bugs
|
||||
* if copyparty says `incorrect --rp-loc or webserver config; expected vpath starting with [...]` it's likely because the webserver is stripping away the proxy location from the request URLs -- see the `ProxyPass` in the apache example below
|
||||
|
||||
when running behind a reverse-proxy (this includes services like cloudflare), it is important to configure real-ip correctly, as many features rely on knowing the client's IP. Look out for red and yellow log messages which explain how to do this. But basically, set `--xff-hdr` to the name of the http header to read the IP from (usually `x-forwarded-for`, but cloudflare uses `cf-connecting-ip`), and then `--xff-src` to the IP of the reverse-proxy so copyparty will trust the xff-hdr. Note that `--rp-loc` in particular will not work at all unless you do this
|
||||
when running behind a reverse-proxy (this includes services like cloudflare), it is important to configure real-ip correctly, as many features rely on knowing the client's IP. The best/safest approach is to configure your reverse-proxy so it gives copyparty a header which only contains the client's true/real IP-address, and then setting `--xff-hdr theHeaderName --rproxy 1` but alternatively, if you want/need to let copyparty handle this, look out for red and yellow log messages which explain how to do that. Basically, the log will say this:
|
||||
|
||||
> set `--xff-hdr` to the name of the http-header to read the IP from (usually `x-forwarded-for`, but cloudflare uses `cf-connecting-ip`), and then `--xff-src` to the IP of the reverse-proxy so copyparty will trust the xff-hdr. You will also need to configure `--rproxy` to `1` if the header only contains one IP (the correct one) or to a *negative value* if it contains multiple; `-1` being the rightmost and most trusted IP (the nearest proxy, so usually not the correct one), `-2` being the second-closest hop, and so on
|
||||
|
||||
Note that `--rp-loc` in particular will not work at all unless you configure the above correctly
|
||||
|
||||
some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which *could* be a nice speed boost, depending on a lot of factors
|
||||
* **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
|
||||
|
@ -2277,11 +2287,9 @@ if your distro/OS is not mentioned below, there might be some hints in the [«on
|
|||
|
||||
`pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
||||
|
||||
it comes with a [systemd service](./contrib/package/arch/copyparty.service) and expects to find one or more [config files](./docs/example.conf) in `/etc/copyparty.d/`
|
||||
it comes with a [systemd service](./contrib/systemd/copyparty@.service) as well as a [user service](./contrib/systemd/copyparty-user.service), and expects to find a [config file](./contrib/systemd/copyparty.example.conf) in `/etc/copyparty/copyparty.conf` or `~/.config/copyparty/copyparty.conf`
|
||||
|
||||
after installing it, you may want to `cp /usr/lib/systemd/system/copyparty.service /etc/systemd/system/` and then `vim /etc/systemd/system/copyparty.service` to change what user/group it is running as (you only need to do this once)
|
||||
|
||||
NOTE: there used to be an aur package; this evaporated when copyparty was adopted by the official archlinux repos. If you're still using the aur package, please move
|
||||
after installing, start either the system service or the user service and navigate to http://127.0.0.1:3923 for further instructions (unless you already edited the config files, in which case you are good to go, probably)
|
||||
|
||||
|
||||
## fedora package
|
||||
|
@ -2504,6 +2512,8 @@ you can provide passwords using header `PW: hunter2`, cookie `cppwd=hunter2`, ur
|
|||
|
||||
> for basic-authentication, all of the following are accepted: `password` / `whatever:password` / `password:whatever` (the username is ignored)
|
||||
|
||||
* unless you've enabled `--usernames`, then it's `PW: usr:pwd`, cookie `cppwd=usr:pwd`, url-param `?pw=usr:pwd`
|
||||
|
||||
NOTE: curl will not send the original filename if you use `-T` combined with url-params! Also, make sure to always leave a trailing slash in URLs unless you want to override the filename
|
||||
|
||||
|
||||
|
@ -2615,7 +2625,7 @@ there is a [discord server](https://discord.gg/25J8CdTT6G) with an `@everyone`
|
|||
|
||||
some notes on hardening
|
||||
|
||||
* set `--rproxy 0` if your copyparty is directly facing the internet (not through a reverse-proxy)
|
||||
* set `--rproxy 0` *if and only if* your copyparty is directly facing the internet (not through a reverse-proxy)
|
||||
* cors doesn't work right otherwise
|
||||
* if you allow anonymous uploads or otherwise don't trust the contents of a volume, you can prevent XSS with volflag `nohtml`
|
||||
* this returns html documents as plaintext, and also disables markdown rendering
|
||||
|
@ -2719,6 +2729,8 @@ when generating hashes using `--ah-cli` for docker or systemd services, make sur
|
|||
* inspecting the generated salt using `--show-ah-salt` in copyparty service configuration
|
||||
* setting the same `--ah-salt` in both environments
|
||||
|
||||
> ⚠️ if you have enabled `--usernames` then provide the password as `username:password` when hashing it, for example `ed:hunter2`
|
||||
|
||||
|
||||
## https
|
||||
|
||||
|
@ -2836,6 +2848,8 @@ these are standalone programs and will never be imported / evaluated by copypart
|
|||
|
||||
the self-contained "binary" (recommended!) [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
|
||||
|
||||
if you only need english, [copyparty-en.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-en.py) is the same thing but smaller
|
||||
|
||||
you can reduce the sfx size by repacking it; see [./docs/devnotes.md#sfx-repack](./docs/devnotes.md#sfx-repack)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# Maintainer: icxes <dev.null@need.moe>
|
||||
# Contributor: Morgan Adamiec <morganamilo@archlinux.org>
|
||||
# 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.18.10"
|
||||
pkgrel=1
|
||||
|
@ -6,52 +9,40 @@ pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFT
|
|||
arch=("any")
|
||||
url="https://github.com/9001/${pkgname}"
|
||||
license=('MIT')
|
||||
depends=("python" "lsof" "python-jinja")
|
||||
depends=("bash" "python" "lsof" "python-jinja")
|
||||
makedepends=("python-wheel" "python-setuptools" "python-build" "python-installer" "make" "pigz")
|
||||
optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tags"
|
||||
"cfssl: generate TLS certificates on startup (pointless when reverse-proxied)"
|
||||
"cfssl: generate TLS certificates on startup"
|
||||
"python-mutagen: music tags (alternative)"
|
||||
"python-pillow: thumbnails for images"
|
||||
"python-pyvips: thumbnails for images (higher quality, faster, uses more ram)"
|
||||
"libkeyfinder-git: detection of musical keys"
|
||||
"qm-vamp-plugins: BPM detection"
|
||||
"libkeyfinder: detection of musical keys"
|
||||
"python-pyopenssl: ftps functionality"
|
||||
"python-pyzmq: send zeromq messages from event-hooks"
|
||||
"python-argon2-cffi: hashed passwords in config"
|
||||
"python-impacket-git: smb support (bad idea)"
|
||||
)
|
||||
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||
backup=("etc/${pkgname}.d/init" )
|
||||
backup=("etc/${pkgname}/copyparty.conf" )
|
||||
sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99")
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
||||
make
|
||||
|
||||
cd "${srcdir}/${pkgname}-${pkgver}"
|
||||
|
||||
pushd copyparty/web
|
||||
make -j$(nproc)
|
||||
rm Makefile
|
||||
popd
|
||||
|
||||
python3 -m build -wn
|
||||
python -m build --wheel --no-isolation
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname}-${pkgver}"
|
||||
python3 -m installer -d "$pkgdir" dist/*.whl
|
||||
python -m installer --destdir="$pkgdir" dist/*.whl
|
||||
|
||||
install -dm755 "${pkgdir}/etc/${pkgname}.d"
|
||||
install -dm755 "${pkgdir}/etc/${pkgname}"
|
||||
install -Dm755 "bin/prisonparty.sh" "${pkgdir}/usr/bin/prisonparty"
|
||||
install -Dm644 "contrib/package/arch/${pkgname}.conf" "${pkgdir}/etc/${pkgname}.d/init"
|
||||
install -Dm644 "contrib/package/arch/${pkgname}.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}.service"
|
||||
install -Dm644 "contrib/package/arch/prisonparty.service" "${pkgdir}/usr/lib/systemd/system/prisonparty.service"
|
||||
install -Dm644 "contrib/package/arch/index.md" "${pkgdir}/var/lib/${pkgname}-jail/README.md"
|
||||
install -Dm644 "contrib/systemd/${pkgname}.conf" "${pkgdir}/etc/${pkgname}/copyparty.conf"
|
||||
install -Dm644 "contrib/systemd/${pkgname}@.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}@.service"
|
||||
install -Dm644 "contrib/systemd/${pkgname}-user.service" "${pkgdir}/usr/lib/systemd/user/${pkgname}.service"
|
||||
install -Dm644 "contrib/systemd/prisonparty@.service" "${pkgdir}/usr/lib/systemd/system/prisonparty@.service"
|
||||
install -Dm644 "contrib/systemd/index.md" "${pkgdir}/var/lib/${pkgname}-jail/README.md"
|
||||
install -Dm644 "LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
|
||||
find /etc/${pkgname}.d -iname '*.conf' 2>/dev/null | grep -qE . && return
|
||||
echo "┏━━━━━━━━━━━━━━━──-"
|
||||
echo "┃ Configure ${pkgname} by adding .conf files into /etc/${pkgname}.d/"
|
||||
echo "┃ and maybe copy+edit one of the following to /etc/systemd/system/:"
|
||||
echo "┣━♦ /usr/lib/systemd/system/${pkgname}.service (standard)"
|
||||
echo "┣━♦ /usr/lib/systemd/system/prisonparty.service (chroot)"
|
||||
echo "┗━━━━━━━━━━━━━━━──-"
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
## import all *.conf files from the current folder (/etc/copyparty.d)
|
||||
% ./
|
||||
|
||||
# add additional .conf files to this folder;
|
||||
# see example config files for reference:
|
||||
# https://github.com/9001/copyparty/blob/hovudstraum/docs/example.conf
|
||||
# https://github.com/9001/copyparty/tree/hovudstraum/docs/copyparty.d
|
|
@ -1,32 +0,0 @@
|
|||
# this will start `/usr/bin/copyparty-sfx.py`
|
||||
# and read config from `/etc/copyparty.d/*.conf`
|
||||
#
|
||||
# you probably want to:
|
||||
# change "User=cpp" and "/home/cpp/" to another user
|
||||
#
|
||||
# unless you add -q to disable logging, you may want to remove the
|
||||
# following line to allow buffering (slightly better performance):
|
||||
# Environment=PYTHONUNBUFFERED=x
|
||||
|
||||
[Unit]
|
||||
Description=copyparty file server
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
SyslogIdentifier=copyparty
|
||||
Environment=PYTHONUNBUFFERED=x
|
||||
WorkingDirectory=/var/lib/copyparty-jail
|
||||
ExecReload=/bin/kill -s USR1 $MAINPID
|
||||
|
||||
# user to run as + where the TLS certificate is (if any)
|
||||
User=cpp
|
||||
Environment=XDG_CONFIG_HOME=/home/cpp/.config
|
||||
|
||||
# stop systemd-tmpfiles-clean.timer from deleting copyparty while it's running
|
||||
ExecStartPre=+/bin/bash -c 'mkdir -p /run/tmpfiles.d/ && echo "x /tmp/pe-copyparty*" > /run/tmpfiles.d/copyparty.conf'
|
||||
|
||||
# run copyparty
|
||||
ExecStart=/usr/bin/python3 /usr/bin/copyparty -c /etc/copyparty.d/init
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,3 +0,0 @@
|
|||
this is `/var/lib/copyparty-jail`, the fallback webroot when copyparty has not yet been configured
|
||||
|
||||
please add some `*.conf` files to `/etc/copyparty.d/`
|
26
contrib/systemd/copyparty-user.service
Normal file
26
contrib/systemd/copyparty-user.service
Normal file
|
@ -0,0 +1,26 @@
|
|||
# this will start `/usr/bin/copyparty`
|
||||
# and read config from `$HOME/.config/copyparty.conf`
|
||||
#
|
||||
# unless you add -q to disable logging, you may want to remove the
|
||||
# following line to allow buffering (slightly better performance):
|
||||
# Environment=PYTHONUNBUFFERED=x
|
||||
|
||||
[Unit]
|
||||
Description=copyparty file server
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
SyslogIdentifier=copyparty
|
||||
WorkingDirectory=/var/lib/copyparty-jail
|
||||
Environment=PYTHONUNBUFFERED=x
|
||||
Environment=PRTY_CONFIG=%h/.config/copyparty/copyparty.conf
|
||||
ExecReload=/bin/kill -s USR1 $MAINPID
|
||||
|
||||
# ensure there is a config
|
||||
ExecStartPre=/bin/bash -c 'if [[ ! -f %h/.config/copyparty/copyparty.conf ]]; then mkdir -p %h/.config/copyparty; cp /etc/copyparty/copyparty.conf %h/.config/copyparty/copyparty.conf; fi'
|
||||
|
||||
# run copyparty
|
||||
ExecStart=/usr/bin/python3 /usr/bin/copyparty
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
|
@ -1,42 +1,13 @@
|
|||
# not actually YAML but lets pretend:
|
||||
# -*- mode: yaml -*-
|
||||
# vim: ft=yaml:
|
||||
|
||||
|
||||
# put this file in /etc/
|
||||
|
||||
|
||||
[global]
|
||||
e2dsa # enable file indexing and filesystem scanning
|
||||
e2ts # and enable multimedia indexing
|
||||
ansi # and colors in log messages
|
||||
|
||||
# disable logging to stdout/journalctl and log to a file instead;
|
||||
# $LOGS_DIRECTORY is usually /var/log/copyparty (comes from systemd)
|
||||
# and copyparty replaces %Y-%m%d with Year-MonthDay, so the
|
||||
# full path will be something like /var/log/copyparty/2023-1130.txt
|
||||
# (note: enable compression by adding .xz at the end)
|
||||
q, lo: $LOGS_DIRECTORY/%Y-%m%d.log
|
||||
|
||||
# p: 80,443,3923 # listen on 80/443 as well (requires CAP_NET_BIND_SERVICE)
|
||||
# i: 127.0.0.1 # only allow connections from localhost (reverse-proxies)
|
||||
# ftp: 3921 # enable ftp server on port 3921
|
||||
# p: 3939 # listen on another port
|
||||
# df: 16 # stop accepting uploads if less than 16 GB free disk space
|
||||
# ver # show copyparty version in the controlpanel
|
||||
# grid # show thumbnails/grid-view by default
|
||||
# theme: 2 # monokai
|
||||
# name: datasaver # change the server-name that's displayed in the browser
|
||||
# stats, nos-dup # enable the prometheus endpoint, but disable the dupes counter (too slow)
|
||||
# no-robots, force-js # make it harder for search engines to read your server
|
||||
|
||||
i: 127.0.0.1
|
||||
|
||||
[accounts]
|
||||
ed: wark # username: password
|
||||
user: password
|
||||
|
||||
|
||||
[/] # create a volume at "/" (the webroot), which will
|
||||
/mnt # share the contents of the "/mnt" folder
|
||||
[/]
|
||||
/var/lib/copyparty-jail
|
||||
accs:
|
||||
rw: * # everyone gets read-write access, but
|
||||
rwmda: ed # the user "ed" gets read-write-move-delete-admin
|
||||
r: *
|
||||
rwdma: user
|
||||
flags:
|
||||
grid
|
42
contrib/systemd/copyparty.example.conf
Normal file
42
contrib/systemd/copyparty.example.conf
Normal file
|
@ -0,0 +1,42 @@
|
|||
# not actually YAML but lets pretend:
|
||||
# -*- mode: yaml -*-
|
||||
# vim: ft=yaml:
|
||||
|
||||
|
||||
# put this file in /etc/
|
||||
|
||||
|
||||
[global]
|
||||
e2dsa # enable file indexing and filesystem scanning
|
||||
e2ts # and enable multimedia indexing
|
||||
ansi # and colors in log messages
|
||||
|
||||
# disable logging to stdout/journalctl and log to a file instead;
|
||||
# $LOGS_DIRECTORY is usually /var/log/copyparty (comes from systemd)
|
||||
# and copyparty replaces %Y-%m%d with Year-MonthDay, so the
|
||||
# full path will be something like /var/log/copyparty/2023-1130.txt
|
||||
# (note: enable compression by adding .xz at the end)
|
||||
q, lo: $LOGS_DIRECTORY/%Y-%m%d.log
|
||||
|
||||
# p: 80,443,3923 # listen on 80/443 as well (requires CAP_NET_BIND_SERVICE)
|
||||
# i: 127.0.0.1 # only allow connections from localhost (reverse-proxies)
|
||||
# ftp: 3921 # enable ftp server on port 3921
|
||||
# p: 3939 # listen on another port
|
||||
# df: 16 # stop accepting uploads if less than 16 GB free disk space
|
||||
# ver # show copyparty version in the controlpanel
|
||||
# grid # show thumbnails/grid-view by default
|
||||
# theme: 2 # monokai
|
||||
# name: datasaver # change the server-name that's displayed in the browser
|
||||
# stats, nos-dup # enable the prometheus endpoint, but disable the dupes counter (too slow)
|
||||
# no-robots, force-js # make it harder for search engines to read your server
|
||||
|
||||
|
||||
[accounts]
|
||||
ed: wark # username: password
|
||||
|
||||
|
||||
[/] # create a volume at "/" (the webroot), which will
|
||||
/mnt # share the contents of the "/mnt" folder
|
||||
accs:
|
||||
rw: * # everyone gets read-write access, but
|
||||
rwmda: ed # the user "ed" gets read-write-move-delete-admin
|
30
contrib/systemd/copyparty@.service
Normal file
30
contrib/systemd/copyparty@.service
Normal file
|
@ -0,0 +1,30 @@
|
|||
# this will start `/usr/bin/copyparty`
|
||||
# and read config from `/etc/copyparty/copyparty.conf`
|
||||
#
|
||||
# the %i refers to whatever you put after the copyparty@
|
||||
# so with copyparty@foo.service, %i == foo
|
||||
#
|
||||
# unless you add -q to disable logging, you may want to remove the
|
||||
# following line to allow buffering (slightly better performance):
|
||||
# Environment=PYTHONUNBUFFERED=x
|
||||
|
||||
[Unit]
|
||||
Description=copyparty file server
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
SyslogIdentifier=copyparty
|
||||
WorkingDirectory=/var/lib/copyparty-jail
|
||||
Environment=PYTHONUNBUFFERED=x
|
||||
Environment=PRTY_CONFIG=/etc/copyparty/copyparty.conf
|
||||
ExecReload=/bin/kill -s USR1 $MAINPID
|
||||
|
||||
# user to run as + where the TLS certificate is (if any)
|
||||
User=%i
|
||||
Environment=XDG_CONFIG_HOME=/home/%i/.config
|
||||
|
||||
# run copyparty
|
||||
ExecStart=/usr/bin/python3 /usr/bin/copyparty
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
10
contrib/systemd/index.md
Normal file
10
contrib/systemd/index.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
this is `/var/lib/copyparty-jail`, the fallback webroot when copyparty has not yet been configured
|
||||
|
||||
please edit `/etc/copyparty/copyparty.conf` (if running as a system service)
|
||||
or `$HOME/.config/copyparty/copyparty.conf` if running as a user service
|
||||
|
||||
a basic configuration example is available at https://github.com/9001/copyparty/blob/hovudstraum/contrib/systemd/copyparty.example.conf
|
||||
a configuration example that explains most flags is available at https://github.com/9001/copyparty/blob/hovudstraum/docs/chungus.conf
|
||||
|
||||
the full list of configuration options can be seen at https://ocv.me/copyparty/helptext.html
|
||||
or by running `copyparty --help`
|
|
@ -1,11 +1,13 @@
|
|||
# this will start `/usr/bin/copyparty-sfx.py`
|
||||
# this will start `/usr/bin/copyparty`
|
||||
# in a chroot, preventing accidental access elsewhere,
|
||||
# and read copyparty config from `/etc/copyparty.d/*.conf`
|
||||
# and read copyparty config from `/etc/copyparty/copyparty.conf`
|
||||
#
|
||||
# expose additional filesystem locations to copyparty
|
||||
# by listing them between the last `cpp` and `--`
|
||||
# by listing them between the last `%i` and `--`
|
||||
#
|
||||
# `cpp cpp` = user/group to run copyparty as; can be IDs (1000 1000)
|
||||
# `%i %i` = user/group to run copyparty as; can be IDs (1000 1000)
|
||||
# the %i refers to whatever you put after the prisonparty@
|
||||
# so with prisonparty@foo.service, %i == foo
|
||||
#
|
||||
# unless you add -q to disable logging, you may want to remove the
|
||||
# following line to allow buffering (slightly better performance):
|
||||
|
@ -15,19 +17,22 @@
|
|||
Description=copyparty file server
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
SyslogIdentifier=prisonparty
|
||||
Environment=PYTHONUNBUFFERED=x
|
||||
WorkingDirectory=/var/lib/copyparty-jail
|
||||
Environment=PYTHONUNBUFFERED=x
|
||||
Environment=PRTY_CONFIG=/etc/copyparty/copyparty.conf
|
||||
ExecReload=/bin/kill -s USR1 $MAINPID
|
||||
|
||||
# stop systemd-tmpfiles-clean.timer from deleting copyparty while it's running
|
||||
ExecStartPre=+/bin/bash -c 'mkdir -p /run/tmpfiles.d/ && echo "x /tmp/pe-copyparty*" > /run/tmpfiles.d/copyparty.conf'
|
||||
# user to run as + where the TLS certificate is (if any)
|
||||
User=%i
|
||||
Environment=XDG_CONFIG_HOME=/home/%i/.config
|
||||
|
||||
# run copyparty
|
||||
ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail cpp cpp \
|
||||
/etc/copyparty.d \
|
||||
ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail %i %i \
|
||||
/etc/copyparty \
|
||||
-- \
|
||||
/usr/bin/python3 /usr/bin/copyparty -c /etc/copyparty.d/init
|
||||
/usr/bin/python3 /usr/bin/copyparty
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -536,7 +536,7 @@ def get_sects():
|
|||
dedent(
|
||||
"""
|
||||
\033[33m-i\033[0m takes a comma-separated list of interfaces to listen on;
|
||||
IP-addresses and/or unix-sockets (Unix Domain Sockets)
|
||||
IP-addresses, unix-sockets, and/or open file descriptors
|
||||
|
||||
the default (\033[32m-i ::\033[0m) means all IPv4 and IPv6 addresses
|
||||
|
||||
|
@ -562,7 +562,9 @@ def get_sects():
|
|||
\033[32m-i unix:\033[33m/dev/shm/party.sock\033[0m keeps umask-defined permission
|
||||
(usually \033[33m0600\033[0m) and the same user/group as copyparty
|
||||
|
||||
\033[33m-p\033[0m (tcp ports) is ignored for unix sockets
|
||||
\033[32m-i fd:\033[33m3\033[0m uses the socket passed to copyparty on file descriptor 3
|
||||
|
||||
\033[33m-p\033[0m (tcp ports) is ignored for unix-sockets and FDs
|
||||
"""
|
||||
),
|
||||
],
|
||||
|
@ -916,6 +918,9 @@ def get_sects():
|
|||
copyparty will also hash and print any passwords that are non-hashed
|
||||
(password which do not start with '+') and then terminate afterwards
|
||||
|
||||
if you have enabled --accounts then the password
|
||||
must be provided as username:password for hashing
|
||||
|
||||
\033[36m--ah-alg\033[0m specifies the hashing algorithm and a
|
||||
list of optional comma-separated arguments:
|
||||
|
||||
|
@ -993,18 +998,19 @@ def build_flags_desc():
|
|||
|
||||
|
||||
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="add config file")
|
||||
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="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="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="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]")
|
||||
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]")
|
||||
ap2.add_argument("--usernames", action="store_true", help="require username and password for login; default is just password")
|
||||
ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)")
|
||||
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
|
||||
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
|
||||
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
||||
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
||||
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("--license", action="store_true", help="show licenses and exit")
|
||||
|
@ -1012,7 +1018,7 @@ def add_general(ap, nc, srvname):
|
|||
|
||||
|
||||
def add_qr(ap, tty):
|
||||
ap2 = ap.add_argument_group('qr options')
|
||||
ap2 = ap.add_argument_group("qr options")
|
||||
ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup")
|
||||
ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup")
|
||||
ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]")
|
||||
|
@ -1034,7 +1040,7 @@ def add_fs(ap):
|
|||
|
||||
def add_share(ap):
|
||||
db_path = os.path.join(E.cfg, "shares.db")
|
||||
ap2 = ap.add_argument_group('share-url options')
|
||||
ap2 = ap.add_argument_group("share-url options")
|
||||
ap2.add_argument("--shr", metavar="DIR", type=u, default="", help="toplevel virtual folder for shared files/folders, for example [\033[32m/share\033[0m]")
|
||||
ap2.add_argument("--shr-db", metavar="FILE", type=u, default=db_path, help="database to store shares in")
|
||||
ap2.add_argument("--shr-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to view/delete any share")
|
||||
|
@ -1043,7 +1049,7 @@ def add_share(ap):
|
|||
|
||||
|
||||
def add_upload(ap):
|
||||
ap2 = ap.add_argument_group('upload options')
|
||||
ap2 = ap.add_argument_group("upload options")
|
||||
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m")
|
||||
ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip")
|
||||
ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)")
|
||||
|
@ -1085,14 +1091,14 @@ def add_upload(ap):
|
|||
|
||||
|
||||
def add_network(ap):
|
||||
ap2 = ap.add_argument_group('network options')
|
||||
ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6")
|
||||
ap2 = ap.add_argument_group("network options")
|
||||
ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (comma-separated list; see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6")
|
||||
ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to listen on (comma/range); ignored for unix-sockets")
|
||||
ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)")
|
||||
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=1, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m2\033[0m]=outermost-proxy, [\033[32m3\033[0m]=second-proxy, [\033[32m-1\033[0m]=closest-proxy")
|
||||
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=9999999, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m-1\033[0m]=closest-proxy, [\033[32m-2\033[0m]=second-hop, [\033[32m-3\033[0m]=third-hop")
|
||||
ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from")
|
||||
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="comma-separated list of trusted reverse-proxy CIDRs; only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)")
|
||||
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)")
|
||||
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]")
|
||||
if ANYWIN:
|
||||
ap2.add_argument("--reuseaddr", action="store_true", help="set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances")
|
||||
|
@ -1110,7 +1116,7 @@ def add_network(ap):
|
|||
|
||||
|
||||
def add_tls(ap, cert_path):
|
||||
ap2 = ap.add_argument_group('SSL/TLS options')
|
||||
ap2 = ap.add_argument_group("SSL/TLS options")
|
||||
ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext")
|
||||
ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls")
|
||||
ap2.add_argument("--cert", metavar="PATH", type=u, default=cert_path, help="path to file containing a concatenation of TLS key and certificate chain")
|
||||
|
@ -1122,7 +1128,7 @@ def add_tls(ap, cert_path):
|
|||
|
||||
def add_cert(ap, cert_path):
|
||||
cert_dir = os.path.dirname(cert_path)
|
||||
ap2 = ap.add_argument_group('TLS certificate generator options')
|
||||
ap2 = ap.add_argument_group("TLS certificate generator options")
|
||||
ap2.add_argument("--no-crt", action="store_true", help="disable automatic certificate creation")
|
||||
ap2.add_argument("--crt-ns", metavar="N,N", type=u, default="", help="comma-separated list of FQDNs (domains) to add into the certificate")
|
||||
ap2.add_argument("--crt-exact", action="store_true", help="do not add wildcard entries for each \033[33m--crt-ns\033[0m")
|
||||
|
@ -1142,7 +1148,7 @@ def add_cert(ap, cert_path):
|
|||
def add_auth(ap):
|
||||
idp_db = os.path.join(E.cfg, "idp.db")
|
||||
ses_db = os.path.join(E.cfg, "sessions.db")
|
||||
ap2 = ap.add_argument_group('IdP / identity provider / user authentication options')
|
||||
ap2 = ap.add_argument_group("IdP / identity provider / user authentication options")
|
||||
ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks if the request-header \033[33mHN\033[0m contains a username to associate the request with (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy")
|
||||
ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control")
|
||||
ap2.add_argument("--idp-h-key", metavar="HN", type=u, default="", help="optional but recommended safeguard; your reverse-proxy will insert a secret header named \033[33mHN\033[0m into all requests, and the other IdP headers will be ignored if this header is not present")
|
||||
|
@ -1156,14 +1162,14 @@ def add_auth(ap):
|
|||
ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)")
|
||||
ap2.add_argument("--ses-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)")
|
||||
ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies")
|
||||
ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]")
|
||||
ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="\033[34mREPEATABLE:\033[0m users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]")
|
||||
|
||||
|
||||
def add_chpw(ap):
|
||||
db_path = os.path.join(E.cfg, "chpw.json")
|
||||
ap2 = ap.add_argument_group('user-changeable passwords options')
|
||||
ap2 = ap.add_argument_group("user-changeable passwords options")
|
||||
ap2.add_argument("--chpw", action="store_true", help="allow users to change their own passwords")
|
||||
ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="do not allow password-changes for this comma-separated list of usernames")
|
||||
ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="\033[34mREPEATABLE:\033[0m do not allow password-changes for this comma-separated list of usernames")
|
||||
ap2.add_argument("--chpw-db", metavar="PATH", type=u, default=db_path, help="where to store the passwords database (if you run multiple copyparty instances, make sure they use different DBs)")
|
||||
ap2.add_argument("--chpw-len", metavar="N", type=int, default=8, help="minimum password length")
|
||||
ap2.add_argument("--chpw-v", metavar="LVL", type=int, default=2, help="verbosity of summary on config load [\033[32m0\033[0m] = nothing at all, [\033[32m1\033[0m] = number of users, [\033[32m2\033[0m] = list users with default-pw, [\033[32m3\033[0m] = list all users")
|
||||
|
@ -1212,12 +1218,12 @@ def add_zc_ssdp(ap):
|
|||
|
||||
|
||||
def add_ftp(ap):
|
||||
ap2 = ap.add_argument_group('FTP options (TCP only)')
|
||||
ap2 = ap.add_argument_group("FTP options (TCP only)")
|
||||
ap2.add_argument("--ftp", metavar="PORT", type=int, default=0, help="enable FTP server on \033[33mPORT\033[0m, for example \033[32m3921")
|
||||
ap2.add_argument("--ftps", metavar="PORT", type=int, default=0, help="enable FTPS server on \033[33mPORT\033[0m, for example \033[32m3990")
|
||||
ap2.add_argument("--ftpv", action="store_true", help="verbose")
|
||||
ap2.add_argument("--ftp4", action="store_true", help="only listen on IPv4")
|
||||
ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--ftp-no-ow", action="store_true", help="if target file exists, reject upload instead of overwrite")
|
||||
ap2.add_argument("--ftp-wt", metavar="SEC", type=int, default=7, help="grace period for resuming interrupted uploads (any client can write to any file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
|
||||
ap2.add_argument("--ftp-nat", metavar="ADDR", type=u, default="", help="the NAT address to use for passive connections")
|
||||
|
@ -1225,7 +1231,7 @@ def add_ftp(ap):
|
|||
|
||||
|
||||
def add_webdav(ap):
|
||||
ap2 = ap.add_argument_group('WebDAV options')
|
||||
ap2 = ap.add_argument_group("WebDAV options")
|
||||
ap2.add_argument("--daw", action="store_true", help="enable full write support, even if client may not be webdav. \033[1;31mWARNING:\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)")
|
||||
ap2.add_argument("--dav-inf", action="store_true", help="allow depth:infinite requests (recursive file listing); extremely server-heavy but required for spec compliance -- luckily few clients rely on this")
|
||||
ap2.add_argument("--dav-mac", action="store_true", help="disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS)")
|
||||
|
@ -1235,7 +1241,7 @@ def add_webdav(ap):
|
|||
|
||||
|
||||
def add_tftp(ap):
|
||||
ap2 = ap.add_argument_group('TFTP options (UDP only)')
|
||||
ap2 = ap.add_argument_group("TFTP options (UDP only)")
|
||||
ap2.add_argument("--tftp", metavar="PORT", type=int, default=0, help="enable TFTP server on \033[33mPORT\033[0m, for example \033[32m69 \033[0mor \033[32m3969")
|
||||
ap2.add_argument("--tftp4", action="store_true", help="only listen on IPv4")
|
||||
ap2.add_argument("--tftpv", action="store_true", help="verbose")
|
||||
|
@ -1243,12 +1249,12 @@ def add_tftp(ap):
|
|||
ap2.add_argument("--tftp-no-fast", action="store_true", help="debug: disable optimizations")
|
||||
ap2.add_argument("--tftp-lsf", metavar="PTN", type=u, default="\\.?(dir|ls)(\\.txt)?", help="return a directory listing if a file with this name is requested and it does not exist; defaults matches .ls, dir, .dir.txt, ls.txt, ...")
|
||||
ap2.add_argument("--tftp-nols", action="store_true", help="if someone tries to download a directory, return an error instead of showing its directory listing")
|
||||
ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||
ap2.add_argument("--tftp-pr", metavar="P-P", type=u, default="", help="the range of UDP ports to use for data transfer, for example \033[32m12000-13000")
|
||||
|
||||
|
||||
def add_smb(ap):
|
||||
ap2 = ap.add_argument_group('SMB/CIFS options')
|
||||
ap2 = ap.add_argument_group("SMB/CIFS options")
|
||||
ap2.add_argument("--smb", action="store_true", help="enable smb (read-only) -- this requires running copyparty as root on linux and macos unless \033[33m--smb-port\033[0m is set above 1024 and your OS does port-forwarding from 445 to that.\n\033[1;31mWARNING:\033[0m this protocol is DANGEROUS and buggy! Never expose to the internet!")
|
||||
ap2.add_argument("--smbw", action="store_true", help="enable write support (please dont)")
|
||||
ap2.add_argument("--smb1", action="store_true", help="disable SMBv2, only enable SMBv1 (CIFS)")
|
||||
|
@ -1262,30 +1268,30 @@ def add_smb(ap):
|
|||
|
||||
|
||||
def add_handlers(ap):
|
||||
ap2 = ap.add_argument_group('handlers (see --help-handlers)')
|
||||
ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="handle 404s by executing \033[33mPY\033[0m file")
|
||||
ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="handle 403s by executing \033[33mPY\033[0m file")
|
||||
ap2 = ap.add_argument_group("handlers (see --help-handlers)")
|
||||
ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 404s by executing \033[33mPY\033[0m file")
|
||||
ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 403s by executing \033[33mPY\033[0m file")
|
||||
ap2.add_argument("--hot-handlers", action="store_true", help="recompile handlers on each request -- expensive but convenient when hacking on stuff")
|
||||
|
||||
|
||||
def add_hooks(ap):
|
||||
ap2 = ap.add_argument_group('event hooks (see --help-hooks)')
|
||||
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file upload starts")
|
||||
ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file upload finishes")
|
||||
ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after all uploads finish and volume is idle")
|
||||
ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file copy")
|
||||
ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file copy")
|
||||
ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file move/rename")
|
||||
ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file move/rename")
|
||||
ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file delete")
|
||||
ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file delete")
|
||||
ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m on message")
|
||||
ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)")
|
||||
ap2 = ap.add_argument_group("event hooks (see --help-hooks)")
|
||||
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file upload starts")
|
||||
ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file upload finishes")
|
||||
ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after all uploads finish and volume is idle")
|
||||
ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file copy")
|
||||
ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file copy")
|
||||
ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file move/rename")
|
||||
ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file move/rename")
|
||||
ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file delete")
|
||||
ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file delete")
|
||||
ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m on message")
|
||||
ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)")
|
||||
ap2.add_argument("--hook-v", action="store_true", help="verbose hooks")
|
||||
|
||||
|
||||
def add_stats(ap):
|
||||
ap2 = ap.add_argument_group('grafana/prometheus metrics endpoint')
|
||||
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("--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)")
|
||||
|
@ -1295,15 +1301,16 @@ def add_stats(ap):
|
|||
|
||||
|
||||
def add_yolo(ap):
|
||||
ap2 = ap.add_argument_group('yolo options')
|
||||
ap2 = ap.add_argument_group("yolo options")
|
||||
ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests")
|
||||
ap2.add_argument("--cookie-lax", action="store_true", help="allow cookies from other domains (if you follow a link from another website into your server, you will arrive logged-in); this reduces protection against CSRF")
|
||||
ap2.add_argument("--no-fnugg", action="store_true", help="disable the smoketest for caching-related issues in the web-UI")
|
||||
ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET")
|
||||
ap2.add_argument("--wo-up-readme", action="store_true", help="allow users with write-only access to upload logues and readmes without adding the _wo_ filename prefix (volflag=wo_up_readme)")
|
||||
|
||||
|
||||
def add_optouts(ap):
|
||||
ap2 = ap.add_argument_group('opt-outs')
|
||||
ap2 = ap.add_argument_group("opt-outs")
|
||||
ap2.add_argument("-nw", action="store_true", help="never write anything to disk (debug/benchmark)")
|
||||
ap2.add_argument("--keep-qem", action="store_true", help="do not disable quick-edit-mode on windows (it is disabled to avoid accidental text selection in the terminal window, as this would pause execution)")
|
||||
ap2.add_argument("--no-dav", action="store_true", help="disable webdav support")
|
||||
|
@ -1329,7 +1336,7 @@ def add_optouts(ap):
|
|||
|
||||
|
||||
def add_safety(ap):
|
||||
ap2 = ap.add_argument_group('safety options')
|
||||
ap2 = ap.add_argument_group("safety options")
|
||||
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
||||
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih")
|
||||
ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r")
|
||||
|
@ -1360,7 +1367,7 @@ def add_safety(ap):
|
|||
|
||||
|
||||
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
||||
ap2 = ap.add_argument_group('salting options')
|
||||
ap2 = ap.add_argument_group("salting options")
|
||||
ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)")
|
||||
ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)")
|
||||
ap2.add_argument("--ah-gen", metavar="PW", type=u, default="", help="generate hashed password for \033[33mPW\033[0m, or read passwords from STDIN if \033[33mPW\033[0m is [\033[32m-\033[0m]")
|
||||
|
@ -1374,14 +1381,14 @@ def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
|||
|
||||
|
||||
def add_shutdown(ap):
|
||||
ap2 = ap.add_argument_group('shutdown options')
|
||||
ap2 = ap.add_argument_group("shutdown options")
|
||||
ap2.add_argument("--ign-ebind", action="store_true", help="continue running even if it's impossible to listen on some of the requested endpoints")
|
||||
ap2.add_argument("--ign-ebind-all", action="store_true", help="continue running even if it's impossible to receive connections at all")
|
||||
ap2.add_argument("--exit", metavar="WHEN", type=u, default="", help="shutdown after \033[33mWHEN\033[0m has finished; [\033[32mcfg\033[0m] config parsing, [\033[32midx\033[0m] volscan + multimedia indexing")
|
||||
|
||||
|
||||
def add_logging(ap):
|
||||
ap2 = ap.add_argument_group('logging options')
|
||||
ap2 = ap.add_argument_group("logging options")
|
||||
ap2.add_argument("-q", action="store_true", help="quiet; disable most STDOUT messages")
|
||||
ap2.add_argument("-lo", metavar="PATH", type=u, default="", help="logfile, example: \033[32mcpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz\033[0m (NB: some errors may appear on STDOUT only)")
|
||||
ap2.add_argument("--no-ansi", action="store_true", default=not VT100, help="disable colors; same as environment-variable NO_COLOR")
|
||||
|
@ -1390,7 +1397,7 @@ def add_logging(ap):
|
|||
ap2.add_argument("--no-voldump", action="store_true", help="do not list volumes and permissions on startup")
|
||||
ap2.add_argument("--log-utc", action="store_true", help="do not use local timezone; assume the TZ env-var is UTC (tiny bit faster)")
|
||||
ap2.add_argument("--log-tdec", metavar="N", type=int, default=3, help="timestamp resolution / number of timestamp decimals")
|
||||
ap2.add_argument("--log-badpwd", metavar="N", type=int, default=1, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed")
|
||||
ap2.add_argument("--log-badpwd", metavar="N", type=int, default=2, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed")
|
||||
ap2.add_argument("--log-conn", action="store_true", help="debug: print tcp-server msgs")
|
||||
ap2.add_argument("--log-htp", action="store_true", help="debug: print http-server threadpool scaling")
|
||||
ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
||||
|
@ -1399,7 +1406,7 @@ def add_logging(ap):
|
|||
|
||||
|
||||
def add_admin(ap):
|
||||
ap2 = ap.add_argument_group('admin panel options')
|
||||
ap2 = ap.add_argument_group("admin panel options")
|
||||
ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)")
|
||||
ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)")
|
||||
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks)")
|
||||
|
@ -1413,7 +1420,7 @@ def add_admin(ap):
|
|||
def add_thumbnail(ap):
|
||||
th_ram = (RAM_AVAIL or RAM_TOTAL or 9) * 0.6
|
||||
th_ram = int(max(min(th_ram, 6), 0.3) * 10) / 10
|
||||
ap2 = ap.add_argument_group('thumbnail options')
|
||||
ap2 = ap.add_argument_group("thumbnail options")
|
||||
ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails (volflag=dthumb)")
|
||||
ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails (volflag=dvthumb)")
|
||||
ap2.add_argument("--no-athumb", action="store_true", help="disable audio thumbnails (spectrograms) (volflag=dathumb)")
|
||||
|
@ -1445,7 +1452,7 @@ def add_thumbnail(ap):
|
|||
|
||||
|
||||
def add_transcoding(ap):
|
||||
ap2 = ap.add_argument_group('transcoding options')
|
||||
ap2 = ap.add_argument_group("transcoding options")
|
||||
ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable")
|
||||
ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable")
|
||||
ap2.add_argument("--allow-wav", action="store_true", help="allow transcoding to wav (lossless, uncompressed)")
|
||||
|
@ -1458,7 +1465,7 @@ def add_transcoding(ap):
|
|||
|
||||
|
||||
def add_tail(ap):
|
||||
ap2 = ap.add_argument_group('tailing options (realtime streaming of a growing file)')
|
||||
ap2 = ap.add_argument_group("tailing options (realtime streaming of a growing file)")
|
||||
ap2.add_argument("--tail-who", metavar="LVL", type=int, default=2, help="who can tail? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=authenticated-with-read-access, [\033[32m3\033[0m]=everyone-with-read-access (volflag=tail_who)")
|
||||
ap2.add_argument("--tail-cmax", metavar="N", type=int, default=64, help="do not allow starting a new tail if more than \033[33mN\033[0m active downloads")
|
||||
ap2.add_argument("--tail-tmax", metavar="SEC", type=float, default=0, help="terminate connection after \033[33mSEC\033[0m seconds; [\033[32m0\033[0m]=never (volflag=tail_tmax)")
|
||||
|
@ -1468,7 +1475,7 @@ def add_tail(ap):
|
|||
|
||||
|
||||
def add_rss(ap):
|
||||
ap2 = ap.add_argument_group('RSS options')
|
||||
ap2 = ap.add_argument_group("RSS options")
|
||||
ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)")
|
||||
ap2.add_argument("--rss-nf", metavar="HITS", type=int, default=250, help="default number of files to return (url-param 'nf')")
|
||||
ap2.add_argument("--rss-fext", metavar="E,E", type=u, default="", help="default list of file extensions to include (url-param 'fext'); blank=all")
|
||||
|
@ -1477,7 +1484,7 @@ def add_rss(ap):
|
|||
|
||||
def add_db_general(ap, hcores):
|
||||
noidx = APPLESAN_TXT if MACOS else ""
|
||||
ap2 = ap.add_argument_group('general db options')
|
||||
ap2 = ap.add_argument_group("general db options")
|
||||
ap2.add_argument("-e2d", action="store_true", help="enable up2k database; this enables file search, upload-undo, improves deduplication")
|
||||
ap2.add_argument("-e2ds", action="store_true", help="scan writable folders for new files on startup; sets \033[33m-e2d\033[0m")
|
||||
ap2.add_argument("-e2dsa", action="store_true", help="scans all folders on startup; sets \033[33m-e2ds\033[0m")
|
||||
|
@ -1506,7 +1513,7 @@ def add_db_general(ap, hcores):
|
|||
|
||||
|
||||
def add_db_metadata(ap):
|
||||
ap2 = ap.add_argument_group('metadata db options')
|
||||
ap2 = ap.add_argument_group("metadata db options")
|
||||
ap2.add_argument("-e2t", action="store_true", help="enable metadata indexing; makes it possible to search for artist/title/codec/resolution/...")
|
||||
ap2.add_argument("-e2ts", action="store_true", help="scan newly discovered files for metadata on startup; sets \033[33m-e2t\033[0m")
|
||||
ap2.add_argument("-e2tsr", action="store_true", help="delete all metadata from DB and do a full rescan; sets \033[33m-e2ts\033[0m")
|
||||
|
@ -1516,15 +1523,16 @@ def add_db_metadata(ap):
|
|||
ap2.add_argument("--mtag-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for tag scanning")
|
||||
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
||||
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/FFprobe parsers")
|
||||
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
||||
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add/replace metadata mapping")
|
||||
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE)
|
||||
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as \033[33m-mte\033[0m", default=DEF_MTH)
|
||||
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file")
|
||||
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="\033[34mREPEATABLE:\033[0m read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file")
|
||||
|
||||
|
||||
def add_txt(ap):
|
||||
ap2 = ap.add_argument_group('textfile options')
|
||||
ap2 = ap.add_argument_group("textfile options")
|
||||
ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)")
|
||||
ap2.add_argument("--txt-eol", metavar="TYPE", type=u, default="", help="enable EOL conversion when writing documents; supported: CRLF, LF (volflag=txt_eol)")
|
||||
ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="the textfile editor will check for serverside changes every \033[33mSEC\033[0m seconds")
|
||||
ap2.add_argument("-emp", action="store_true", help="enable markdown plugins -- neat but dangerous, big XSS risk")
|
||||
ap2.add_argument("--exp", action="store_true", help="enable textfile expansion -- replace {{self.ip}} and such; see \033[33m--help-exp\033[0m (volflag=exp)")
|
||||
|
@ -1534,7 +1542,7 @@ def add_txt(ap):
|
|||
|
||||
|
||||
def add_og(ap):
|
||||
ap2 = ap.add_argument_group('og / open graph / discord-embed options')
|
||||
ap2 = ap.add_argument_group("og / open graph / discord-embed options")
|
||||
ap2.add_argument("--og", action="store_true", help="disable hotlinking and return an html document instead; this is required by open-graph, but can also be useful on its own (volflag=og)")
|
||||
ap2.add_argument("--og-ua", metavar="RE", type=u, default="", help="only disable hotlinking / engage OG behavior if the useragent matches regex \033[33mRE\033[0m (volflag=og_ua)")
|
||||
ap2.add_argument("--og-tpl", metavar="PATH", type=u, default="", help="do not return the regular copyparty html, but instead load the jinja2 template at \033[33mPATH\033[0m (if path contains 'EXT' then EXT will be replaced with the requested file's extension) (volflag=og_tpl)")
|
||||
|
@ -1552,7 +1560,7 @@ def add_og(ap):
|
|||
|
||||
|
||||
def add_ui(ap, retry):
|
||||
ap2 = ap.add_argument_group('ui options')
|
||||
ap2 = ap.add_argument_group("ui options")
|
||||
ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)")
|
||||
ap2.add_argument("--gsel", action="store_true", help="select files in grid by ctrl-click (volflag=gsel)")
|
||||
ap2.add_argument("--localtime", action="store_true", help="default to local timezone instead of UTC")
|
||||
|
@ -1567,7 +1575,7 @@ def add_ui(ap, retry):
|
|||
ap2.add_argument("--qdel", metavar="LVL", type=int, default=2, help="number of confirmations to show when deleting files (2/1/0)")
|
||||
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files/folders matching \033[33mREGEX\033[0m in file list. WARNING: Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
||||
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
||||
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="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("--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("--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")
|
||||
|
@ -1583,6 +1591,7 @@ def add_ui(ap, retry):
|
|||
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
|
||||
ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
|
||||
ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
|
||||
ap2.add_argument("--ctl-re", metavar="SEC", type=int, default=1, help="the controlpanel Refresh-button will autorefresh every SEC; [\033[32m0\033[0m] = just once")
|
||||
ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox")
|
||||
ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs (volflag=lg_sbf)")
|
||||
ap2.add_argument("--md-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for README.md docs, for example [\033[32mfullscreen\033[0m] (volflag=md_sba)")
|
||||
|
@ -1593,7 +1602,7 @@ def add_ui(ap, retry):
|
|||
|
||||
|
||||
def add_debug(ap):
|
||||
ap2 = ap.add_argument_group('debug options')
|
||||
ap2 = ap.add_argument_group("debug options")
|
||||
ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
|
||||
ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
|
||||
ap2.add_argument("--deps", action="store_true", help="list information about detected optional dependencies")
|
||||
|
|
|
@ -1700,6 +1700,7 @@ class AuthSrv(object):
|
|||
if not mount and not self.args.idp_h_usr:
|
||||
# -h says our defaults are CWD at root and read/write for everyone
|
||||
axs = AXS(["*"], ["*"], None, None)
|
||||
ehint = ""
|
||||
if self.is_lxc:
|
||||
t = "Read-access has been disabled due to failsafe: Docker detected, but %s. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw"
|
||||
if len(cfg_files_loaded) == 1:
|
||||
|
@ -1709,10 +1710,21 @@ class AuthSrv(object):
|
|||
else:
|
||||
self.log(t % ("the config does not define any volumes",), 1)
|
||||
axs = AXS()
|
||||
ehint = "; please try moving them up one level, into the parent folder:"
|
||||
elif self.args.c:
|
||||
t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw"
|
||||
self.log(t, 1)
|
||||
axs = AXS()
|
||||
ehint = ":"
|
||||
if ehint:
|
||||
try:
|
||||
files = os.listdir(E.cfg)
|
||||
except:
|
||||
files = []
|
||||
hits = [x for x in files if x.lower().endswith(".conf")]
|
||||
if hits:
|
||||
t = "Hint: Found some config files in [%s], but these were not automatically loaded because they are in the wrong place%s %s\n"
|
||||
self.log(t % (E.cfg, ehint, ", ".join(hits)), 3)
|
||||
zvf = {"tcolor": self.args.tcolor}
|
||||
vfs = VFS(self.log_func, absreal("."), "", "", axs, zvf)
|
||||
if not axs.uread:
|
||||
|
@ -2630,6 +2642,8 @@ class AuthSrv(object):
|
|||
self.re_pwd = None
|
||||
pwds = [re.escape(x) for x in self.iacct.keys()]
|
||||
pwds.extend(list(self.sesa))
|
||||
if self.args.usernames:
|
||||
pwds.extend([x.split(":", 1)[1] for x in pwds if ":" in x])
|
||||
if pwds:
|
||||
if self.ah.on:
|
||||
zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)"
|
||||
|
@ -2930,6 +2944,9 @@ class AuthSrv(object):
|
|||
t = "minimum password length: %d characters"
|
||||
return False, t % (self.args.chpw_len,)
|
||||
|
||||
if self.args.usernames:
|
||||
pw = "%s:%s" % (uname, pw)
|
||||
|
||||
hpw = self.ah.hash(pw) if self.ah.on else pw
|
||||
|
||||
if hpw == self.acct[uname]:
|
||||
|
@ -3021,6 +3038,12 @@ class AuthSrv(object):
|
|||
self.log("chpw: " + msg, 6)
|
||||
|
||||
def setup_pwhash(self, acct: dict[str, str]) -> None:
|
||||
if self.args.usernames:
|
||||
for uname, pw in list(acct.items())[:]:
|
||||
if pw.startswith("+") and len(pw) == 33:
|
||||
continue
|
||||
acct[uname] = "%s:%s" % (uname, pw)
|
||||
|
||||
self.ah = PWHash(self.args)
|
||||
if not self.ah.on:
|
||||
if self.args.ah_cli or self.args.ah_gen:
|
||||
|
|
|
@ -111,6 +111,7 @@ def vf_vmap() -> dict[str, str]:
|
|||
"tail_tmax",
|
||||
"tail_who",
|
||||
"tcolor",
|
||||
"txt_eol",
|
||||
"unlist",
|
||||
"u2abort",
|
||||
"u2ts",
|
||||
|
@ -322,6 +323,7 @@ flagcats = {
|
|||
"exp": "enable textfile expansion; see --help-exp",
|
||||
"exp_md": "placeholders to expand in markdown files; see --help",
|
||||
"exp_lg": "placeholders to expand in prologue/epilogue; see --help",
|
||||
"txt_eol=lf": "enable EOL conversion when writing docs (LF or CRLF)",
|
||||
},
|
||||
"tailing": {
|
||||
"notail": "disable ?tail (download a growing file continuously)",
|
||||
|
|
|
@ -83,7 +83,12 @@ class FtpAuth(DummyAuthorizer):
|
|||
uname = "*"
|
||||
if username != "anonymous":
|
||||
uname = ""
|
||||
for zs in (password, username):
|
||||
if args.usernames:
|
||||
alts = ["%s:%s" % (username, password)]
|
||||
else:
|
||||
alts = password, username
|
||||
|
||||
for zs in alts:
|
||||
zs = asrv.iacct.get(asrv.ah.hash(zs), "")
|
||||
if zs:
|
||||
uname = zs
|
||||
|
@ -607,7 +612,7 @@ class Ftpd(object):
|
|||
if "::" in ips:
|
||||
ips.append("0.0.0.0")
|
||||
|
||||
ips = [x for x in ips if "unix:" not in x]
|
||||
ips = [x for x in ips if not x.startswith(("unix:", "fd:"))]
|
||||
|
||||
if self.args.ftp4:
|
||||
ips = [x for x in ips if ":" not in x]
|
||||
|
|
|
@ -62,6 +62,7 @@ from .util import (
|
|||
alltrace,
|
||||
atomic_move,
|
||||
b64dec,
|
||||
eol_conv,
|
||||
exclude_dotfiles,
|
||||
formatdate,
|
||||
fsenc,
|
||||
|
@ -262,7 +263,8 @@ class HttpCli(object):
|
|||
|
||||
def _assert_safe_rem(self, rem: str) -> None:
|
||||
# sanity check to prevent any disasters
|
||||
if rem.startswith("/") or rem.startswith("../") or "/../" in rem:
|
||||
# (this function hopefully serves no purpose; validation has already happened at this point, this only exists as a last-ditch effort just in case)
|
||||
if rem.startswith(("/", "../")) or "/../" in rem:
|
||||
raise Exception("that was close")
|
||||
|
||||
def _gen_fk(self, alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str:
|
||||
|
@ -383,9 +385,20 @@ class HttpCli(object):
|
|||
try:
|
||||
cli_ip = zsl[n].strip()
|
||||
except:
|
||||
cli_ip = zsl[0].strip()
|
||||
t = "rproxy={} oob x-fwd {}"
|
||||
self.log(t.format(self.args.rproxy, zso), c=3)
|
||||
cli_ip = self.ip
|
||||
self.bad_xff = True
|
||||
if self.args.rproxy != 9999999:
|
||||
t = "global-option --rproxy %d could not be used (out-of-bounds) for the received header [%s]"
|
||||
self.log(t % (self.args.rproxy, zso), c=3)
|
||||
else:
|
||||
zsl = [
|
||||
" rproxy: %d if this client's IP-address is [%s]"
|
||||
% (-1 - zd, zs.strip())
|
||||
for zd, zs in enumerate(zsl)
|
||||
]
|
||||
t = 'could not determine the client\'s IP-address because the global-option --rproxy has not been configured, so the request-header [%s] specified by global-option --xff-hdr cannot be used safely! Please see the "reverse-proxy" section in the readme. The best approach is to configure your reverse-proxy to give copyparty the exact IP-address to assume (perhaps in another header), but you may also try the following:'
|
||||
t = t % (self.args.xff_hdr,)
|
||||
self.log("%s\n\n%s\n" % (t, "\n".join(zsl)), 3)
|
||||
|
||||
pip = self.conn.addr[0]
|
||||
xffs = self.conn.xff_nm
|
||||
|
@ -2924,12 +2937,16 @@ class HttpCli(object):
|
|||
|
||||
def handle_chpw(self) -> bool:
|
||||
assert self.parser # !rm
|
||||
if self.args.usernames:
|
||||
self.parser.require("uname", 64)
|
||||
pwd = self.parser.require("pw", 64)
|
||||
self.parser.drop()
|
||||
|
||||
ok, msg = self.asrv.chpw(self.conn.hsrv.broker, self.uname, pwd)
|
||||
if ok:
|
||||
self.cbonk(self.conn.hsrv.gpwc, pwd, "pw", "too many password changes")
|
||||
if self.args.usernames:
|
||||
pwd = "%s:%s" % (self.uname, pwd)
|
||||
ok, msg = self.get_pwd_cookie(pwd)
|
||||
if ok:
|
||||
msg = "new password OK"
|
||||
|
@ -2942,6 +2959,15 @@ class HttpCli(object):
|
|||
|
||||
def handle_login(self) -> bool:
|
||||
assert self.parser # !rm
|
||||
if self.args.usernames and not (
|
||||
self.args.shr and self.vpath.startswith(self.args.shr1)
|
||||
):
|
||||
try:
|
||||
un = self.parser.require("uname", 64)
|
||||
except:
|
||||
un = ""
|
||||
else:
|
||||
un = ""
|
||||
pwd = self.parser.require("cppwd", 64)
|
||||
try:
|
||||
uhash = self.parser.require("uhash", 256)
|
||||
|
@ -2952,6 +2978,9 @@ class HttpCli(object):
|
|||
if not pwd:
|
||||
raise Pebkac(422, "password cannot be blank")
|
||||
|
||||
if un:
|
||||
pwd = "%s:%s" % (un, pwd)
|
||||
|
||||
dst = self.args.SRS
|
||||
if self.vpath:
|
||||
dst += quotep(self.vpaths)
|
||||
|
@ -3583,7 +3612,7 @@ class HttpCli(object):
|
|||
rem = "{}/{}".format(rp, fn).strip("/")
|
||||
dbv, vrem = vfs.get_dbv(rem)
|
||||
|
||||
if not rem.endswith(".md") and not self.can_delete:
|
||||
if not rem.lower().endswith(".md") and not self.can_delete:
|
||||
raise Pebkac(400, "only markdown pls")
|
||||
|
||||
if nullwrite:
|
||||
|
@ -3667,6 +3696,9 @@ class HttpCli(object):
|
|||
if p_field != "body":
|
||||
raise Pebkac(400, "expected body, got {}".format(p_field))
|
||||
|
||||
if "txt_eol" in vfs.flags:
|
||||
p_data = eol_conv(p_data, vfs.flags["txt_eol"])
|
||||
|
||||
xbu = vfs.flags.get("xbu")
|
||||
if xbu:
|
||||
if not runhook(
|
||||
|
@ -4637,7 +4669,9 @@ class HttpCli(object):
|
|||
else:
|
||||
fn = self.host.split(":")[0]
|
||||
|
||||
if vn.flags.get("zipmax") and (not self.uname or not "zipmaxu" in vn.flags):
|
||||
if vn.flags.get("zipmax") and not (
|
||||
vn.flags.get("zipmaxu") and self.uname != "*"
|
||||
):
|
||||
maxs = vn.flags.get("zipmaxs_v") or 0
|
||||
maxn = vn.flags.get("zipmaxn_v") or 0
|
||||
nf = 0
|
||||
|
@ -5031,7 +5065,7 @@ class HttpCli(object):
|
|||
wvol = [x for x in wvol if "unlistcw" not in allvols[x[1:-1]].flags]
|
||||
|
||||
fmt = self.uparam.get("ls", "")
|
||||
if not fmt and (self.ua.startswith("curl/") or self.ua.startswith("fetch")):
|
||||
if not fmt and self.ua.startswith(("curl/", "fetch")):
|
||||
fmt = "v"
|
||||
|
||||
if fmt in ["v", "t", "txt"]:
|
||||
|
@ -5071,6 +5105,13 @@ class HttpCli(object):
|
|||
self.reply(zb, mime="text/plain; charset=utf-8")
|
||||
return True
|
||||
|
||||
re_btn = ""
|
||||
nre = self.args.ctl_re
|
||||
if "re" in self.uparam:
|
||||
self.out_headers["Refresh"] = str(nre)
|
||||
elif nre:
|
||||
re_btn = "&re=%s" % (nre,)
|
||||
|
||||
html = self.j2s(
|
||||
"splash",
|
||||
this=self,
|
||||
|
@ -5088,6 +5129,7 @@ class HttpCli(object):
|
|||
mtpq=vs["mtpq"],
|
||||
dbwt=vs["dbwt"],
|
||||
url_suf=suf,
|
||||
re=re_btn,
|
||||
k304=self.k304(),
|
||||
no304=self.no304(),
|
||||
k304vis=self.args.k304 > 0,
|
||||
|
@ -5133,7 +5175,7 @@ class HttpCli(object):
|
|||
t = '<h1 id="n">404 not found ┐( ´ -`)┌</h1><p><a id="r" href="{}/?h">go home</a></p>'
|
||||
pt = "404 not found ┐( ´ -`)┌"
|
||||
|
||||
if self.ua.startswith("curl/") or self.ua.startswith("fetch"):
|
||||
if self.ua.startswith(("curl/", "fetch")):
|
||||
pt = "# acct: %s\n%s\n" % (self.uname, pt)
|
||||
self.reply(pt.encode("utf-8"), status=rc)
|
||||
return True
|
||||
|
@ -5447,6 +5489,8 @@ class HttpCli(object):
|
|||
elif nfi == 3:
|
||||
if not vp.endswith(vfi):
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
n -= 1
|
||||
if not n:
|
||||
|
@ -5571,6 +5615,8 @@ class HttpCli(object):
|
|||
elif nfi == 3:
|
||||
if not vp.endswith(vfi):
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
if not dots and "/." in vp:
|
||||
continue
|
||||
|
@ -6001,6 +6047,12 @@ class HttpCli(object):
|
|||
else:
|
||||
[x.pop(k) for k in ["name", "dt"] for y in [dirs, files] for x in y]
|
||||
|
||||
# nonce (tlnote: norwegian for flake as in snowflake)
|
||||
if self.args.no_fnugg:
|
||||
ls["fnugg"] = "nei"
|
||||
elif "fnugg" in self.headers:
|
||||
ls["fnugg"] = self.headers["fnugg"]
|
||||
|
||||
ret = json.dumps(ls)
|
||||
mime = "application/json"
|
||||
|
||||
|
@ -6183,7 +6235,8 @@ class HttpCli(object):
|
|||
if not use_filekey:
|
||||
return self.tx_404(True)
|
||||
|
||||
if add_og and not abspath.lower().endswith(".md"):
|
||||
is_md = abspath.lower().endswith(".md")
|
||||
if add_og and not is_md:
|
||||
if og_ua or self.host not in self.headers.get("referer", ""):
|
||||
self.vpath, og_fn = vsplit(self.vpath)
|
||||
vpath = self.vpath
|
||||
|
@ -6195,10 +6248,10 @@ class HttpCli(object):
|
|||
vpnodes.pop()
|
||||
|
||||
if (
|
||||
(abspath.endswith(".md") or self.can_delete)
|
||||
(is_md or self.can_delete)
|
||||
and "nohtml" not in vn.flags
|
||||
and (
|
||||
("v" in self.uparam and abspath.endswith(".md"))
|
||||
(is_md and "v" in self.uparam)
|
||||
or "edit" in self.uparam
|
||||
or "edit2" in self.uparam
|
||||
)
|
||||
|
@ -6255,11 +6308,7 @@ class HttpCli(object):
|
|||
is_ls = "ls" in self.uparam
|
||||
is_js = self.args.force_js or self.cookies.get("js") == "y"
|
||||
|
||||
if (
|
||||
not is_ls
|
||||
and not add_og
|
||||
and (self.ua.startswith("curl/") or self.ua.startswith("fetch"))
|
||||
):
|
||||
if not is_ls and not add_og and self.ua.startswith(("curl/", "fetch")):
|
||||
self.uparam["ls"] = "v"
|
||||
is_ls = True
|
||||
|
||||
|
|
|
@ -183,11 +183,7 @@ class MCast(object):
|
|||
srv.ips[oth_ip.split("/")[0]] = ipaddress.ip_network(oth_ip, False)
|
||||
|
||||
# gvfs breaks if a linklocal ip appears in a dns reply
|
||||
ll = {
|
||||
k: v
|
||||
for k, v in srv.ips.items()
|
||||
if k.startswith("169.254") or k.startswith("fe80")
|
||||
}
|
||||
ll = {k: v for k, v in srv.ips.items() if k.startswith(("169.254", "fe80"))}
|
||||
rt = {k: v for k, v in srv.ips.items() if k not in ll}
|
||||
|
||||
if self.args.ll or not rt:
|
||||
|
|
|
@ -147,6 +147,10 @@ class PWHash(object):
|
|||
def cli(self) -> None:
|
||||
import getpass
|
||||
|
||||
if self.args.usernames:
|
||||
t = "since you have enabled --usernames, please provide username:password"
|
||||
print(t)
|
||||
|
||||
while True:
|
||||
try:
|
||||
p1 = getpass.getpass("password> ")
|
||||
|
|
|
@ -850,15 +850,6 @@ class SvcHub(object):
|
|||
|
||||
def _check_env(self) -> None:
|
||||
al = self.args
|
||||
try:
|
||||
files = os.listdir(E.cfg)
|
||||
except:
|
||||
files = []
|
||||
|
||||
hits = [x for x in files if x.lower().endswith(".conf")]
|
||||
if hits:
|
||||
t = "WARNING: found config files in [%s]: %s\n config files are not expected here, and will NOT be loaded (unless your setup is intentionally hella funky)"
|
||||
self.log("root", t % (E.cfg, ", ".join(hits)), 3)
|
||||
|
||||
if self.args.no_bauth:
|
||||
t = "WARNING: --no-bauth disables support for the Android app; you may want to use --bauth-last instead"
|
||||
|
@ -868,7 +859,7 @@ class SvcHub(object):
|
|||
|
||||
have_tcp = False
|
||||
for zs in al.i:
|
||||
if not zs.startswith("unix:"):
|
||||
if not zs.startswith(("unix:", "fd:")):
|
||||
have_tcp = True
|
||||
if not have_tcp:
|
||||
zb = False
|
||||
|
@ -878,7 +869,7 @@ class SvcHub(object):
|
|||
setattr(al, zs, False)
|
||||
zb = True
|
||||
if zb:
|
||||
t = "only listening on unix-sockets; cannot enable zeroconf/mdns/ssdp as requested"
|
||||
t = "not listening on any ip-addresses (only unix-sockets and/or FDs); cannot enable zeroconf/mdns/ssdp as requested"
|
||||
self.log("root", t, 3)
|
||||
|
||||
if not self.args.no_dav:
|
||||
|
|
|
@ -25,8 +25,8 @@ from .util import (
|
|||
termsize,
|
||||
)
|
||||
|
||||
if True:
|
||||
from typing import Generator, Union
|
||||
if True: # pylint: disable=using-constant-test
|
||||
from typing import Generator, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .svchub import SvcHub
|
||||
|
@ -245,8 +245,10 @@ class TcpSrv(object):
|
|||
|
||||
def _listen(self, ip: str, port: int) -> None:
|
||||
uds_perm = uds_gid = -1
|
||||
bound: Optional[socket.socket] = None
|
||||
tcp = False
|
||||
|
||||
if "unix:" in ip:
|
||||
tcp = False
|
||||
ipv = socket.AF_UNIX
|
||||
uds = ip.split(":")
|
||||
ip = uds[-1]
|
||||
|
@ -259,7 +261,12 @@ class TcpSrv(object):
|
|||
import grp
|
||||
|
||||
uds_gid = grp.getgrnam(uds[2]).gr_gid
|
||||
elif "fd:" in ip:
|
||||
fd = ip[3:]
|
||||
bound = socket.socket(fileno=int(fd))
|
||||
|
||||
tcp = bound.proto == socket.IPPROTO_TCP
|
||||
ipv = bound.family
|
||||
elif ":" in ip:
|
||||
tcp = True
|
||||
ipv = socket.AF_INET6
|
||||
|
@ -267,7 +274,7 @@ class TcpSrv(object):
|
|||
tcp = True
|
||||
ipv = socket.AF_INET
|
||||
|
||||
srv = socket.socket(ipv, socket.SOCK_STREAM)
|
||||
srv = bound or socket.socket(ipv, socket.SOCK_STREAM)
|
||||
|
||||
if not ANYWIN or self.args.reuseaddr:
|
||||
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
@ -285,6 +292,10 @@ class TcpSrv(object):
|
|||
if getattr(self.args, "freebind", False):
|
||||
srv.setsockopt(socket.SOL_IP, socket.IP_FREEBIND, 1)
|
||||
|
||||
if bound:
|
||||
self.srv.append(srv)
|
||||
return
|
||||
|
||||
try:
|
||||
if tcp:
|
||||
srv.bind((ip, port))
|
||||
|
@ -437,7 +448,7 @@ class TcpSrv(object):
|
|||
def detect_interfaces(self, listen_ips: list[str]) -> dict[str, Netdev]:
|
||||
from .stolen.ifaddr import get_adapters
|
||||
|
||||
listen_ips = [x for x in listen_ips if "unix:" not in x]
|
||||
listen_ips = [x for x in listen_ips if not x.startswith(("unix:", "fd:"))]
|
||||
|
||||
nics = get_adapters(True)
|
||||
eps: dict[str, Netdev] = {}
|
||||
|
|
|
@ -179,7 +179,7 @@ class Tftpd(object):
|
|||
if "::" in ips:
|
||||
ips.append("0.0.0.0")
|
||||
|
||||
ips = [x for x in ips if "unix:" not in x]
|
||||
ips = [x for x in ips if not x.startswith(("unix:", "fd:"))]
|
||||
|
||||
if self.args.tftp4:
|
||||
ips = [x for x in ips if ":" not in x]
|
||||
|
|
|
@ -375,11 +375,12 @@ class Up2k(object):
|
|||
if ineed == ihash or not ineed:
|
||||
continue
|
||||
|
||||
poke = job["poke"]
|
||||
zt = (
|
||||
ineed / ihash,
|
||||
job["size"],
|
||||
int(job["t0c"]),
|
||||
int(job["poke"]),
|
||||
int(job.get("t0c", poke)),
|
||||
int(poke),
|
||||
djoin(vtop, job["prel"], job["name"]),
|
||||
)
|
||||
ret.append(zt)
|
||||
|
|
|
@ -2982,6 +2982,17 @@ def justcopy(
|
|||
return tlen, "checksum-disabled", "checksum-disabled"
|
||||
|
||||
|
||||
def eol_conv(
|
||||
fin: Generator[bytes, None, None], conv: str
|
||||
) -> Generator[bytes, None, None]:
|
||||
crlf = conv.lower() == "crlf"
|
||||
for buf in fin:
|
||||
buf = buf.replace(b"\r", b"")
|
||||
if crlf:
|
||||
buf = buf.replace(b"\n", b"\r\n")
|
||||
yield buf
|
||||
|
||||
|
||||
def hashcopy(
|
||||
fin: Generator[bytes, None, None],
|
||||
fout: Union[typing.BinaryIO, typing.IO[Any]],
|
||||
|
|
|
@ -1374,6 +1374,7 @@ html.y #ops svg circle {
|
|||
#op_cfg input[type=text] {
|
||||
top: -.3em;
|
||||
}
|
||||
.opview select,
|
||||
.opview input[type=text] {
|
||||
color: var(--fg);
|
||||
background: var(--txt-bg);
|
||||
|
@ -1384,6 +1385,10 @@ html.y #ops svg circle {
|
|||
border-radius: .2em;
|
||||
padding: .2em .3em;
|
||||
}
|
||||
.opview select {
|
||||
padding: .3em;
|
||||
margin: .2em .4em;
|
||||
}
|
||||
.opview input.err {
|
||||
color: var(--err-fg);
|
||||
background: var(--err-bg);
|
||||
|
|
|
@ -3072,7 +3072,7 @@ var Ls = {
|
|||
|
||||
"u_https1": "für bessere Performance solltest du",
|
||||
"u_https2": "auf HTTPS wechseln",
|
||||
"u_https3": "",
|
||||
"u_https3": " ",
|
||||
"u_ancient": 'Dein Browser ist verdammt antik -- vielleicht solltest du <a href="#" onclick="goto(\'bup\')">stattdessen bup benutzen</a>',
|
||||
"u_nowork": "Benötigt Firefox 53+ oder Chrome 57+ oder iOS 11+",
|
||||
"tail_2old": "Benötigt Firefox 105+ oder Chrome 71+ oder iOS 14.5+",
|
||||
|
@ -3122,7 +3122,7 @@ var Ls = {
|
|||
"u_ehsdf": "Server hat kein Speicherplatz mehr!\n\nwerde es erneut versuchen, falls jemand\ngenug Platz schafft um fortzufahren",
|
||||
"u_emtleak1": "scheint, als ob dein Browser ein Memory Leak hätte;\nbitte",
|
||||
"u_emtleak2": ' <a href="{0}">wechsle auf HTTPS (empfohlen)</a> oder ',
|
||||
"u_emtleak3": '',
|
||||
"u_emtleak3": ' ',
|
||||
"u_emtleakc": 'versuche folgendes:\n<ul><li>drücke <code>F5</code> um die Seite neu zu laden</li><li>deaktivere dann den <code>mt</code> Button in den <code>⚙️ Einstellungen</code></li><li>und versuche den Upload nochmal.</li></ul>Uploads werden etwas langsamer sein, aber man kann ja nicht alles haben.\nSorry für die Umstände !\n\nPS: Chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">hat ein Bugfix</a> dafür',
|
||||
"u_emtleakf": 'versuche folgendes:\n<ul><li>drücke <code>F5</code> um die Seite neu zu laden</li><li>aktivere dann <code>🥔</code> (potato) im Upload UI<li>und versuche den Upload nochmal</li></ul>\nPS: Firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">hat hoffentlich irgendwann ein Bugfix</a>',
|
||||
"u_s404": "nicht auf dem Server gefunden",
|
||||
|
@ -3490,7 +3490,7 @@ var Ls = {
|
|||
"mm_uncache": "välimuisti tyhjennetty; kaikki kappaleet ladataan uudelleen seuraavalla toistolla",
|
||||
"mm_hnf": "tuota kappaletta ei enää ole olemassa",
|
||||
|
||||
" im_hnf": "tuota kuvaa ei enää ole olemassa",
|
||||
"im_hnf": "tuota kuvaa ei enää ole olemassa",
|
||||
|
||||
"f_empty": 'tämä hakemisto on tyhjä',
|
||||
"f_chide": 'tämä piilottaa sarakkeen «{0}»\n\nvoit palauttaa sarakkeet asetuksista',
|
||||
|
@ -3785,6 +3785,635 @@ var Ls = {
|
|||
|
||||
"lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?",
|
||||
},
|
||||
"grc": {
|
||||
"tt": "Ελληνικά",
|
||||
|
||||
"cols": {
|
||||
"c": "κουμπιά ενεργειών",
|
||||
"dur": "διάρκεια",
|
||||
"q": "ποιότητα / bitrate",
|
||||
"Ac": "κωδικοποιητής ήχου",
|
||||
"Vc": "κωδικοποιητής βίντεο",
|
||||
"Fmt": "μορφή / container",
|
||||
"Ahash": "checksum ήχου",
|
||||
"Vhash": "checksum βίντεο",
|
||||
"Res": "ανάλυση",
|
||||
"T": "τύπος αρχείου",
|
||||
"aq": "ποιότητα ήχου / bitrate",
|
||||
"vq": "ποιότητα βίντεο / bitrate",
|
||||
"pixfmt": "subsampling / δομή εικονοστοιχείων",
|
||||
"resw": "οριζόντια ανάλυση",
|
||||
"resh": "κάθετη ανάλυση",
|
||||
"chs": "κανάλια ήχου",
|
||||
"hz": "συχνότητα δειγματοληψίας"
|
||||
},
|
||||
|
||||
"hks": [
|
||||
[
|
||||
"διάφορα",
|
||||
["ESC", "κλείσιμο διαφόρων λειτουργιών"],
|
||||
|
||||
"διαχειριστής αρχείων",
|
||||
["G", "εναλλαγή λίστας / πλέγματος"],
|
||||
["T", "εναλλαγή μικρογραφιών / εικονιδίων"],
|
||||
["⇧ A/D", "μέγεθος μικρογραφιών"],
|
||||
["ctrl-K", "διαγραφή επιλεγμένων"],
|
||||
["ctrl-X", "αποκοπή επιλογής στο πρόχειρο"],
|
||||
["ctrl-C", "αντιγραφή επιλογής στο πρόχειρο"],
|
||||
["ctrl-V", "επικόλληση (μετακίνηση/αντιγραφή) εδώ"],
|
||||
["Y", "λήψη επιλεγμένων"],
|
||||
["F2", "μετονομασία επιλεγμένων"],
|
||||
|
||||
"λίστα αρχείων",
|
||||
["space", "εναλλαγή επιλογής αρχείου"],
|
||||
["↑/↓", "μετακίνηση δείκτη επιλογής"],
|
||||
["ctrl ↑/↓", "μετακίνηση δείκτη και προβολής"],
|
||||
["⇧ ↑/↓", "επιλογή προηγούμενου/επόμενου αρχείου"],
|
||||
["ctrl-A", "επιλογή όλων των αρχείων / φακέλων"]
|
||||
], [
|
||||
"πλοήγηση",
|
||||
["B", "εναλλαγή σε καρτέλες διαδρομών / δέντρο διαδρομών"],
|
||||
["I/K", "προηγούμενος/επόμενος φάκελος"],
|
||||
["M", "γονικός φάκελος (ή σμίκρυνση τρέχοντος)"],
|
||||
["V", "εναλλαγή φακέλων / δέντρο αρχείων κειμένου"],
|
||||
["A/D", "μέγεθος πίνακα πλοήγησης"]
|
||||
], [
|
||||
"μουσική",
|
||||
["J/L", "προηγούμενο/επόμενο τραγούδι"],
|
||||
["U/O", "μετάβαση 10δευτ πίσω/μπροστά"],
|
||||
["0..9", "μετάβαση στο 0%..90%"],
|
||||
["P", "αναπαραγωγή/παύση (ξεκινάει κιόλας)"],
|
||||
["S", "επιλογή αναπαραγόμενου τραγουδιού"],
|
||||
["Y", "λήψη τραγουδιού"]
|
||||
], [
|
||||
"εικόνες",
|
||||
["J/L, ←/→", "προηγούμενη/επόμενη εικόνα"],
|
||||
["Home/End", "πρώτη/τελευταία εικόνα"],
|
||||
["F", "πλήρης οθόνη"],
|
||||
["R", "περιστροφή δεξιόστροφα"],
|
||||
["⇧ R", "περιστροφή αριστερόστροφα"],
|
||||
["S", "επιλογή εικόνας"],
|
||||
["Y", "λήψη εικόνας"]
|
||||
], [
|
||||
"βίντεο",
|
||||
["U/O", "μετάβαση 10δευτ πίσω/μπροστά"],
|
||||
["P/K/Space", "αναπαραγωγή/παύση"],
|
||||
["C", "συνέχεια στο επόμενο"],
|
||||
["V", "επανάληψη"],
|
||||
["M", "σίγαση"],
|
||||
["[ και ]", "ορισμός διαστήματος επανάληψης"]
|
||||
], [
|
||||
"αρχεία κειμένου",
|
||||
["I/K", "προηγούμενο/επόμενο αρχείο"],
|
||||
["M", "κλείσιμο αρχείου"],
|
||||
["E", "επεξεργασία αρχείου"],
|
||||
["S", "επιλογή αρχείου (για αποκοπή/αντιγραφή/μετονομασία)"]
|
||||
]
|
||||
],
|
||||
|
||||
"m_ok": "Εντάξει",
|
||||
"m_ng": "Άκυρο",
|
||||
|
||||
"enable": "Ενεργοποίηση",
|
||||
"danger": "ΚΙΝΔΥΝΟΣ",
|
||||
"clipped": "αντιγράφηκε στο πρόχειρο",
|
||||
|
||||
"ht_s1": "δευτερόλεπτο",
|
||||
"ht_s2": "δευτερόλεπτα",
|
||||
"ht_m1": "λεπτό",
|
||||
"ht_m2": "λεπτά",
|
||||
"ht_h1": "ώρα",
|
||||
"ht_h2": "ώρες",
|
||||
"ht_d1": "μέρα",
|
||||
"ht_d2": "μέρες",
|
||||
"ht_and": " και ",
|
||||
|
||||
"goh": "πίνακας ελέγχου",
|
||||
"gop": 'προηγούμενος φάκελος στο ίδιο επίπεδο">προηγούμενο',
|
||||
"gou": 'γονικός φάκελος">πάνω',
|
||||
"gon": 'επόμενος φάκελος">επόμενο',
|
||||
"logout": "Αποσύνδεση ",
|
||||
"access": " πρόσβαση",
|
||||
"ot_close": "κλείσιμο υπομενού",
|
||||
"ot_search": "αναζήτηση αρχείων με βάση χαρακτηριστικά, διαδρομή / όνομα, μουσικά tags ή οποιονδήποτε συνδυασμό$N$N<code>foo bar</code> = πρέπει να περιέχει και τα «foo» και «bar»,$N<code>foo -bar</code> = πρέπει να περιέχει το «foo» αλλά όχι το «bar»,$N<code>^yana .opus$</code> = να ξεκινά με «yana» και να είναι αρχείο «opus»$N<code>"try unite"</code> = να περιέχει ακριβώς «try unite»$N$Nη μορφή ημερομηνίας είναι iso-8601, όπως$N<code>2009-12-31</code> ή <code>2020-09-12 23:30:00</code>",
|
||||
"ot_unpost": "unpost: διαγραφή πρόσφατων μεταφορτώσεων ή ακύρωση ανολοκλήρωτων",
|
||||
"ot_bup": "bup: βασικός uploader, υποστηρίζει μέχρι και netscape 4.0",
|
||||
"ot_mkdir": "mkdir: δημιουργία νέου φακέλου",
|
||||
"ot_md": "new-md: δημιουργία νέου markdown εγγράφου",
|
||||
"ot_msg": "msg: αποστολή μηνύματος στο server log",
|
||||
"ot_mp": "επιλογές media player",
|
||||
"ot_cfg": "επιλογές ρυθμίσεων",
|
||||
"ot_u2i": 'up2k: ανέβασε αρχεία (αν έχεις δικαίωμα εγγραφής) ή ενεργοποίησε τη λειτουργία αναζήτησης για να δεις αν υπάρχουν ήδη στο server$N$Nοι μεταφορτώσεις συνεχίζονται αν διακοπούν, είναι πολυνηματικές και διατηρούν τις χρονοσφραγίδες, αλλά καταναλώνουν περισσότερο CPU από τον [🎈] (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!',
|
||||
"ot_u2w": 'up2k: ανέβασε αρχεία με υποστήριξη συνέχισης (κλείσε τον browser και ρίξε τα ίδια αρχεία ξανά μετά)$N$Nπολυνηματικό, διατηρεί τις χρονοσφραγίδες, αλλά καταναλώνει περισσότερο CPU από τον [🎈] (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!',
|
||||
"ot_noie": 'Χρησιμοποίησε Chrome / Firefox / Edge',
|
||||
|
||||
"ab_mkdir": "δημιουργία φακέλου",
|
||||
"ab_mkdoc": "νέο markdown έγγραφο",
|
||||
"ab_msg": "στείλε μήνυμα στο server log",
|
||||
|
||||
"ay_path": "πήγαινε σε φακέλους",
|
||||
"ay_files": "πήγαινε σε αρχεία",
|
||||
|
||||
"wt_ren": "μετονομασία επιλεγμένων$NΣυντόμευση: F2",
|
||||
"wt_del": "διαγραφή επιλεγμένων$NΣυντόμευση: ctrl-K",
|
||||
"wt_cut": "αποκοπή επιλεγμένων <small>(και επικόλληση αλλού)</small>$NΣυντόμευση: ctrl-X",
|
||||
"wt_cpy": "αντιγραφή επιλεγμένων στο πρόχειρο$N(για επικόλληση αλλού)$NΣυντόμευση: ctrl-C",
|
||||
"wt_pst": "επικόλληση αποκομμένων / αντεγραμμένων$NΣυντόμευση: ctrl-V",
|
||||
"wt_selall": "επιλογή όλων$NΣυντόμευση: ctrl-A (με το αρχείο επιλεγμένο)",
|
||||
"wt_selinv": "αντιστροφή επιλογής",
|
||||
"wt_zip1": "κατέβασμα φακέλου ως συμπιεσμένο αρχείο",
|
||||
"wt_selzip": "κατέβασμα επιλογής ως συμπιεσμένο αρχείο",
|
||||
"wt_seldl": "κατέβασμα επιλογής ως μεμονωμένα αρχεία$NΣυντόμευση: Y",
|
||||
"wt_npirc": "αντιγραφή πληροφοριών τραγουδιού σε μορφή irc",
|
||||
"wt_nptxt": "αντιγραφή πληροφοριών τραγουδιού ως κείμενο",
|
||||
"wt_m3ua": "προσθήκη σε m3u λίστα αναπαραγωγής (μετά πάτησε <code>📻αντιγραφή</code>)",
|
||||
"wt_m3uc": "αντιγραφή m3u λίστας αναπαραγωγής στο πρόχειρο",
|
||||
"wt_grid": "εναλλαγή πλέγματος / λίστας$NΣυντόμευση: G",
|
||||
"wt_prev": "προηγούμενο κομμάτι$NΣυντόμευση: J",
|
||||
"wt_play": "αναπαραγωγή / παύση$NΣυντόμευση: P",
|
||||
"wt_next": "επόμενο κομμάτι$NΣυντόμευση: L",
|
||||
|
||||
"ul_par": "παράλληλες μεταφορτώσεις:",
|
||||
"ut_rand": "τυχαιοποίηση ονομάτων αρχείων",
|
||||
"ut_u2ts": "αντιγραφή της τελευταίας τροποποιημένης χρονοσφραγίδας αλλαγής$Nαπό το σύστημά σου στον server\">📅",
|
||||
"ut_ow": "αντικατάσταση σε ήδη υπάρχοντα αρχεία του server?$N🛡️: ποτέ (θα δημιουργηθεί νέο όνομα)$N🕒: αν το αρχείο του server είναι παλαιότερο$N♻️: πάντα να αντικαθίστανται αν διαφέρουν",
|
||||
"ut_mt": "συνέχιση υπολογισμού hash για άλλα αρχεία κατά τη μεταφόρτωση$N$Nαπενεργοποίησέ το αν η CPU ή ο δίσκος σου ζορίζονται",
|
||||
"ut_ask": 'επιβεβαίωση πριν ξεκινήσει η μεταφόρτωση">💭',
|
||||
"ut_pot": "βελτίωση ταχύτητας μεταφόρτωσης σε αργές συσκευές$Nμε απλοποίηση του UI",
|
||||
"ut_srch": "μην ανεβάζεις, έλεγξε αν τα αρχεία$Nυπάρχουν ήδη στον server (ψάχνει σε όλους τους φακέλους που έχεις πρόσβαση)",
|
||||
"ut_par": "κάνε παύση στις μεταφορτώσεις βάζοντάς το 0$N$Nαύξησε το αν έχεις αργή/μεγάλη καθυστέρηση σύνδεσης$N$Nκράτα το 1 σε LAN ή αν ο server έχει αργό δίσκο",
|
||||
"ul_btn": "ρίξε αρχεία / φακέλους<br>εδώ (ή κάνε κλικ σε μένα)",
|
||||
"ul_btnu": "Μ Ε Τ Α Φ Ο Ρ Τ Ω Σ Η",
|
||||
"ul_btns": "Α Ν Α Ζ Η Τ Η Σ Η",
|
||||
|
||||
"ul_hash": "υπολογισμός hash",
|
||||
"ul_send": "αποστολή",
|
||||
"ul_done": "ολοκληρώθηκε",
|
||||
"ul_idle1": "καμία μεταφόρτωση στην ουρά για την ώρα",
|
||||
"ut_etah": "μέση ταχύτητα <em>υπολογισμού hash</em> και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
|
||||
"ut_etau": "μέση ταχύτητα <em>μεταφόρτωσης</em> και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
|
||||
"ut_etat": "μέση <em>συνολική</em> ταχύτητα και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
|
||||
|
||||
"uct_ok": "ολοκληρώθηκε επιτυχώς",
|
||||
"uct_ng": "no-good: απέτυχε / απορρίφθηκε / δεν βρέθηκε",
|
||||
"uct_done": "ολοκληρωμένα και αποτυχημένα",
|
||||
"uct_bz": "κάνει hash ή μεταφορτώνει",
|
||||
"uct_q": "σε αναμονή, εκκρεμεί",
|
||||
|
||||
"utl_name": "όνομα αρχείου",
|
||||
"utl_ulist": "λίστα",
|
||||
"utl_ucopy": "αντιγραφή",
|
||||
"utl_links": "σύνδεσμοι",
|
||||
"utl_stat": "κατάσταση",
|
||||
"utl_prog": "πρόοδος",
|
||||
|
||||
// keep short:
|
||||
"utl_404": "404",
|
||||
"utl_err": "ΣΦΑΛΜΑ",
|
||||
"utl_oserr": "ΣΦ-ΛΕ",
|
||||
"utl_found": "βρέθηκε",
|
||||
"utl_defer": "αναβολή",
|
||||
"utl_yolo": "YOLO",
|
||||
"utl_done": "έγινε",
|
||||
|
||||
"ul_flagblk": "τα αρχεία προστέθηκαν στην ουρά</b><br>αλλά υπάρχει άλλη ενεργή μεταφόρτωση σε άλλη καρτέλα,<br>οπότε περίμενε να τελειώσει αυτό πρώτα",
|
||||
"ul_btnlk": "ο διακομιστής έχει κλειδώσει αυτήν την επιλογή σε αυτήν την κατάσταση",
|
||||
|
||||
"udt_up": "Μεταφόρτωση",
|
||||
"udt_srch": "Αναζήτηση",
|
||||
"udt_drop": "ρίξ' το εδώ",
|
||||
|
||||
"u_nav_m": '<h6>οκ, τι έχουμε εδώ;</h6><code>Enter</code> = Αρχεία (ένα ή περισσότερα)\n<code>ESC</code> = Ένας φάκελος (μαζί με υποφακέλους)',
|
||||
"u_nav_b": '<a href="#" id="modal-ok">Αρχεία</a><a href="#" id="modal-ng">Ένας φάκελος</a>',
|
||||
|
||||
"cl_opts": "διακόπτες",
|
||||
"cl_themes": "θέμα",
|
||||
"cl_langs": "γλώσσα",
|
||||
"cl_ziptype": "λήψη φακέλου",
|
||||
"cl_uopts": "διακόπτες μεταφόρτωσης",
|
||||
"cl_favico": "favicon",
|
||||
"cl_bigdir": "μεγάλοι φάκελοι",
|
||||
"cl_hsort": "#ταξινόμηση",
|
||||
"cl_keytype": "σημείωση πλήκτρων",
|
||||
"cl_hiddenc": "κρυφές στήλες",
|
||||
"cl_hidec": "κρύψε",
|
||||
"cl_reset": "επανεκκίνηση",
|
||||
"cl_hpick": "πάτησε στις κεφαλίδες στηλών για να τις κρύψεις στον πίνακα παρακάτω",
|
||||
"cl_hcancel": "η απόκρυψη στηλών ακυρώθηκε",
|
||||
|
||||
"ct_grid": '田 το πλέγμα',
|
||||
"ct_ttips": '◔ ◡ ◔">ℹ️ συμβουλές εργαλείων',
|
||||
"ct_thumb": 'σε προβολή πλέγματος, εναλλαγή εικονιδίων ή μικρογραφιών$NΠλήκτρο συντόμευσης: T">🖼️ μικρογραφίες',
|
||||
"ct_csel": 'χρησιμοποίησε CTRL και SHIFT για επιλογή αρχείων σε προβολή πλέγματος">επιλογή',
|
||||
"ct_ihop": 'όταν η προβολή εικόνων κλείνει, κάνε scroll στο τελευταίο προβολόμενο αρχείο">g⮯',
|
||||
"ct_dots": 'εμφάνιση κρυφών αρχείων (αν το επιτρέπει ο server)">dotfiles',
|
||||
"ct_qdel": 'όταν διαγράφεις αρχεία, ζήτα επιβεβαίωση μόνο μία φορά">γρήγορη διαγραφή',
|
||||
"ct_dir1st": 'ταξινόμηση φακέλων πριν από τα αρχεία">📁 πρώτα',
|
||||
"ct_nsort": 'φυσική ταξινόμηση (για ονόματα αρχείων με αριθμούς στην αρχή)">φυσική ταξινόμηση',
|
||||
"ct_utc": 'εμφάνιση όλων των ημερομηνιών σε UTC">UTC',
|
||||
"ct_readme": 'εμφάνιση README.md στις λίστες φακέλων">📜 πληροφορίες',
|
||||
"ct_idxh": 'εμφάνιση index.html αντί για λίστα φακέλων">html',
|
||||
"ct_sbars": 'εμφάνιση μπαρών κύλισης">⟊',
|
||||
|
||||
"cut_umod": "αν το αρχείο υπάρχει ήδη στον server, ενημέρωσέ το με την τελευταία χρονοσφραγίδα τροποποίησης για να ταιριάζει με το τοπικό αρχείο (απαιτεί δικαιώματα εγγραφής+διαγραφής)\">re📅",
|
||||
|
||||
"cut_turbo": "το κουμπί yolo, πιθανόν να ΜΗΝ ΘΕΛΕΙΣ να το ενεργοποιήσεις:$N$Nχρησιμοποίησέ το αν μεταφορτώνεις πολλά αρχεία και χρειάστηκε να ξαναρχίσεις, και θες να συνεχίσεις τη μεταφότρωση όσο το δυνατόν πιο γρήγορα$N$Nαντικαθιστά τον έλεγχο hash με απλό <em>"έχει το ίδιο μέγεθος αρχείου στον server?"</em> οπότε αν το περιεχόμενο είναι διαφορετικό, ΔΕΝ θα ανέβει$N$Nπρέπει να το κλείσεις όταν τελειώσει η μεταφόρτωση και μετά να "μεταφορτώσεις" πάλι τα ίδια αρχεία για να τα επιβεβαιώσει το τοπικό σου πρόγραμμα\">turbo",
|
||||
|
||||
"cut_datechk": "δεν επηρεάζει τίποτα εκτός αν το turbo είναι ενεργοποιημένο$N$Nμειώνει λίγο τον παράγοντα yolo; ελέγχει αν οι χρονοσφραγίδες στο διακομιστή ταιριάζουν με τα δικά σου$N$Nπιάνει <em>θεωρητικά</em> τις περισσότερες μισοτελειωμένες/κατεστραμμένες μεταφορτώσεις, αλλά δεν αντικαθιστά τον έλεγχο με το turbo απενεργοποιημένο μετέπειτα\">έλεγχος ημερομηνίας",
|
||||
|
||||
"cut_u2sz": "μέγεθος (σε MiB) κάθε κομματιού μεταφόρτωσης; μεγάλες τιμές λειτουργούν καλύτερα σε μεγαλύτερες αποστάσεις διακομιστή-πελάτη. Δοκίμασε μικρές τιμές σε πολύ άστατες συνδέσεις",
|
||||
|
||||
"cut_flag": "εξασφαλίζει ότι μόνο μία καρτέλα μεταφορτώνει κάθε φορά $N -- οι άλλες καρτέλες πρέπει να το έχουν κι αυτές ενεργό $N -- επηρεάζει μόνο τις καρτέλες που βρίσκονται στο ίδιο διεύθυνση",
|
||||
|
||||
"cut_az": "μεταφόρτωσε τα αρχεία αλφαβητικά, αντί για το μικρότερο αρχείο, πρώτα$N$Nη αλφαβητική σειρά βοηθά να καταλάβεις αν κάτι χάλασε στο διακομιστή αλλά κάνει το ανέβασμα λίγο πιο αργό σε fiber / LAN",
|
||||
|
||||
"cut_nag": "ειδοποίηση λειτουργικού συστήματος όταν τελειώσει η μεταφόρτωση$N(μόνο αν ο browser ή η καρτέλα δεν είναι ενεργά)",
|
||||
"cut_sfx": "ηχητική ειδοποίηση όταν τελειώσει η μεταφόρτωση$N(μόνο αν ο browser ή η καρτέλα δεν είναι ενεργά)",
|
||||
|
||||
"cut_mt": "χρησιμοποίησε multithreading για να επιταχύνεις το hashing των αρχείων$N$Nχρησιμοποιεί web-workers και χρειάζεται$Nπερισσότερη RAM (μέχρι 512 MiB επιπλέον)$N$Nκάνει το https 30% πιο γρήγορο, το http 4.5x πιο γρήγορο\">mt",
|
||||
|
||||
"cut_wasm": "χρησιμοποίησε wasm αντί για τον ενσωματωμένο hasher του browser; βελτιώνει την ταχύτητα σε chrome-based browsers αλλά αυξάνει το φορτίο της CPU, και παλιές εκδόσεις chrome έχουν bugs που κάνουν το browser να τρώει όλη τη RAM και να κρασάρει αν ενεργοποιηθεί\">wasm",
|
||||
|
||||
"cft_text": "κείμενο favicon (κενό και ανανέωση για απενεργοποίηση)",
|
||||
"cft_fg": "χρώμα προσκηνίου",
|
||||
"cft_bg": "χρώμα παρασκηνίου",
|
||||
|
||||
"cdt_lim": "μέγιστος αριθμός αρχείων προς εμφάνιση σε ένα φάκελο",
|
||||
"cdt_ask": "όταν φτάνεις στο τέλος,$Nαντί να φορτώσει περισσότερα αρχεία,$Nρώτα τι να κάνει",
|
||||
"cdt_hsort": "πόσους κανόνες ταξινόμησης (<code>,sorthref</code>) να συμπεριλάβει σε URLs πολυμέσων. Αν το βάλεις 0 αγνοεί και κανόνες ταξινόμησης στους συνδέσμους πολυμέσων",
|
||||
|
||||
"tt_entree": "εμφάνιση navpane (δέντρο διαδρομών)$NΠλήκτρο συντόμευσης: B",
|
||||
"tt_detree": "εμφάνιση breadcrumbs (καρτέλες διαδρομών)$NΠλήκτρο συντόμευσης: B",
|
||||
"tt_visdir": "κύλιση στον επιλεγμένο φάκελο",
|
||||
"tt_ftree": "εναλλαγή δέντρου διαδρομών / αρχείων κειμένου$NΠλήκτρο συντόμευσης: V",
|
||||
"tt_pdock": "εμφάνιση γονικών φακέλων σε σταθερή μπάρα επάνω",
|
||||
"tt_dynt": "αυτόματη επέκταση καθώς επεκτείνεται το δέντρο διαδρομών",
|
||||
"tt_wrap": "αναδίπλωση λέξεων",
|
||||
"tt_hover": "αποκάλυψη των γραμμών που ξεπερνούν το πλάτος με το ποντίκι πάνω τους$N( σπάει το scroll εκτός αν το ποντίκι $N είναι στην αριστερή στήλη )",
|
||||
|
||||
"ml_pmode": "στο τέλος του φακέλου...",
|
||||
"ml_btns": "εντολές",
|
||||
"ml_tcode": "μετακωδικοποίηση",
|
||||
"ml_tcode2": "μετακωδικοποίηση σε",
|
||||
"ml_tint": "φίλτρο χρώματος",
|
||||
"ml_eq": "ισοσταθμιστής ήχου",
|
||||
"ml_drc": "συμπιεστής δυναμικής εμβέλειας",
|
||||
|
||||
"mt_loop": "επανάληψη ενός τραγουδιού\">🔁",
|
||||
"mt_one": "σταμάτα μετά από ένα τραγούδι\">1️⃣",
|
||||
"mt_shuf": "τυχαία σειρά τραγουδιών σε κάθε φάκελο\">🔀",
|
||||
"mt_aplay": "αυτόματη αναπαραγωγή αν υπάρχει song-ID στη διεύθυνση που μπήκες στο διακομιστή$N$Nη απενεργοποίηση αυτού, σταματά το URL από το να ενημερώνεται με τα song-ID ενώ παίζει η μουσική για να αποτραπεί η αυτόματη αναπαραγωγή αν χαθούν αυτές οι ρυθμίσεις αλλά το URL παραμείνει το ίδιο\">a▶",
|
||||
"mt_preload": "ξεκίνα τη φόρτωση του επόμενου τραγουδιού κοντά στο τέλος για συνεχόμενη ακρόαση\">προφόρτωση",
|
||||
"mt_prescan": "πήγαινε στον επόμενο φάκελο πριν τελειώσει το τελευταίο τραγούδι$Nγια να μη σταματήσει το πρόγραμμα περιήγησης να παίζει μουσική\">nav",
|
||||
"mt_fullpre": "προσπάθησε να προφορτώσεις ολόκληρο το τραγούδι;$N✅ ενεργό σε <b>αναξιόπιστες</b> συνδέσεις,$N❌ πιθανότατα απενεργοποιημένο σε αργές συνδέσεις\">πλήρες",
|
||||
"mt_fau": "σε κινητά, πρόλαβε να μην σταματήσει η μουσική αν το επόμενο τραγούδι δεν προφορτώθηκε γρήγορα (μπορεί να προκαλέσει πρόβλημα στην εμφάνιση των ετικετών)\">☕️",
|
||||
"mt_waves": "γραμμή αναζήτησης κυματομορφής:$Nεμφάνιση έντασης ήχου στην μπάρα αναζήτησης\">~s",
|
||||
"mt_npclip": "εμφάνισε κουμπιά για αντιγραφή του τρέχοντος τραγουδιού\">/np",
|
||||
"mt_m3u_c": "εμφάνισε κουμπιά για αντιγραφή των$Nεπιλεγμένων τραγουδιών ως καταχωρήσεις λίστας m3u8\">📻",
|
||||
"mt_octl": "ενσωμάτωση στο λειτουργικό σύστημα (σηντομεύσεις πλήκτρων πολυμέσων / osd)\">έλεγχος-OS",
|
||||
"mt_oseek": "επιτρέπει την αναζήτηση μέσω ενσωμάτωσης του λειτουργικού συστήματος$N$Nσημείωση: σε μερικές συσκευές (iPhones),$Nαντικαθιστά το κουμπί επόμενου τραγουδιού\">αναζήτηση",
|
||||
"mt_oscv": "εμφάνιση εξωφύλλου άλμπουμ σε osd\">εξώφυλλο",
|
||||
"mt_follow": "κρατά το τρέχον κομμάτι ορατό κατά την κύλιση\">🎯",
|
||||
"mt_compact": "συμπαγή κουμπιά ελέγχου\">⟎",
|
||||
"mt_uncache": "καθάρισε την προσωρινή μνήμη (δοκίμασε αυτό αν ο browser έχει αποθηκεύσει$Nχαλασμένο αντίγραφο τραγουδιού και αρνείται να παίξει)\">εκκαθάριση",
|
||||
"mt_mloop": "τυχαία αναπαραγωγή στον ανοικτό φάκελο\">🔁 τυχαία αναπαραγωγή",
|
||||
"mt_mnext": "φόρτωση επόμενου φακέλου και συνέχιση\">📂 επόμενο",
|
||||
"mt_mstop": "σταμάτησε την αναπαραγωγή\">⏸ σταμάτημα",
|
||||
"mt_cflac": "μετατροπή flac / wav σε opus\">flac",
|
||||
"mt_caac": "μετατροπή aac / m4a σε opus\">aac",
|
||||
"mt_coth": "μετατροπή όλων των άλλων (εκτός των mp3) σε opus\">άλλο",
|
||||
"mt_c2opus": "καλύτερη επιλογή για desktop, laptop, android\">opus",
|
||||
"mt_c2owa": "opus-weba, για iOS 17.5 και νεότερα\">owa",
|
||||
"mt_c2caf": "opus-caf, για iOS 11 έως 17\">caf",
|
||||
"mt_c2mp3": "χρησιμοποίησε αυτό σε πολύ παλιές συσκευές\">mp3",
|
||||
"mt_c2flac": "βέλτιστη ποιότητα ήχου αλλά τεράστιο αρχείο για μεταφόρτωση\">flac",
|
||||
"mt_c2wav": "ασυμπίεστη αναπαραγωγή (ακόμα μεγαλύτερο αρχείο)\">wav",
|
||||
"mt_c2ok": "μια χαρά, σοφή επιλογή",
|
||||
"mt_c2nd": "δεν είναι η προτεινόμενη μορφή εξόδου για τη συσκευή σου, αλλά αυτό είναι ok",
|
||||
"mt_c2ng": "η συσκευή σου φαίνεται να μην υποστηρίζει αυτήν τη μορφή εξόδου, αλλά ας το δοκιμάσουμε ούτως ή άλλως",
|
||||
"mt_xowa": "υπάρχουν bugs σε iOS που εμποδίζουν την αναπαραγωγή στο παρασκήνιο με αυτήν τη μορφή· χρησιμοποίησε caf ή mp3 αντ’ αυτού",
|
||||
"mt_tint": "επίπεδο φόντου (0-100) στην μπάρα αναζήτησης$Nγια να κάνεις το buffering λιγότερο ενοχλητικό",
|
||||
"mt_eq": "ενεργοποιεί τον ισοσταθμιστή και τον έλεγχο ενίσχυσης;$N$Nενίσχυση <code>0</code> = στάνταρ 100% ένταση (απαράλλαχτη)$N$Nεύρος <code>1 </code> = στάνταρ στερεοφωνικό (απαράλλαχτο)$Nεύρος <code>0.5</code> = 50% αριστερά-δεξιά μίξη ήχου$Nεύρος <code>0 </code> = μονοφωνικό$N$Nενίσχυση <code>-0.8</code> & εύρος <code>10</code> = αφαίρεση φωνής :^)$N$Nη ενεργοποίηση του ισοσταθμιστή κάνει τα άλμπουμ χωρίς κενά, να παίζουν χωρίς καθόλου κενά, οπότε άφησέ το ενεργό με όλες τις τιμές στο μηδέν (εκτός από εύρος = 1) αν σε νοιάζει",
|
||||
"mt_drc": "ενεργοποιεί τον συμπιεστή δυναμικής εμβέλειας (εξομάλυνση έντασης / ακραία συμπίεση έντασης); θα ενεργοποιήσει και τον ισοσταθμιστή για να ισορροπήσει τον ήχο, οπότε βάλε όλα τα πεδία ισοσταθμιστή εκτός από το 'εύρος' στο 0 αν δεν το θες$N$Nχαμηλώνει την ένταση του ήχου πάνω από το όριο (THRESHOLD) dB; για κάθε RATIO dB πέρα από το όριο υπάρχει 1 dB εξόδου, οπότε οι προεπιλεγμένες τιμές όριο -24 και 'λόγος' 12 σημαίνουν ότι δεν θα ξεπεράσει ποτέ τα -22 dB και είναι ασφαλές να αυξήσεις την ενίσχυση ισοσταθμιστή σε 0.8, ή και 1.8 με ATK 0 και μεγάλο RLS όπως 90 (δουλεύει μόνο σε firefox· το RLS είναι max 1 σε άλλους browsers)$N$N(δες wikipedia, το εξηγούν καλύτερα)",
|
||||
|
||||
"mb_play": "παίξε",
|
||||
"mm_hashplay": "να παίξω αυτό το αρχείο ήχου;",
|
||||
"mm_m3u": "πάτα <code>Enter/OK</code> για Αναπαραγωγή\nπάτα <code>ESC/Άκυρο</code> για Επεξεργασία",
|
||||
"mp_breq": "χρειάζεται firefox 82+ ή chrome 73+ ή iOS 15+",
|
||||
"mm_bload": "φορτώνει...",
|
||||
"mm_bconv": "μετατροπή σε {0}, περίμενε...",
|
||||
"mm_opusen": "ο browser σου δεν παίζει αρχεία aac / m4a;\nη μετατροπή σε opus είναι τώρα ενεργή",
|
||||
"mm_playerr": "η αναπαραγωγή, απέτυχε: ",
|
||||
"mm_eabrt": "Η προσπάθεια αναπαραγωγής ακυρώθηκε",
|
||||
"mm_enet": "Η σύνδεση του ίντερνέτ σου είναι χάλια",
|
||||
"mm_edec": "Το αρχείο αυτό είναι μάλλον κατεστραμμένο;;",
|
||||
"mm_esupp": "Ο browser σου δεν καταλαβαίνει αυτή τη μορφή ήχου",
|
||||
"mm_eunk": "Άγνωστο σφάλμα",
|
||||
"mm_e404": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 404: Το αρχείο δεν βρέθηκε.",
|
||||
"mm_e403": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 403: Άρνηση πρόσβασης.\n\nΔοκίμασε F5 για επαναφόρτωση, ίσως να έχεις αποσυνδεθεί",
|
||||
"mm_e500": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 500: Έλεγξε τα logs του διακομιστή.",
|
||||
"mm_e5xx": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα διακομιστή",
|
||||
"mm_nof": "δεν βρέθηκαν άλλα αρχεία ήχου τριγύρω",
|
||||
"mm_prescan": "Αναζήτηση μουσικής για επόμενο τραγούδι...",
|
||||
"mm_scank": "Βρέθηκε το επόμενο τραγούδι:",
|
||||
"mm_uncache": "κρυφή μνήμη καθαρίστηκε· όλα τα τραγούδια θα ξανακατεβούν στην επόμενη αναπαραγωγή",
|
||||
"mm_hnf": "το τραγούδι αυτό πλέον δεν υπάρχει",
|
||||
|
||||
"im_hnf": "η εικόνα αυτή πλέον δεν υπάρχει",
|
||||
|
||||
"f_empty": "αυτός ο φάκελος είναι άδειος",
|
||||
"f_chide": "αυτό θα κρύψει τη στήλη «{0}»\n\nμπορείς να εμφανίσεις τις στήλες από τις ρυθμίσεις",
|
||||
"f_bigtxt": "αυτό το αρχείο είναι {0} MiB σε μέγεθος — σίγουρα θέλεις να το δεις ως κείμενο;",
|
||||
"f_bigtxt2": "να δεις μόνο το τέλος του αρχείου αντί για όλο; αυτό ενεργοποιεί και το following/tailing, που δείχνει νέες γραμμές που προστίθενται ζωντανά",
|
||||
"fbd_more": '<div id="blazy">εμφανίζονται <code>{0}</code> από <code>{1}</code> αρχεία; <a href="#" id="bd_more">δείξε {2}</a> ή <a href="#" id="bd_all">δείξε τα όλα</a></div>',
|
||||
"fbd_all": '<div id="blazy">εμφανίζονται <code>{0}</code> από <code>{1}</code> αρχεία; <a href="#" id="bd_all">δείξε όλα</a></div>',
|
||||
"f_anota": "μόνο {0} από τα {1} αντικείμενα επιλέχθηκαν;\nγια να επιλέξεις ολόκληρο το φάκελο, κύλησε πρώτα μέχρι κάτω",
|
||||
|
||||
"f_dls": 'οι σύνδεσμοι αρχείων στον τρέχοντα φάκελο έχουν\nμετατραπεί σε συνδέσμους λήψης',
|
||||
|
||||
"f_partial": "Για να κατεβάσεις με ασφάλεια ένα αρχείο που ανεβαίνει, κλίκαρε το αρχείο με το ίδιο όνομα, αλλά χωρίς την κατάληξη <code>.PARTIAL</code>. Πάτα Άκυρο ή Escape για να σταματήσεις.\n\nΠάτα OK / Enter αν αγνοείς την προειδοποίηση και κατέβασε το <code>.PARTIAL</code> αρχείο, που σχεδόν σίγουρα θα είναι κατεστραμμένο.",
|
||||
|
||||
"ft_paste": "επικόλλησε {0} αντικείμενα$NΠλήκτρο συντόμευσης: ctrl-V",
|
||||
"fr_eperm": 'δεν μπορεί να μετονομαστεί:\nδεν έχεις δικαίωμα “μετακίνησης” σε αυτόν το φάκελο',
|
||||
"fd_eperm": 'δεν μπορεί να διαγραφεί:\nδεν έχεις δικαίωμα “διαγραφής” σε αυτόν το φάκελο',
|
||||
"fc_eperm": 'δεν μπορεί να κοπεί:\nδεν έχεις δικαίωμα “μετακίνησης” σε αυτόν το φάκελο',
|
||||
"fp_eperm": 'δεν μπορεί να επικολληθεί:\nδεν έχεις δικαίωμα “εγγραφής” σε αυτόν το φάκελο',
|
||||
"fr_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για μετονομασία",
|
||||
"fd_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για διαγραφή",
|
||||
"fc_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για αποκοπή",
|
||||
"fcp_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για αντιγραφή στο πρόχειρο",
|
||||
|
||||
"fs_sc": "μοιράσου το φάκελο που βρίσκεσαι",
|
||||
"fs_ss": "μοιράσου τα επιλεγμένα αρχεία",
|
||||
"fs_just1d": "δεν μπορείς να επιλέξεις περισσότερους από έναν φακέλους,\nή να αναμείξεις αρχεία και φακέλους στην ίδια επιλογή",
|
||||
"fs_abrt": "❌ ακύρωση",
|
||||
"fs_rand": "🎲 τυχαίο όνομα",
|
||||
"fs_go": "✅ δημιούργησε κοινή χρήση",
|
||||
"fs_name": "όνομα",
|
||||
"fs_src": "πηγή",
|
||||
"fs_pwd": "κωδικός",
|
||||
"fs_exp": "λήξη",
|
||||
"fs_tmin": "λεπτά",
|
||||
"fs_thrs": "ώρες",
|
||||
"fs_tdays": "ημέρες",
|
||||
"fs_never": "αιώνιο",
|
||||
"fs_pname": "προαιρετικό όνομα συνδέσμου; αν είναι κενό, θα είναι τυχαίο",
|
||||
"fs_tsrc": "το αρχείο ή ο φάκελος προς κοινή χρήση",
|
||||
"fs_ppwd": "προαιρετικός κωδικός",
|
||||
"fs_w8": "δημιουργία κοινής χρήσης...",
|
||||
"fs_ok": "πάτα <code>Enter/OK</code> για Πρόχειρο\nπάτα <code>ESC/Άκυρο</code> για Κλείσιμο",
|
||||
|
||||
"frt_dec": "μπορεί να διορθώσει μερικές περιπτώσεις κατεστραμμένων ονομάτων αρχείων\">αποκωδικοποίηση url",
|
||||
"frt_rst": "επανέφερε τα ονόματα αρχείων στα αρχικά τους\">↺ επαναφορά",
|
||||
"frt_abrt": "ακύρωσε και κλείσε αυτό το παράθυρο\">❌ ακύρωση",
|
||||
"frb_apply": "ΕΦΑΡΜΟΓΗ ΜΕΤΟΝΟΜΑΣΙΑΣ",
|
||||
"fr_adv": "μαζική / μεταδεδομένα / μετονομασία με πρότυπα\">προχωρημένη",
|
||||
"fr_case": "regex με διάκριση πεζών/κεφαλαίων\">case",
|
||||
"fr_win": "ασφαλή ονόματα για windows; αντικαθιστά <code><>:"\\|?*</code> με ιαπωνικούς χαρακτήρες πλήρους πλάτους\">win",
|
||||
"fr_slash": "αντικαθίσταται <code>/</code> με χαρακτήρα που δεν δημιουργεί νέους φακέλους\">όχι /",
|
||||
"fr_re": "μοτίβα αναζήτησης (regex) για αναζήτηση στα αρχικά ονόματα; τα καταγραφόμενα groups μπορούν να χρησιμοποιηθούν στο πεδίο μορφοποίησης παρακάτω όπως <code>(1)</code> και <code>(2)</code> και ούτω καθεξής",
|
||||
"fr_fmt": "εμπνευσμένο από foobar2000:$N<code>(title)</code> αντικαθίσταται από τίτλο τραγουδιού,$N<code>[(artist) - ](title)</code> παραλείπει το [this] αν το artist είναι κενό$N<code>$lpad((tn),2,0)</code> γεμίζει τον αριθμό κομματιού σε 2 ψηφία",
|
||||
"fr_pdel": "διαγραφή",
|
||||
"fr_pnew": "αποθήκευση ως",
|
||||
"fr_pname": "δώσε όνομα για τη νέα προεπιλογή",
|
||||
"fr_aborted": "ακυρώθηκε",
|
||||
"fr_lold": "παλιό όνομα",
|
||||
"fr_lnew": "νέο όνομα",
|
||||
"fr_tags": "ετικέτες για τα επιλεγμένα αρχεία (μόνο για ανάγνωση):",
|
||||
"fr_busy": "μετονομασία {0} αντικειμένων...\n\n{1}",
|
||||
"fr_efail": "αποτυχία μετονομασίας:\n",
|
||||
"fr_nchg": "{0} από τα νέα ονόματα άλλαξαν λόγω <code>win</code> και/ή <code>όχι /</code>\n\nΕίναι ΟΚ να συνεχίσουμε με αυτά τα ονόματα;",
|
||||
|
||||
"fd_ok": "διαγραφή OK",
|
||||
"fd_err": "αποτυχία διαγραφής:\n",
|
||||
"fd_none": "δεν διαγράφηκε τίποτα; ίσως μπλοκαρισμένο από τις ρυθμίσεις του διακομιστή (xbd);",
|
||||
"fd_busy": "διαγραφή {0} αντικειμένων...\n\n{1}",
|
||||
"fd_warn1": "ΔΙΑΓΡΑΦΗ αυτών των {0} αντικειμένων;",
|
||||
"fd_warn2": "<b>Τελευταία ευκαιρία!</b> Δεν υπάρχει αναίρεση. Διαγραφή;",
|
||||
|
||||
"fc_ok": "αποκοπή {0} αντικειμένων",
|
||||
"fc_warn": 'αποκοπή {0} αντικειμένων\n\nαλλά: μόνο <b>αυτή</b> η καρτέλα browser μπορεί να τα επικολλήσει\n(λόγω πολύ μεγάλης επιλογής)',
|
||||
|
||||
"fcc_ok": "αντιγράφηκαν {0} αντικείμενα στο πρόχειρο",
|
||||
"fcc_warn": "αντιγράφηκαν {0} αντικείμενα στο πρόχειρο\n\nαλλά: μόνο <b>αυτή</b> η καρτέλα browser μπορεί να τα επικολλήσει\n(λόγω πολύ μεγάλης επιλογής)",
|
||||
|
||||
"fp_apply": "χρησιμοποίησε αυτά τα ονόματα",
|
||||
"fp_ecut": "πρώτα κάνε αποκοπή ή αντιγραφή κάποιων αρχείων / φακέλων για επικόλληση / μετακίνηση\n\nσημείωση: μπορείς να αποκόπτεις / επικολλάς ανάμεσα σε διαφορετικές καρτέλες browser",
|
||||
"fp_ename": "τα {0} αντικείμενα δεν μπορούν να μετακινηθούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό για να τα αγνοήσεις:",
|
||||
"fcp_ename": "τα {0} αντικείμενα δεν μπορούν να αντιγραφούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό για να τα αγνοήσεις:",
|
||||
"fp_emore": "υπάρχουν ακόμα συγκρούσεις ονομάτων που πρέπει να διορθωθούν",
|
||||
"fp_ok": "μετακίνηση OK",
|
||||
"fcp_ok": "αντιγραφή OK",
|
||||
"fp_busy": "μετακίνηση {0} αντικειμένων...\n\n{1}",
|
||||
"fcp_busy": "αντιγραφή {0} αντικειμένων...\n\n{1}",
|
||||
"fp_err": "αποτυχία μετακίνησης:\n",
|
||||
"fcp_err": "αποτυχία αντιγραφής:\n",
|
||||
"fp_confirm": "να μετακινηθούν αυτά τα {0} αντικείμενα εδώ;",
|
||||
"fcp_confirm": "να αντιγραφούν αυτά τα {0} αντικείμενα εδώ;",
|
||||
"fp_etab": "αποτυχία ανάγνωσης πρόχειρου από άλλη καρτέλα browser",
|
||||
"fp_name": "μεταφόρτωση αρχείου από τη συσκευή σου. Δώσε του όνομα:",
|
||||
"fp_both_m": '<h6>διάλεξε τι θα επικολλήσεις</h6><code>Enter</code> = Μετακίνηση {0} αρχείων από «{1}»\n<code>ESC</code> = Μεταφόρτωση {2} αρχείων από τη συσκευή σου',
|
||||
"fcp_both_m": '<h6>διάλεξε τι θα επικολλήσεις</h6><code>Enter</code> = Αντιγραφή {0} αρχείων από «{1}»\n<code>ESC</code> = Μεταφόρτωση {2} αρχείων από τη συσκευή σου',
|
||||
"fp_both_b": '<a href="#" id="modal-ok">Μετακίνηση</a><a href="#" id="modal-ng">Μεταφόρτωση</a>',
|
||||
"fcp_both_b": '<a href="#" id="modal-ok">Αντιγραφή</a><a href="#" id="modal-ng">Μεταφόρτωση</a>',
|
||||
|
||||
"mk_noname": "γράψε ένα όνομα στο πεδίο κειμένου αριστερά πριν το κάνεις :p",
|
||||
|
||||
"tv_load": "Φόρτωση αρχείου κειμένου:\n\n{0}\n\n{1}% ({2} από {3} MiB φορτωμένα)",
|
||||
"tv_xe1": "αδυναμία φόρτωσης αρχείου κειμένου:\n\nσφάλμα ",
|
||||
"tv_xe2": "404, αρχείο δεν βρέθηκε",
|
||||
"tv_lst": "λίστα αρχείων κειμένου σε",
|
||||
"tvt_close": "επιστροφή στην προβολή φακέλου$NΣυντόμευση: M (ή Esc)\">❌ κλείσιμο",
|
||||
"tvt_dl": "κατέβασε αυτό το αρχείο$NΣυντόμευση: Y\">💾 λήψη",
|
||||
"tvt_prev": "προβολή προηγούμενου εγγράφου$NΣυντόμευση: i\">⬆ προηγούμενο",
|
||||
"tvt_next": "προβολή επόμενου εγγράφου$NΣυντόμευση: K\">⬇ επόμενο",
|
||||
"tvt_sel": "επέλεξε αρχείο (για αποκοπή / αντιγραφή / διαγραφή / ...)$NΣυντόμευση: S\">επιλογή",
|
||||
"tvt_edit": "άνοιγμα αρχείου στον επεξεργαστή κειμένου$NΣυντόμευση: E\">✏️ επεξεργασία",
|
||||
"tvt_tail": "παρακολούθηση αρχείου για αλλαγές; εμφάνιση νέων γραμμών σε πραγματικό χρόνο\">📡 παρακολούθηση",
|
||||
"tvt_wrap": "αναδίπλωση λέξεων\">↵",
|
||||
"tvt_atail": "κλείδωμα κύλισης στο κάτω μέρος\">⚓",
|
||||
"tvt_ctail": "αποκωδικοποίηση χρωμάτων τερματικού (ansi escape codes)\">🌈",
|
||||
"tvt_ntail": "όριο κύλισης (πόσα bytes κειμένου να κρατούνται φορτωμένα)",
|
||||
|
||||
"m3u_add1": "το τραγούδι προστέθηκε στη λίστα m3u",
|
||||
"m3u_addn": "προστέθηκαν {0} τραγούδια στη λίστα m3u",
|
||||
"m3u_clip": "η λίστα m3u αντιγράφηκε στο πρόχειρο\n\nπρέπει να φτιάξεις ένα νέο αρχείο κειμένου με όνομα η_λίστα_μου.m3u και να επικολλήσεις τη λίστα μέσα· αυτό θα το καταστήσει αναπαράξιμο",
|
||||
|
||||
"gt_vau": "μην δείχνεις το βίντεο, παίξε μόνο τον ήχο\">🎧",
|
||||
"gt_msel": "ενεργοποίηση επιλογής αρχείων; ctrl-κλικ σε αρχείο για παράκαμψη$N$N<em>όταν είναι ενεργό: διπλό κλικ σε αρχείο / φάκελο το ανοίγει</em>$N$NΣυντόμευση: S\">πολλαπλή επιλογή",
|
||||
"gt_crop": "κεντραρισμένη περικοπή μικρογραφιών\">περικοπή",
|
||||
"gt_3x": "μικρογραφίες υψηλής ανάλυσης\">3x",
|
||||
"gt_zoom": "ζουμ",
|
||||
"gt_chop": "κόψε",
|
||||
"gt_sort": "ταξινόμηση κατά",
|
||||
"gt_name": "όνομα",
|
||||
"gt_sz": "μέγεθος",
|
||||
"gt_ts": "ημερομηνία",
|
||||
"gt_ext": "τύπος",
|
||||
"gt_c1": "μεγαλύτερη περικοπή ονομάτων αρχείων (δείξε λιγότερα)",
|
||||
"gt_c2": "μικρότερη περικοπή ονομάτων αρχείων (δείξε περισσότερα)",
|
||||
|
||||
"sm_w8": "αναζήτηση...",
|
||||
"sm_prev": "τα παρακάτω αποτελέσματα αναζήτησης προέρχονται από προηγούμενη αναζήτηση:\n ",
|
||||
"sl_close": "κλείσιμο αποτελεσμάτων αναζήτησης",
|
||||
"sl_hits": "εμφανίζονται {0} αποτελέσματα",
|
||||
"sl_moar": "φόρτωσε περισσότερα",
|
||||
|
||||
"s_sz": "μέγεθος",
|
||||
"s_dt": "ημερομηνία",
|
||||
"s_rd": "μονοπάτι",
|
||||
"s_fn": "όνομα",
|
||||
"s_ta": "ετικέτες",
|
||||
"s_ua": "ανέβηκε@",
|
||||
"s_ad": "προχωρ.",
|
||||
"s_s1": "ελάχιστο σε MiB",
|
||||
"s_s2": "μέγιστο σε MiB",
|
||||
"s_d1": "ελάχιστο iso8601",
|
||||
"s_d2": "μέγιστο iso8601",
|
||||
"s_u1": "μεταφορτώθηκε αργότερα",
|
||||
"s_u2": "και/ή πριν",
|
||||
"s_r1": "το μονοπάτι περιέχει (χωρισμένα με κενό)",
|
||||
"s_f1": "το όνομα περιέχει (άρνηση με -nope)",
|
||||
"s_t1": "οι ετικέτες περιέχουν (^=αρχή, τέλος=$)",
|
||||
"s_a1": "συγκεκριμένες ιδιότητες μεταδεδομένων",
|
||||
|
||||
"md_eshow": "δεν μπορεί να εμφανιστεί ",
|
||||
"md_off": "[📜<em>readme</em>] απενεργοποιημένο στο [⚙️] -- κρυμμένο έγγραφο",
|
||||
|
||||
"badreply": "Αποτυχία ανάλυσης απάντησης από το διακομιστή",
|
||||
|
||||
"xhr403": "403: Πρόσβαση αρνήθηκε\n\nδοκίμασε το F5, ίσως αποσυνδέθηκες",
|
||||
"xhr0": "άγνωστο (πιθανόν αποσύνδεση από το διακομιστή ή ο διακομιστής είναι εκτός σύνδεσης)",
|
||||
"cf_ok": "συγγνώμη γι' αυτό -- η προστασία DD" + wah + "oS ενεργοποιήθηκε\n\nοι διαδικασίες θα συνεχιστούν σε περίπου 30 δευτερόλεπτα\n\nαν δεν γίνει τίποτα, πάτα F5 για επαναφόρτωση",
|
||||
"tl_xe1": "αδύνατη η λίστα υποφακέλων:\n\nσφάλμα ",
|
||||
"tl_xe2": "404: Ο φάκελος δεν βρέθηκε",
|
||||
"fl_xe1": "αδύνατη η λίστα αρχείων σε φάκελο:\n\nσφάλμα ",
|
||||
"fl_xe2": "404: Ο φάκελος δεν βρέθηκε",
|
||||
"fd_xe1": "αδύνατη η δημιουργία υποφακέλου:\n\nσφάλμα ",
|
||||
"fd_xe2": "404: Ο γονικός φάκελος δεν βρέθηκε",
|
||||
"fsm_xe1": "αδύνατη η αποστολή μηνύματος:\n\nσφάλμα ",
|
||||
"fsm_xe2": "404: Ο γονικός φάκελος δεν βρέθηκε",
|
||||
"fu_xe1": "αποτυχία φόρτωσης λίστας unpost από το διακομιστή:\n\nσφάλμα ",
|
||||
"fu_xe2": "404: Το αρχείο δεν βρέθηκε??",
|
||||
|
||||
"fz_tar": "μη συμπιεσμένο αρχείο gnu-tar (linux / mac)",
|
||||
"fz_pax": "μη συμπιεσμένο pax-format tar (πιο αργό)",
|
||||
"fz_targz": "gnu-tar με συμπίεση gzip επίπεδο 3$N$Nσυνήθως πολύ αργό, οπότε$Nχρησιμοποίησε καλύτερα μη συμπιεσμένο tar",
|
||||
"fz_tarxz": "gnu-tar με συμπίεση xz επίπεδο 1$N$Nσυνήθως πολύ αργό, οπότε$Nχρησιμοποίησε καλύτερα μη συμπιεσμένο tar",
|
||||
"fz_zip8": "zip με ονόματα αρχείων utf8 (ίσως να κολλάει σε windows 7 και παλιότερα)",
|
||||
"fz_zipd": "zip με παραδοσιακά ονόματα cp437, για πολύ παλιό λογισμικό",
|
||||
"fz_zipc": "cp437 με crc32 υπολογισμένο νωρίτερα,$Nγια MS-DOS PKZIP v2.04g (οκτώβριος 1993)$N(παίρνει παραπάνω χρόνο πριν ξεκινήσει η μεταφόρτωση)",
|
||||
|
||||
"un_m1": "μπορείς να διαγράψεις τα πρόσφατα αρχεία που μεταφόρτωσες (ή να ακυρώσεις τα μισοτελειωμένα) παρακάτω",
|
||||
"un_upd": "ανανέωση",
|
||||
"un_m4": "ή μοιράσου τα αρχεία που βλέπεις παρακάτω:",
|
||||
"un_ulist": "εμφάνιση",
|
||||
"un_ucopy": "αντιγραφή",
|
||||
"un_flt": "προαιρετικό φίλτρο: η διεύθυνση πρέπει να περιέχει",
|
||||
"un_fclr": "καθαρισμός φίλτρου",
|
||||
"un_derr": "αποτυχία διαγραφής unpost:\n",
|
||||
"un_f5": "κάτι χάλασε, δοκίμασε την ανανέωση ή πάτα F5",
|
||||
"un_uf5": "συγγνώμη αλλά πρέπει να ανανεώσεις τη σελίδα (πχ με F5 ή CTRL-R) πριν ακυρώσεις αυτήν την αποστολή",
|
||||
"un_nou": "<b>προσοχή:</b> ο διακομιστής είναι πολύ φορτωμένος για να δείξει μισοτελειωμένες αποστολές· πάτα την ανανέωση, σε λίγο",
|
||||
"un_noc": "<b>προσοχή:</b> το unpost των ολοκληρωμένων αρχείων δεν επιτρέπεται από τη ρύθμιση του διακομιστή",
|
||||
"un_max": "εμφανίζονται τα πρώτα 2000 αρχεία (χρησιμοποίησε φίλτρο)",
|
||||
"un_avail": "μπορείς να διαγράψεις {0} πρόσφατα αρχεία<br />μπορείς να ακυρώσεις {1} μισοτελειωμένες αποστολές",
|
||||
"un_m2": "ταξινομημένα κατά χρόνο μεταφόρτωσης; τα πιο πρόσφατα πρώτα:",
|
||||
"un_no1": "άκυρο! καμία μεταφόρτωση δεν είναι αρκετά πρόσφατη",
|
||||
"un_no2": "άκυρο! καμία μεταφόρτωση με αυτό το φίλτρο δεν είναι αρκετά πρόσφατη",
|
||||
"un_next": "διάγραψε τα επόμενα {0} αρχεία παρακάτω",
|
||||
"un_abrt": "άκυρο",
|
||||
"un_del": "διαγραφή",
|
||||
"un_m3": "φορτώνω τις πρόσφατες μεταφορτώσεις σου...",
|
||||
"un_busy": "διαγράφω {0} αρχεία...",
|
||||
"un_clip": "αντιγράφηκαν {0} σύνδεσμοι στο πρόχειρο",
|
||||
|
||||
"u_https1": "πρέπει",
|
||||
"u_https2": "μετάβαση σε https",
|
||||
"u_https3": "για καλύτερη απόδοση",
|
||||
"u_ancient": 'ο browser σου είναι εντυπωσιακά απαρχαιωμένος — ίσως να <a href="#" onclick="goto(\'bup\')">χρησιμοποιήσεις το bup αντί γι\' αυτό</a>',
|
||||
"u_nowork": "χρειάζεται firefox 53+ ή chrome 57+ ή iOS 11+",
|
||||
"tail_2old": "χρειάζεται firefox 105+ ή chrome 71+ ή iOS 14.5+",
|
||||
"u_nodrop": "ο browser σου είναι πολύ παλιός για drag&drop μεταφορτώσεις",
|
||||
"u_notdir": "αυτός δεν είναι φάκελος!\n\nο browser σου είναι πολύ παλιός,\nδοκίμασε drag&drop αντ' αυτού",
|
||||
"u_uri": "για να κάνεις drag&drop εικόνων από άλλα παράθυρα browser,\nρίξ' τες πάνω στο μεγάλο κουμπί μεταφόρτωσης",
|
||||
"u_enpot": 'άλλαξε στο <a href="#">potato UI</a> (ίσως ανεβάζει πιο γρήγορα)',
|
||||
"u_depot": 'άλλαξε στο <a href="#">fancy UI</a> (ίσως ανεβάζει πιο αργά)',
|
||||
"u_gotpot": "αλλάζω στο potato UI για πιο γρήγορη μεταφόρτωση,\n\nμπορείς να το αλλάξεις πάλι αν θες!",
|
||||
"u_pott": "<p>αρχεία: <b>{0}</b> ολοκληρωμένα, <b>{1}</b> αποτυχημένα, <b>{2}</b> σε εξέλιξη, <b>{3}</b> σε ουρά</p>",
|
||||
"u_ever": "αυτός είναι ο βασικός uploader; το up2k θέλει τουλάχιστον<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
|
||||
"u_su2k": 'αυτός είναι ο βασικός uploader; το <a href="#" id="u2yea">up2k</a> είναι καλύτερο',
|
||||
"u_uput": "βελτιστοποίηση για ταχύτητα (παράλειψη ελέγχου ακεραιότητας)",
|
||||
"u_ewrite": "δεν έχεις δικαίωμα εγγραφής σε αυτόν τον φάκελο",
|
||||
"u_eread": "δεν έχεις δικαίωμα ανάγνωσης σε αυτόν τον φάκελο",
|
||||
"u_enoi": "η αναζήτηση αρχείων δεν είναι ενεργοποιημένη στο αρχείο ρυθμίσεων του διακομιστή",
|
||||
"u_enoow": "δεν μπορείς να κάνεις αντικατάσταση εδώ· χρειάζεται δικαίωμα Διαγραφής",
|
||||
"u_badf": "Αυτά τα {0} αρχεία (από {1} συνολικά) παραλείφθηκαν, πιθανώς λόγω δικαιωμάτων συστήματος αρχείων:\n\n",
|
||||
"u_blankf": "Αυτά τα {0} αρχεία (από {1} συνολικά) είναι άδεια / κενά· να τα μεταφορτώσω έτσι κι αλλιώς;\n\n",
|
||||
"u_applef": "Αυτά τα {0} αρχεία (από {1} συνολικά) πιθανώς δεν είναι επιθυμητά;\nΠάτα <code>OK/Enter</code> για ΝΑ ΑΓΝΟΗΘΟΥΝ τα παρακάτω αρχεία,\nΠάτα <code>Cancel/ESC</code> για ΝΑ ΜΗΝ ΑΠΟΚΛΕΙΣΤΟΥΝ και να ΜΕΤΑΦΟΡΤΩΘΟΎΝ κι αυτά:\n\n",
|
||||
"u_just1": "\nΊσως δουλέψει καλύτερα αν επιλέξεις μόνο ένα αρχείο",
|
||||
"u_ff_many": "αν χρησιμοποιείς <b>Linux / MacOS / Android,</b> τότε τόσα αρχεία <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>μπορεί</em> να κατάρρευση του Firefox!</a>\nαν γίνει αυτό, δοκίμασε ξανά (ή χρησιμοποίησε τον Chrome).",
|
||||
"u_up_life": "Αυτή η μεταφόρτωση θα διαγραφεί από το διακομιστή\n{0} μετά την ολοκλήρωσή της",
|
||||
"u_asku": "μεταφόρτωση αυτών των {0} αρχείων στο <code>{1}</code>",
|
||||
"u_unpt": "μπορείς να αναιρέσεις / διαγράψεις αυτήν τη μεταφόρτωση χρησιμοποιώντας το 🧯, πάνω αριστερά",
|
||||
"u_bigtab": "θα εμφανιστούν {0} αρχεία\n\nαυτό μπορεί να κάνει τον browser σου να κολλήσει, είσαι σίγουρος;",
|
||||
"u_scan": "Σάρωση αρχείων...",
|
||||
"u_dirstuck": "ο επεξεργαστής φακέλων κόλλησε προσπαθώντας να προσπελάσει τα εξής {0} αντικείμενα· θα τα παραλείψει:",
|
||||
"u_etadone": "Ολοκληρώθηκε ({0}, {1} αρχεία)",
|
||||
"u_etaprep": "(προετοιμασία για μεταφόρτωση)",
|
||||
"u_hashdone": "το hashing ολοκληρώθηκε",
|
||||
"u_hashing": "υπολογισμός hash",
|
||||
"u_hs": "handshaking...",
|
||||
"u_started": "τα αρχεία ανεβαίνουν τώρα· δες τα στο [🚀]",
|
||||
"u_dupdefer": "διπλότυπο; θα επεξεργαστεί μετά από όλα τα άλλα αρχεία",
|
||||
"u_actx": "πάτα αυτό το κείμενο για να μην χάσεις<br />απόδοση όταν αλλάζεις παράθυρα/καρτέλες",
|
||||
"u_fixed": "ΟΚ! Το διόρθωσα 👍",
|
||||
"u_cuerr": "αποτυχία μεταφόρτωσης τμήματοςς {0} από {1};\nπιθανώς ακίνδυνο, συνεχίζω\n\nαρχείο: {2}",
|
||||
"u_cuerr2": "ο διακομιστής απέρριψε τη μεταφόρτωση (τμήμα {0} από {1});\nθα ξαναδοκιμάσει αργότερα\n\nαρχείο: {2}\n\nσφάλμα ",
|
||||
"u_ehstmp": "θα ξαναδοκιμάσει; δες κάτω δεξιά",
|
||||
"u_ehsfin": "ο διακομιστής απέρριψε το αίτημα ολοκλήρωσης της μεταφόρτωσης; ξαναδοκιμάζει...",
|
||||
"u_ehssrch": "ο διακομιστής απέρριψε το αίτημα αναζήτησης; ξαναδοκιμάζει...",
|
||||
"u_ehsinit": "ο διακομιστής απέρριψε το αίτημα για εκκίνηση μεταφόρτωσης; ξαναδοκιμάζει...",
|
||||
"u_eneths": "σφάλμα δικτύου κατά το handshake μεταφόρτωσης; ξαναδοκιμάζει...",
|
||||
"u_enethd": "σφάλμα δικτύου κατά τον έλεγχο ύπαρξης στόχου; ξαναδοκιμάζει...",
|
||||
"u_cbusy": "ο διακομιστής περιμένει να μας εμπιστευτεί ξανά μετά από πρόβλημα δικτύου...",
|
||||
"u_ehsdf": "ο διακομιστής έμεινε από χώρο στο δίσκο!\n\nθα συνεχίσει να ξαναδοκιμάζει,\nσε περίπτωση που κάποιος\nελευθερώσει αρκετό χώρο για συνέχεια",
|
||||
"u_emtleak1": "φαίνεται πως ο browser σου έχει διαρροή μνήμης;\nπαρακαλώ",
|
||||
"u_emtleak2": ' <a href="{0}">αλλαγή σε https (συνιστάται)</a> ή ',
|
||||
"u_emtleak3": ' ',
|
||||
"u_emtleakc": 'δοκίμασε τα εξής:\n<ul><li>πάτα <code>F5</code> για ανανέωση σελίδας</li><li>μετά απενεργοποίησε το <code>mt</code> κουμπί στις <code>⚙️ ρυθμίσεις</code></li><li>και δοκίμασε ξανά τη μεταφόρτωση</li></ul>Οι μεταφορτώσιες θα είναι λίγο πιο αργές, αλλά ok.\nΣυγγνώμη για την ταλαιπωρία!\n\nPS: το chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">έχει διόρθωση γι\' αυτό</a>',
|
||||
"u_emtleakf": 'δοκίμασε τα εξής:\n<ul><li>πάτα <code>F5</code> για ανανέωση σελίδας</li><li>μετά άνοιξε το <code>🥔</code> (potato) στο UI μεταφόρτωσης<li>και δοκίμασε ξανά τη μεταφόρτωση</li></ul>\nPS: ο firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">ελπίζει να φτιάξει αυτό το bug</a> κάποια στιγμή',
|
||||
"u_s404": "δεν βρέθηκε στο διακομιστή",
|
||||
"u_expl": "επεξήγηση",
|
||||
"u_maxconn": "οι περισσότεροι browser το περιορίζουν στα 6, αλλά ο firefox σου επιτρέπει να το αυξήσεις με <code>connections-per-server</code> στο <code>about:config</code>",
|
||||
"u_tu": '<p class="warn">ΠΡΟΕΙΔΟΠΟΙΗΣΗ: το turbo είναι ενεργοποιημένο, <span> το πρόγραμμα πελάτη ίσως να μην ανιχνεύσει και να μην ξαναεκκινήσει μισοτελειωμένες μεταφορτώσεις; δες τα tooltip του κουμπιού turbo</span></p>',
|
||||
"u_ts": '<p class="warn">ΠΡΟΕΙΔΟΠΟΙΗΣΗ: το turbo είναι ενεργοποιημένο, <span> τα αποτελέσματα αναζήτησης μπορεί να είναι λάθος; δες τα tooltip του κουμπιού turbo</span></p>',
|
||||
"u_turbo_c": "το turbo είναι απενεργοποιημένο στο αρχείο ρυθμίσεων του διακομιστή",
|
||||
"u_turbo_g": "απενεργοποιώ το turbo επειδή δεν έχεις δικαίωμα\nγια τη λίστα φακέλων σε αυτόν τον τόμο",
|
||||
"u_life_cfg": 'αυτόματη διαγραφή μετά από <input id="lifem" p="60" /> λεπτά (ή <input id="lifeh" p="3600" /> ώρες)',
|
||||
"u_life_est": 'η μεταφόρτωση θα διαγραφεί <span id="lifew" tt="τοπική ώρα">---</span>',
|
||||
"u_life_max": 'αυτός ο φάκελος επιβάλλει\nμέγιστη διάρκεια ζωής {0}',
|
||||
"u_unp_ok": "επιτρέπεται το unpost για {0}",
|
||||
"u_unp_ng": "δεν επιτρέπεται το unpost",
|
||||
"ue_ro": "έχεις μόνο δικαίωμα ανάγνωσης σε αυτόν το φάκελο\n\n",
|
||||
"ue_nl": "δεν είσαι συνδεδεμένος τώρα",
|
||||
"ue_la": 'είσαι συνδεδεμένος ως "{0}"',
|
||||
"ue_sr": "είσαι σε λειτουργία αναζήτησης αρχείων\n\nπήγαινε σε λειτουργία μεταφόρτωσης πατώντας το 🔎 (δίπλα στο μεγάλο κουμπί ΑΝΑΖΗΤΗΣΗΣ) και δοκίμασε πάλι\n\nσυγγνώμη",
|
||||
"ue_ta": "δοκίμασε να μεταφορτώσεις εκ νέου, θα πρέπει να δουλέψει τώρα",
|
||||
"ue_ab": "αυτό το αρχείο ανεβαίνει σε άλλο φάκελο και η μεταφόρτωση πρέπει να ολοκληρωθεί πριν ανέβει αλλού.\n\nΜπορείς να ακυρώσεις και να ξεχάσεις την αρχική μεταφόρτωση με το κουμπί 🧯 πάνω αριστερά",
|
||||
"ur_1uo": "ΟΚ: Το αρχείο ανέβηκε επιτυχώς",
|
||||
"ur_auo": "ΟΚ: Και τα {0} αρχεία ανέβηκαν επιτυχώς",
|
||||
"ur_1so": "ΟΚ: Το αρχείο βρέθηκε στο διακομιστή",
|
||||
"ur_aso": "ΟΚ: Και τα {0} αρχεία βρέθηκαν στο διακομιστή",
|
||||
"ur_1un": "Η μεταφόρτωση απέτυχε, συγγνώμη",
|
||||
"ur_aun": "Και οι {0} μεταφορτώσεις απέτυχαν, συγγνώμη",
|
||||
"ur_1sn": "Το αρχείο ΔΕΝ βρέθηκε στο διακομιστή",
|
||||
"ur_asn": "Τα {0} αρχεία ΔΕΝ βρέθηκαν στο διακομιστή",
|
||||
"ur_um": "Ολοκληρώθηκε;\n{0} μεταφορτώσεις είναι OK,\n{1} μεταφορτώσεις απέτυχαν, συγγνώμη",
|
||||
"ur_sm": "Ολοκληρώθηκε;\n{0} αρχεία βρέθηκαν στο διακομιστή,\n{1} αρχεία ΔΕΝ βρέθηκαν στο διακομιστή",
|
||||
|
||||
"lang_set": "ανανέωση σελίδας για εφαρμογή της αλλαγής;"
|
||||
},
|
||||
"ita": {
|
||||
"tt": "Italiano",
|
||||
|
||||
|
@ -6931,7 +7560,7 @@ var Ls = {
|
|||
},
|
||||
};
|
||||
|
||||
var LANGS = ["eng", "nor", "chi", "cze", "deu", "fin", "ita", "nld", "rus", "spa", "ukr"];
|
||||
var LANGS = ["eng", "nor", "chi", "cze", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"];
|
||||
|
||||
if (window.langmod)
|
||||
langmod();
|
||||
|
@ -7155,13 +7784,12 @@ ebi('op_cfg').innerHTML = (
|
|||
'</div>\n' +
|
||||
'<div>\n' +
|
||||
' <h3>' + L.cl_themes + '</h3>\n' +
|
||||
' <div id="themes">\n' +
|
||||
' <div><select id="themes"></select></div>\n' +
|
||||
' </div>\n' +
|
||||
'</div>\n' +
|
||||
'<div>\n' +
|
||||
' <h3>' + L.cl_langs + '</h3>\n' +
|
||||
' <div id="langs">\n' +
|
||||
' </div>\n' +
|
||||
' <div><select id="langs"></select></div>\n' +
|
||||
'</div>\n' +
|
||||
(have_zip ? (
|
||||
'<div><h3>' + L.cl_ziptype + '</h3><div id="arc_fmt"></div></div>\n'
|
||||
|
@ -7208,7 +7836,7 @@ ebi('op_cfg').innerHTML = (
|
|||
' </td>\n' +
|
||||
' </div>\n' +
|
||||
'</div>\n' +
|
||||
'<div><h3>' + L.cl_keytype + '</h3><div id="key_notation"></div></div>\n' +
|
||||
'<div><h3>' + L.cl_keytype + '</h3><div><select id="key_notation"></select></div></div>\n' +
|
||||
'<div><h3>' + L.cl_hiddenc + ' ' + (MOBILE ? '<a href="#" id="hcolsh">' + L.cl_hidec + '</a> / ' : '') + '<a href="#" id="hcolsr">' + L.cl_reset + '</a></h3><div id="hcols"></div></div>'
|
||||
);
|
||||
|
||||
|
@ -7375,6 +8003,10 @@ var ACtx = !IPHONE && (window.AudioContext || window.webkitAudioContext),
|
|||
dk, mp;
|
||||
|
||||
|
||||
if (location.pathname.indexOf('//') === 0)
|
||||
hist_replace(location.pathname.replace(/^\/+/, '/'));
|
||||
|
||||
|
||||
if (window.og_fn) {
|
||||
hash0 = 1;
|
||||
hist_replace(vsplit(get_evpath())[0]);
|
||||
|
@ -12590,7 +13222,7 @@ function ev_load_m3u(e) {
|
|||
function () { load_m3u(url); },
|
||||
function () {
|
||||
if (has(perms, 'write') && has(perms, 'delete'))
|
||||
window.location = url + '?edit';
|
||||
location = url + '?edit';
|
||||
else
|
||||
showfile.show(url);
|
||||
}
|
||||
|
@ -13189,7 +13821,7 @@ var treectl = (function () {
|
|||
|
||||
r.reqls = function (url, hpush, back, hydrate) {
|
||||
if (IE && !history.pushState)
|
||||
return window.location = url;
|
||||
return location = url;
|
||||
|
||||
var xhr = new XHR(),
|
||||
m = /[?&](k=[^&#]+)/.exec(url),
|
||||
|
@ -13205,6 +13837,7 @@ var treectl = (function () {
|
|||
xhr.hydrate = hydrate;
|
||||
xhr.ts = Date.now();
|
||||
xhr.open('GET', xhr.top + '?ls' + uq, true);
|
||||
xhr.setRequestHeader('Fnugg', '' + xhr.ts);
|
||||
xhr.onload = xhr.onerror = recvls;
|
||||
xhr.send();
|
||||
|
||||
|
@ -13270,6 +13903,9 @@ var treectl = (function () {
|
|||
if (r.chk_index_html(this.top, res))
|
||||
return;
|
||||
|
||||
if (this.ts != res.fnugg && res.fnugg != 'nei' && sread('no_fnugg') !== '1')
|
||||
toast.warn(60, "WARNING: A proxy/CDN between your webbrowser and the server is misbehaving, and caching responses it shouldn't. As a result, you are now seeing stale directory listings. There will be many issues.\n\nIf you need to ignore this and stop these messages, you can set the global-option 'no-fnugg' on the server, or click <code>π</code> and run this: <code>STG.no_fnugg=1</code>");
|
||||
|
||||
for (var a = 0; a < res.files.length; a++)
|
||||
if (res.files[a].tags === undefined)
|
||||
res.files[a].tags = {};
|
||||
|
@ -14109,25 +14745,21 @@ var mukey = (function () {
|
|||
defnot = 'rekobo_alnum';
|
||||
|
||||
var map = {},
|
||||
html = [];
|
||||
html = [],
|
||||
cb = ebi('key_notation');
|
||||
|
||||
for (var k in maps) {
|
||||
if (!maps.hasOwnProperty(k))
|
||||
continue;
|
||||
|
||||
html.push(
|
||||
'<span><input type="radio" name="keytype" value="' + k + '" id="key_' + k + '">' +
|
||||
'<label for="key_' + k + '">' + k + '</label></span>');
|
||||
|
||||
html.push('<option value="{0}">{0}</option>'.format(k));
|
||||
for (var a = 0; a < 24; a++)
|
||||
maps[k][a] = maps[k][a].trim();
|
||||
}
|
||||
ebi('key_notation').innerHTML = html.join('\n');
|
||||
cb.innerHTML = html.join('');
|
||||
|
||||
function set_key_notation(e) {
|
||||
ev(e);
|
||||
var notation = this.getAttribute('value');
|
||||
load_notation(notation);
|
||||
function set_key_notation() {
|
||||
load_notation(cb.value);
|
||||
try_render();
|
||||
}
|
||||
|
||||
|
@ -14184,14 +14816,10 @@ var mukey = (function () {
|
|||
if (!maps[notation])
|
||||
notation = defnot;
|
||||
|
||||
ebi('key_' + notation).checked = true;
|
||||
cb.value = notation;
|
||||
cb.onchange = set_key_notation;
|
||||
load_notation(notation);
|
||||
|
||||
var o = QSA('#key_notation input');
|
||||
for (var a = 0; a < o.length; a++) {
|
||||
o[a].onchange = set_key_notation;
|
||||
}
|
||||
|
||||
return {
|
||||
"render": try_render
|
||||
};
|
||||
|
@ -14230,17 +14858,17 @@ var settheme = (function () {
|
|||
showfile.setstyle();
|
||||
bchrome();
|
||||
|
||||
var html = [], itheme = ax.indexOf(theme[0]) * 2 + (light ? 1 : 0),
|
||||
var html = [],
|
||||
cb = ebi('themes'),
|
||||
itheme = ax.indexOf(theme[0]) * 2 + (light ? 1 : 0),
|
||||
names = ['classic dark', 'classic light', 'pm-monokai', 'flat light', 'vice', 'hotdog stand', 'hacker', 'hi-con'];
|
||||
|
||||
for (var a = 0; a < themes; a++)
|
||||
html.push('<a href="#" class="btn tgl' + (a == itheme ? ' on' : '') +
|
||||
'" tt="' + (names[a] || 'custom') + '">' + a + '</a>');
|
||||
html.push('<option value="{0}">{0} ┃ {1}</option>'.format(a, names[a] || 'custom'));
|
||||
|
||||
ebi('themes').innerHTML = html.join('');
|
||||
var btns = QSA('#themes a');
|
||||
for (var a = 0; a < themes; a++)
|
||||
btns[a].onclick = r.go;
|
||||
cb.value = itheme;
|
||||
cb.onchange = r.onsel;
|
||||
|
||||
if (chldr) {
|
||||
var x = r.ldr[itheme] || [tre];
|
||||
|
@ -14249,12 +14877,13 @@ var settheme = (function () {
|
|||
}
|
||||
|
||||
bcfg_set('light', light);
|
||||
tt.att(ebi('themes'));
|
||||
}
|
||||
|
||||
r.go = function (e) {
|
||||
var i = e;
|
||||
try { ev(e); i = e.target.textContent; } catch (ex) { }
|
||||
r.onsel = function () {
|
||||
r.go(parseInt(ebi('themes').value));
|
||||
};
|
||||
|
||||
r.go = function (i) {
|
||||
light = i % 2 == 1;
|
||||
var c = ax[Math.floor(i / 2)],
|
||||
l = light ? 'y' : 'z';
|
||||
|
@ -14262,7 +14891,7 @@ var settheme = (function () {
|
|||
themen = c + l;
|
||||
swrite('cpp_thm', theme);
|
||||
freshen();
|
||||
}
|
||||
};
|
||||
|
||||
freshen();
|
||||
return r;
|
||||
|
@ -14272,26 +14901,25 @@ var settheme = (function () {
|
|||
(function () {
|
||||
function freshen() {
|
||||
lang = sread("cpp_lang", LANGS) || lang;
|
||||
var k, html = [];
|
||||
var k, cb = ebi('langs'), html = [];
|
||||
for (var a = 0; a < LANGS.length; a++) {
|
||||
k = LANGS[a];
|
||||
html.push('<a href="#" class="btn tgl' + (k == lang ? ' on' : '') +
|
||||
'" tt="' + Ls[k].tt + '">' + k + '</a>');
|
||||
html.push('<option value="{0}">{0} ┃ {1}</option>'.format(k, Ls[k].tt));
|
||||
}
|
||||
ebi('langs').innerHTML = html.join('');
|
||||
var btns = QSA('#langs a');
|
||||
for (var a = 0, aa = btns.length; a < aa; a++)
|
||||
btns[a].onclick = setlang;
|
||||
cb.innerHTML = html.join('');
|
||||
cb.onchange = setlang;
|
||||
cb.value = lang;
|
||||
}
|
||||
|
||||
function setlang(e) {
|
||||
ev(e);
|
||||
var t = L.lang_set;
|
||||
L = Ls[this.textContent];
|
||||
swrite("cpp_lang", this.textContent);
|
||||
lang = ebi('langs').value;
|
||||
L = Ls[lang];
|
||||
swrite("cpp_lang", lang);
|
||||
freshen();
|
||||
modal.confirm(L.lang_set + "\n\n" + t, location.reload.bind(location), null);
|
||||
};
|
||||
}
|
||||
|
||||
freshen();
|
||||
})();
|
||||
|
|
|
@ -255,7 +255,7 @@ function Modpoll() {
|
|||
}
|
||||
|
||||
console.log('modpoll...');
|
||||
var url = (document.location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var url = (location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var xhr = new XHR();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'text';
|
||||
|
@ -346,7 +346,7 @@ function save(e) {
|
|||
fd.append("lastmod", (force ? -1 : last_modified));
|
||||
fd.append("body", txt);
|
||||
|
||||
var url = (document.location + '').split('?')[0];
|
||||
var url = (location + '').split('?')[0];
|
||||
var xhr = new XHR();
|
||||
xhr.open('POST', url, true);
|
||||
xhr.responseType = 'text';
|
||||
|
@ -404,7 +404,7 @@ function save_cb() {
|
|||
|
||||
function run_savechk(lastmod, txt, btn, ntry) {
|
||||
// download the saved doc from the server and compare
|
||||
var url = (document.location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var url = (location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var xhr = new XHR();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'text';
|
||||
|
|
|
@ -6,7 +6,7 @@ var dom_doc = ebi('m');
|
|||
var dom_md = ebi('mt');
|
||||
|
||||
(function () {
|
||||
var n = document.location + '';
|
||||
var n = location + '';
|
||||
n = (n.slice(n.indexOf('//') + 2).split('?')[0] + '?v').split('/');
|
||||
n[0] = 'top';
|
||||
var loc = [];
|
||||
|
@ -113,7 +113,7 @@ function save(mde) {
|
|||
fd.append("lastmod", (force ? -1 : last_modified));
|
||||
fd.append("body", txt);
|
||||
|
||||
var url = (document.location + '').split('?')[0];
|
||||
var url = (location + '').split('?')[0];
|
||||
var xhr = new XHR();
|
||||
xhr.open('POST', url, true);
|
||||
xhr.responseType = 'text';
|
||||
|
@ -166,7 +166,7 @@ function save_cb() {
|
|||
//alert('save OK -- wrote ' + r.size + ' bytes.\n\nsha512: ' + r.sha512);
|
||||
|
||||
// download the saved doc from the server and compare
|
||||
var url = (document.location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var url = (location + '').split('?')[0] + '?_=' + Date.now();
|
||||
var xhr = new XHR();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'text';
|
||||
|
|
|
@ -19,14 +19,7 @@
|
|||
<a href="{{ r }}/?h">control-panel</a>
|
||||
Filter: <input type="text" id="filter" size="20" placeholder="documents/passwords" />
|
||||
<span id="hits"></span>
|
||||
<table id="tab"><thead><tr>
|
||||
<th>size</th>
|
||||
<th>who</th>
|
||||
<th>when</th>
|
||||
<th>age</th>
|
||||
<th>dir</th>
|
||||
<th>file</th>
|
||||
</tr></thead><tbody id="tb"></tbody></table>
|
||||
<div id="tw"></div>
|
||||
</div>
|
||||
<a href="#" id="repl">π</a>
|
||||
<script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
function render() {
|
||||
var ups = V.ups, now = V.now, html = [];
|
||||
var html = ['<table id="tab"><thead><tr><th>size</th><th>who</th><th>when</th><th>age</th><th>dir</th><th>file</th></tr></thead><tbody>'];
|
||||
var ups = V.ups, now = V.now;
|
||||
ebi('filter').value = V.filter;
|
||||
ebi('hits').innerHTML = 'showing ' + ups.length + ' files';
|
||||
|
||||
|
@ -26,7 +27,8 @@ function render() {
|
|||
var t = V.filter ? ' matching the filter' : '';
|
||||
html = ['<tr><td colspan="6">there are no uploads' + t + '</td></tr>'];
|
||||
}
|
||||
ebi('tb').innerHTML = html.join('');
|
||||
html.push('</tbody></table>');
|
||||
ebi('tw').innerHTML = html.join('\n');
|
||||
}
|
||||
render();
|
||||
|
||||
|
@ -46,7 +48,7 @@ function ask(e) {
|
|||
V = JSON.parse(this.responseText)
|
||||
}
|
||||
catch (ex) {
|
||||
ebi('tb').innerHTML = '<tr><td colspan="6">failed to decode server response as json: <pre>' + esc(this.responseText) + '</pre></td></tr>';
|
||||
ebi('tw').innerHTML = 'failed to decode server response as json: <pre>' + esc(this.responseText) + '</pre>';
|
||||
return;
|
||||
}
|
||||
render();
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
var SRS = SR.trimEnd('/') + '/';
|
||||
|
||||
var t = QSA('a[k]');
|
||||
for (var a = 0; a < t.length; a++)
|
||||
t[a].onclick = rm;
|
||||
|
||||
function rm() {
|
||||
var u = SRS + '?eshare=rm&skey=' + uricom_enc(this.getAttribute('k')),
|
||||
var u = SR + '/?eshare=rm&skey=' + uricom_enc(this.getAttribute('k')),
|
||||
xhr = new XHR();
|
||||
|
||||
xhr.open('POST', u, true);
|
||||
|
@ -15,7 +13,7 @@ function rm() {
|
|||
|
||||
function bump() {
|
||||
var k = this.closest('tr').getElementsByTagName('a')[2].getAttribute('k'),
|
||||
u = SRS + '?skey=' + uricom_enc(k) + '&eshare=' + this.value,
|
||||
u = SR + '/?skey=' + uricom_enc(k) + '&eshare=' + this.value,
|
||||
xhr = new XHR();
|
||||
|
||||
xhr.open('POST', u, true);
|
||||
|
@ -27,7 +25,7 @@ function cb() {
|
|||
if (this.status !== 200)
|
||||
return modal.alert('<h6>server error</h6>' + esc(unpre(this.responseText)));
|
||||
|
||||
document.location = '?shares';
|
||||
location = '?shares';
|
||||
}
|
||||
|
||||
function qr(e) {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<body>
|
||||
<div id="wrap">
|
||||
{%- if not in_shr %}
|
||||
<a id="a" href="{{ r }}/?h" class="af">refresh</a>
|
||||
<a id="a" href="{{ r }}/?h{{ re }}" class="af">refresh</a>
|
||||
<a id="v" href="{{ r }}/?hc" class="af">connect</a>
|
||||
|
||||
{%- if this.uname == '*' %}
|
||||
|
@ -120,7 +120,12 @@
|
|||
<div>
|
||||
<form id="lf" method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
|
||||
<input type="hidden" id="la" name="act" value="login" />
|
||||
{% if this.args.usernames %}
|
||||
<input type="text" id="lu" name="uname" placeholder=" username" size="12" />
|
||||
<input type="password" id="lp" name="cppwd" placeholder=" password" size="12" />
|
||||
{% else %}
|
||||
<input type="password" id="lp" name="cppwd" placeholder=" password" />
|
||||
{% endif %}
|
||||
<input type="hidden" name="uhash" id="uhash" value="x" />
|
||||
<input type="submit" id="ls" value="login" />
|
||||
{% if chpw %}
|
||||
|
|
|
@ -215,9 +215,50 @@ var Ls = {
|
|||
"ac1": "ota no304 käyttöön",
|
||||
"ad1": "no304:n lopettaa välimuistin käytön kokonaan; kokeile tätä jos k304 ei riittänyt. Tuhlaa valtavan määrän verkkoliikennettä!",
|
||||
"ae1": "lähtevät:",
|
||||
"af1": "näytä viimeaikaiset lataukset",
|
||||
"af1": "näytä viimeaikaiset lataukset",
|
||||
"ag1": "näytä tunnetut IdP-käyttäjät",
|
||||
},
|
||||
"grc": {
|
||||
"a1": "ανανέωση",
|
||||
"b1": "γεια σου ξένε! <small>(δεν είσαι συνδεδεμένος)</small>",
|
||||
"c1": "αποσύνδεση",
|
||||
"d1": "σωρός απορριμμάτων",
|
||||
"d2": "εμφανίζει την κατάσταση όλων των ενεργών διεργασιών",
|
||||
"e1": "επαναφόρτωση του cfg",
|
||||
"e2": "φορτώνει ξανά τα αρχεία ρυθμίσεων (λογαριασμοί/τόμοι/volflags),$Nκαι κάνει επανεξέταση όλων των τόμων e2ds$N$Nσημείωση: οποιαδήποτε αλλαγή στις καθολικές ρυθμίσεις$Nαπαιτεί πλήρη επανεκκίνηση για να εφαρμοστεί",
|
||||
"f1": "μπορείς να περιηγηθείς:",
|
||||
"g1": "μπορείς να εκτελέσεις μεταφόρτωση σε:",
|
||||
"cc1": "άλλα πράγματα:",
|
||||
"h1": "απενεργοποίση k304",
|
||||
"i1": "ενεργοποίηση k304",
|
||||
"j1": "η ενεργοποίηση του k304 θα αποσυνδέσει το πρόγραμμα πελάτη σου σε κάθε HTTP 304, κάτι που μπορεί να αποτρέψει κάποια προβληματικά proxies από το να κολλάνε (να μην φορτώνουν ξαφνικά σελίδες), <em>αλλά</em> θα κάνει τα πράγματα, γενικά πιο αργά",
|
||||
"k1": "επαναφορά ρυθμίσεων στο πρόγραμμα πελάτη",
|
||||
"l1": "συνδέσου για περισσότερα:",
|
||||
"m1": "καλώς ήρθες,",
|
||||
"n1": "404 δεν βρέθηκε ┐( ´ -`)┌",
|
||||
"o1": '´η μήπως δεν έχεις πρόσβαση -- δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>',
|
||||
"p1": "403 απαγορευμένο ~┻━┻",
|
||||
"q1": 'δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>',
|
||||
"r1": "πίσω στην αρχική",
|
||||
".s1": "επανάληψη σάρωσης",
|
||||
"t1": "ενέργεια",
|
||||
"u2": "χρόνος από την τελευταία εγγραφή του διακομιστή$N( μεταφόρτωση / μετονομασία / ... )$N$N17d = 17 days$N1ω23 = 1 ώρα 23 λεπτά$N4λ56 = 4 λεπτά 56 δευτερόλεπτα",
|
||||
"v1": "σύνδεση",
|
||||
"v2": "χρησιμοποίησε αυτόν το διακομιστή σαν τοπικό δίσκο",
|
||||
"w1": "εναλλαγή σε https",
|
||||
"x1": "αλλαγή κωδικού",
|
||||
"y1": "επεξεργασία κοινόχρηστων φακέλων",
|
||||
"z1": "ξεκλείδωμα αυτού του κοινόχρηστου φακέλου:",
|
||||
"ta1": "συμπλήρωσε πρώτα το νέο σου κωδικό",
|
||||
"ta2": "επανέλαβε για να επιβεβαιώσεις το νέο κωδικό:",
|
||||
"ta3": "βρέθηκε τυπογραφικό λάθος· δοκίμασε ξανά",
|
||||
"aa1": "εισερχόμενα αρχεία:",
|
||||
"ab1": "απενεργοποίηση no304",
|
||||
"ac1": "ενεργοποίηση no304",
|
||||
"ad1": "η ενεργοποίηση του no304 θα απενεργοποιήσει όλη την προσωρινή αποθήκευση· δοκίμασέ το αν το k304 δεν ήταν αρκετό. Προσοχή, θα σπαταλήσει τεράστιο όγκο δικτυακής κίνησης!",
|
||||
"ae1": "ενεργές μεταφορτώσεις:",
|
||||
"af1": "προβολή πρόσφατων μεταφορτώσεων",
|
||||
},
|
||||
"ita": {
|
||||
"a1": "aggiorna",
|
||||
"b1": "ciao <small>(non sei connesso)</small>",
|
||||
|
@ -259,7 +300,7 @@ var Ls = {
|
|||
"ae1": "in uscita:",
|
||||
"af1": "mostra i file caricati di recente",
|
||||
"ag1": "mostra utenti IdP conosciuti"
|
||||
},
|
||||
},
|
||||
"nld": {
|
||||
"a1": "Update",
|
||||
"b1": "Hallo, hoe gaat het met jou? <small>(Je bent niet ingelogd)</small>",
|
||||
|
@ -416,7 +457,7 @@ try {
|
|||
catch (ex) { }
|
||||
|
||||
tt.init();
|
||||
var o = QS('input[name="cppwd"]');
|
||||
var o = QS('input[name="uname"]') || QS('input[name="cppwd"]');
|
||||
if (!ebi('c') && o.offsetTop + o.offsetHeight < window.innerHeight)
|
||||
o.focus();
|
||||
|
||||
|
@ -426,6 +467,9 @@ if (o && /[0-9]+$/.exec(o.innerHTML))
|
|||
|
||||
ebi('uhash').value = '' + location.hash;
|
||||
|
||||
if (/\&re=/.test('' + location))
|
||||
ebi('a').className = 'af g';
|
||||
|
||||
(function() {
|
||||
if (!ebi('x'))
|
||||
return;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
{% if accs %}<code><b id="pw0">{{ pw }}</b></code>=password, {% endif %}<code><b>mp</b></code>=mountpoint
|
||||
</span>
|
||||
{% if accs %}<a href="#" id="setpw">use real password</a>{% endif %}
|
||||
<a href="#" id="qr">show qr</a>
|
||||
</p>
|
||||
|
||||
|
||||
|
|
|
@ -49,12 +49,14 @@ function setos(os) {
|
|||
setos(WINDOWS ? 'win' : LINUX ? 'lin' : MACOS ? 'mac' : 'idk');
|
||||
|
||||
|
||||
var pw = '';
|
||||
function setpw(e) {
|
||||
ev(e);
|
||||
modal.prompt('password:', '', function (v) {
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
pw = v;
|
||||
var pw0 = ebi('pw0').innerHTML,
|
||||
oa = QSA('b');
|
||||
|
||||
|
@ -67,3 +69,12 @@ function setpw(e) {
|
|||
}
|
||||
if (ebi('setpw'))
|
||||
ebi('setpw').onclick = setpw;
|
||||
|
||||
|
||||
ebi('qr').onclick = function () {
|
||||
var url = ('' + location).split('?')[0];
|
||||
if (pw)
|
||||
url += '?pw=' + pw;
|
||||
var txt = esc(url) + '<img class="b64" width="100" height="100" src="' + addq(url, 'qr') + '" />';
|
||||
modal.alert(txt);
|
||||
};
|
||||
|
|
|
@ -964,6 +964,7 @@ function up2k_init(subtle) {
|
|||
"t": 0
|
||||
},
|
||||
"car": 0,
|
||||
"nre": 0,
|
||||
"slow_io": null,
|
||||
"oserr": false,
|
||||
"modn": 0,
|
||||
|
@ -1572,7 +1573,7 @@ function up2k_init(subtle) {
|
|||
|
||||
function linklist() {
|
||||
var ret = [],
|
||||
base = document.location.origin.replace(/\/$/, '');
|
||||
base = location.origin.replace(/\/$/, '');
|
||||
|
||||
for (var a = 0; a < st.files.length; a++) {
|
||||
var t = st.files[a],
|
||||
|
@ -1595,7 +1596,7 @@ function up2k_init(subtle) {
|
|||
ev(e);
|
||||
var txt = linklist();
|
||||
cliptxt(txt + '\n', function () {
|
||||
toast.inf(5, un_clip.format(txt.split('\n').length));
|
||||
toast.inf(5, L.un_clip.format(txt.split('\n').length));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1783,8 +1784,7 @@ function up2k_init(subtle) {
|
|||
}
|
||||
|
||||
var tasker = (function () {
|
||||
var running = false,
|
||||
was_busy = false;
|
||||
var running = false;
|
||||
|
||||
var defer = function () {
|
||||
running = false;
|
||||
|
@ -1801,7 +1801,17 @@ function up2k_init(subtle) {
|
|||
while (true) {
|
||||
var now = Date.now(),
|
||||
blocktime = now - r.tact,
|
||||
is_busy = st.car < st.files.length;
|
||||
was_busy = st.is_busy,
|
||||
is_busy = !!( // gzip take the wheel
|
||||
st.car < st.files.length ||
|
||||
st.busy.hash.length ||
|
||||
st.todo.hash.length ||
|
||||
st.busy.handshake.length ||
|
||||
st.todo.handshake.length ||
|
||||
st.busy.upload.length ||
|
||||
st.todo.upload.length ||
|
||||
st.busy.head.length ||
|
||||
st.todo.head.length);
|
||||
|
||||
if (blocktime > 2500)
|
||||
console.log('main thread blocked for ' + blocktime);
|
||||
|
@ -1809,7 +1819,16 @@ function up2k_init(subtle) {
|
|||
r.tact = now;
|
||||
|
||||
if (was_busy && !is_busy) {
|
||||
for (var a = 0; a < st.files.length; a++) {
|
||||
var nre = 0, nf = 0;
|
||||
for (var a = 0; a < st.files.length; a++)
|
||||
if (st.files[a].want_recheck)
|
||||
nre++;
|
||||
console.log('nre', nre, 'st', st.nre);
|
||||
if (st.nre != nre) {
|
||||
st.nre = nre;
|
||||
nf = st.files.length;
|
||||
}
|
||||
for (var a = 0; a < nf; a++) {
|
||||
var t = st.files[a];
|
||||
if (t.want_recheck) {
|
||||
t.rechecks++;
|
||||
|
@ -1817,7 +1836,7 @@ function up2k_init(subtle) {
|
|||
push_t(st.todo.handshake, t);
|
||||
}
|
||||
}
|
||||
is_busy = st.todo.handshake.length;
|
||||
is_busy = !!st.todo.handshake.length;
|
||||
try {
|
||||
if (!is_busy && !uc.fsearch && !msel.getsel().length && (!mp.au || mp.au.paused))
|
||||
treectl.goto();
|
||||
|
@ -1826,7 +1845,7 @@ function up2k_init(subtle) {
|
|||
}
|
||||
|
||||
if (was_busy != is_busy) {
|
||||
st.is_busy = was_busy = is_busy;
|
||||
st.is_busy = is_busy;
|
||||
|
||||
window[(is_busy ? "add" : "remove") +
|
||||
"EventListener"]("beforeunload", warn_uploader_busy);
|
||||
|
@ -1947,7 +1966,7 @@ function up2k_init(subtle) {
|
|||
|
||||
for (var a = 0; a < st.files.length; a++) {
|
||||
var t = st.files[a];
|
||||
if (t.want_recheck && !t.rechecks)
|
||||
if (t.want_recheck && t.rechecks < 999)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2693,8 +2712,9 @@ function up2k_init(subtle) {
|
|||
if (ofs !== -1) {
|
||||
err = err.slice(0, ofs + 1) + linksplit(err.slice(ofs + 2).trimEnd()).join(' / ');
|
||||
}
|
||||
if (!t.rechecks && (err_pend || err_srcb)) {
|
||||
if (!t.rechecks)
|
||||
t.rechecks = 0;
|
||||
if (t.rechecks < 999 && (err_pend || err_srcb)) {
|
||||
t.want_recheck = true;
|
||||
if (st.busy.upload.length || st.busy.handshake.length || st.bytes.uploaded) {
|
||||
err = L.u_dupdefer;
|
||||
|
|
|
@ -120,7 +120,7 @@ function esc(txt) {
|
|||
function basenames(txt) {
|
||||
return (txt + '').replace(/https?:\/\/[^ \/]+\//g, '/').replace(/js\?_=[a-zA-Z]{4}/g, 'js');
|
||||
}
|
||||
if ((document.location + '').indexOf(',rej,') + 1)
|
||||
if ((location + '').indexOf(',rej,') + 1)
|
||||
window.onunhandledrejection = function (e) {
|
||||
var err = e.reason;
|
||||
try {
|
||||
|
@ -741,7 +741,7 @@ function assert_vp(path) {
|
|||
if (path.indexOf('//') + 1)
|
||||
throw 'nonlocal1: ' + path;
|
||||
|
||||
var o = window.location.origin;
|
||||
var o = location.origin;
|
||||
if (have_URL && (new URL(path, o)).origin != o)
|
||||
throw 'nonlocal2: ' + path;
|
||||
}
|
||||
|
@ -893,7 +893,7 @@ function uricom_adec(arr, li) {
|
|||
|
||||
|
||||
function get_evpath() {
|
||||
var ret = document.location.pathname;
|
||||
var ret = location.pathname;
|
||||
|
||||
if (ret.indexOf('/') !== 0)
|
||||
ret = '/' + ret;
|
||||
|
@ -1249,10 +1249,10 @@ function hist_replace(url) {
|
|||
|
||||
function sethash(hv) {
|
||||
if (window.history && history.replaceState) {
|
||||
hist_replace(document.location.pathname + document.location.search + '#' + hv);
|
||||
hist_replace(location.pathname + location.search + '#' + hv);
|
||||
}
|
||||
else {
|
||||
document.location.hash = hv;
|
||||
location.hash = hv;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2138
docs/chungus.conf
Normal file
2138
docs/chungus.conf
Normal file
File diff suppressed because it is too large
Load diff
|
@ -74,7 +74,6 @@ gtar=$(command -v gtar || command -v gnutar) || true
|
|||
sed() { gsed "$@"; }
|
||||
find() { gfind "$@"; }
|
||||
sort() { gsort "$@"; }
|
||||
shuf() { gshuf "$@"; }
|
||||
nproc() { gnproc; }
|
||||
sha1sum() { shasum "$@"; }
|
||||
unexpand() { gunexpand "$@"; }
|
||||
|
@ -157,9 +156,9 @@ stamp=$(
|
|||
done | sort | tail -n 1 | sha1sum | cut -c-16
|
||||
)
|
||||
|
||||
rm -rf sfx$CSN/*
|
||||
mkdir -p sfx$CSN build
|
||||
cd sfx$CSN
|
||||
rm -rf sfx/*
|
||||
mkdir -p sfx build
|
||||
cd sfx
|
||||
|
||||
tmpdir="$(
|
||||
printf '%s\n' "$TMPDIR" /tmp |
|
||||
|
@ -395,7 +394,7 @@ ts=$(date -u +%s)
|
|||
hts=$(date -u +%Y-%m%d-%H%M%S) # --date=@$ts (thx osx)
|
||||
|
||||
mkdir -p ../dist
|
||||
sfx_out=../dist/copyparty-sfx$CSN
|
||||
sfx_out=../dist/copyparty-sfx
|
||||
|
||||
echo cleanup
|
||||
find -name '*.pyc' -delete
|
||||
|
@ -554,7 +553,7 @@ gzres() {
|
|||
}
|
||||
|
||||
|
||||
zdir="$tmpdir/cpp-mksfx$CSN"
|
||||
zdir="$tmpdir/cpp-mksfx"
|
||||
[ -e "$zdir/$stamp" ] || rm -rf "$zdir"
|
||||
mkdir -p "$zdir"
|
||||
echo a > "$zdir/$stamp"
|
||||
|
@ -583,15 +582,7 @@ echo gen tarlist
|
|||
for d in copyparty partftpy magic j2 py2 py37 ftp; do find $d -type f || true; done | # strip_hints
|
||||
sed -r 's/(.*)\.(.*)/\2 \1/' | LC_ALL=C sort |
|
||||
sed -r 's/([^ ]*) (.*)/\2.\1/' | grep -vE '/list1?$' > list1
|
||||
|
||||
for n in {1..50}; do
|
||||
(grep -vE '\.gz$' list1; grep -E '\.gz$' list1 | (shuf||gshuf) ) >list || true
|
||||
s=$( (sha1sum||shasum) < list | cut -c-16)
|
||||
grep -q $s "$zdir/h" 2>/dev/null && continue
|
||||
echo $s >> "$zdir/h"
|
||||
break
|
||||
done
|
||||
[ $n -eq 50 ] && exit
|
||||
(grep -vE '\.gz$' list1; grep -E '\.gz$' list1) >list
|
||||
|
||||
echo creating tar
|
||||
tar -cf tar "${targs[@]}" --numeric-owner -T list
|
||||
|
|
|
@ -32,11 +32,8 @@ v=$1
|
|||
rm -f ../dist/copyparty-sfx*
|
||||
shift
|
||||
./make-sfx.sh "$@"
|
||||
f=../dist/copyparty-sfx
|
||||
[ -e $f.py ] && s= || s=-gz
|
||||
# TODO: the -gz suffix is gone, can drop all the $s stuff probably
|
||||
|
||||
$f$s.py --version >/dev/null
|
||||
../dist/copyparty-sfx.py --version >/dev/null
|
||||
mv ../dist/copyparty-{sfx,int}.py
|
||||
|
||||
while [ "$1" ]; do
|
||||
case "$1" in
|
||||
|
@ -46,27 +43,8 @@ while [ "$1" ]; do
|
|||
shift
|
||||
done
|
||||
|
||||
[ $parallel -gt 1 ] && {
|
||||
printf '\033[%s' s 2r H "0;1;37;44mbruteforcing sfx size -- press enter to terminate" K u "7m $* " K $'27m\n'
|
||||
trap "rm -f .sfx-run; printf '\033[%s' s r u" INT TERM EXIT
|
||||
touch .sfx-run
|
||||
min=99999999
|
||||
for ((a=0; a<$parallel; a++)); do
|
||||
while [ -e .sfx-run ]; do
|
||||
CSN=$a ./make-sfx.sh re "$@"
|
||||
sz=$(wc -c <$f$a$s.py | awk '{print$1}')
|
||||
[ $sz -ge $min ] && continue
|
||||
mv $f$a$s.py $f$s.py.$sz
|
||||
min=$sz
|
||||
done &
|
||||
done
|
||||
read
|
||||
exit
|
||||
}
|
||||
|
||||
while true; do
|
||||
mv $f$s.py $f$s.$(wc -c <$f$s.py | awk '{print$1}').py
|
||||
./make-sfx.sh re "$@"
|
||||
done
|
||||
./make-sfx.sh re lang eng "$@"
|
||||
mv ../dist/copyparty-{sfx,en}.py
|
||||
mv ../dist/copyparty-{int,sfx}.py
|
||||
|
||||
# git tag -d v$v; git push --delete origin v$v
|
||||
|
|
|
@ -143,7 +143,7 @@ class Cfg(Namespace):
|
|||
def __init__(self, a=None, v=None, c=None, **ka0):
|
||||
ka = {}
|
||||
|
||||
ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs"
|
||||
ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_fnugg no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe usernames vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs"
|
||||
ka.update(**{k: False for k in ex.split()})
|
||||
|
||||
ex = "dav_inf dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash see_dots plain_ip"
|
||||
|
@ -161,10 +161,10 @@ class Cfg(Namespace):
|
|||
ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who"
|
||||
ka.update(**{k: 9 for k in ex.split()})
|
||||
|
||||
ex = "db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
||||
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
||||
ka.update(**{k: 0 for k in ex.split()})
|
||||
|
||||
ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR"
|
||||
ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"
|
||||
ka.update(**{k: "" for k in ex.split()})
|
||||
|
||||
ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner"
|
||||
|
|
Loading…
Reference in a new issue