Merge branch 'hovudstraum' into hovudstraum

Signed-off-by: oreo <77515999+dopreo@users.noreply.github.com>
This commit is contained in:
oreo 2026-01-07 09:34:12 +00:00 committed by GitHub
commit 6f17eab794
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
169 changed files with 22199 additions and 13824 deletions

View file

@ -7,10 +7,9 @@ assignees: '9001'
---
NOTE:
<!-- NOTE:
**please use english, or include an english translation.** aside from that,
all of the below are optional, consider them as inspiration, delete and rewrite at will, thx md
all of the below are optional, consider them as inspiration, delete and rewrite at will, thx md -->
### Describe the bug
a description of what the bug is
@ -45,5 +44,11 @@ if the issue is possibly on the client-side, then mention some of the following:
* OS version:
* browser version:
### The rest of the stack
if you are connecting directly to copyparty then that's cool, otherwise please mention everything else between copyparty and the browser (reverseproxy, tunnels, etc.)
### Server log
if the issue might be server-related, include everything that appears in the copyparty log during startup, and also anything else you think might be relevant
### Additional context
any other context about the problem here

View file

@ -7,9 +7,9 @@ assignees: '9001'
---
NOTE:
<!-- NOTE:
**please use english, or include an english translation.** aside from that,
all of the below are optional, consider them as inspiration, delete and rewrite at will
all of the below are optional, consider them as inspiration, delete and rewrite at will -->
**is your feature request related to a problem? Please describe.**
a description of what the problem is, for example, `I'm always frustrated when [...]` or `Why is it not possible to [...]`

1
.gitignore vendored
View file

@ -43,6 +43,7 @@ scripts/docker/*.err
# nix build output link
result
result-*
# IDEA config
.idea/

52
.vscode/launch.json vendored
View file

@ -3,7 +3,7 @@
"configurations": [
{
"name": "Run copyparty",
"type": "python",
"type": "debugpy",
"request": "launch",
"module": "copyparty",
"console": "integratedTerminal",
@ -11,30 +11,46 @@
"justMyCode": false,
"env": {
"PYDEVD_DISABLE_FILE_VALIDATION": "1",
"PYTHONWARNINGS": "always", //error
"PYTHONWARNINGS": "always" //error
},
"args": [
//"-nw",
"-ed",
"-emp",
//"-nw", // no-write; for testing uploads without writing to disk
//"-q", // quiet; speedboost when console output is not needed
// # increase debugger performance:
//"no-htp",
//"hash-mt=0",
//"mtag-mt=1",
//"th-mt=1",
// # listen for FTP and TFTP
"--ftp=3921",
"--ftp-pr=12000-12099",
"--tftp=3969",
// # listen on all IPv6, all IPv4, and unix-socket
"-i::,unix:777:a.sock",
// # misc
"--dedup",
"-e2dsa",
"-e2ts",
"-mtp=.bpm=f,bin/mtag/audio-bpm.py",
"--rss",
"--shr=/shr",
"--stats",
"-z",
// # users + volumes
"-aed:wark",
"-vsrv::r:rw,ed:c,dupe",
"-vdist:dist:r"
"-vdist:dist:r",
"-vsrv::r:rw,ed",
"-vsrv/junk:junk:r:A,ed",
"--ver"
]
},
{
"name": "No debug",
"preLaunchTask": "no_dbg",
"type": "python",
//"request": "attach", "port": 42069
// fork: nc -l 42069 </dev/null
},
{
"name": "Run active unit test",
"type": "python",
"type": "debugpy",
"request": "launch",
"module": "unittest",
"console": "integratedTerminal",
@ -51,6 +67,6 @@
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false
},
}
]
}
}

View file

@ -39,7 +39,7 @@ if you wanna have a go at coding it up yourself then maybe mention the idea on d
aside from documentation and ideas, some other things that would be cool to have some help with is:
* **translations** -- the copyparty web-UI has translations for english and norwegian at the top of [browser.js](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/web/browser.js); if you'd like to add a translation for another language then that'd be welcome! and if that language has a grammar that doesn't fit into the way the strings are assembled, then we'll fix that as we go :>
* **translations** -- the copyparty web-UI has translations in [copyparty/web/tl](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/web/tl); if you'd like to [add a translation](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#translations) for another language then that'd be welcome! and if that language has a grammar that doesn't fit into the way the strings are assembled, then we'll fix that as we go :>
* but please note that support for [RTL (Right-to-Left) languages](https://en.wikipedia.org/wiki/Right-to-left_script) is currently not planned, since the javascript is a bit too jank for that

340
README.md
View file

@ -5,7 +5,7 @@
turn almost any device into a file server with resumable uploads/downloads using [*any*](#browser-support) web browser
* server only needs Python (2 or 3), all dependencies optional
* 🔌 protocols: [http](#the-browser) // [webdav](#webdav-server) // [ftp](#ftp-server) // [tftp](#tftp-server) // [smb/cifs](#smb-server)
* 🔌 protocols: [http(s)](#the-browser) // [webdav](#webdav-server) // [sftp](#sftp-server) // [ftp(s)](#ftp-server) // [tftp](#tftp-server) // [smb/cifs](#smb-server)
* 📱 [android app](#android-app) // [iPhone shortcuts](#ios-shortcuts)
👉 **[get started](#quickstart)!** or visit the **[read-only demo server](https://a.ocv.me/pub/demo/)** 👀 running on a nuc in my basement
@ -14,50 +14,46 @@ turn almost any device into a file server with resumable uploads/downloads using
🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm) // 👉 **[feature-showcase](https://a.ocv.me/pub/demo/showcase-hq.webm)** ([youtube](https://www.youtube.com/watch?v=15_-hgsX2V0))
made in Norway 🇳🇴
built in Norway 🇳🇴 with contributions from [not-norway](https://github.com/9001/copyparty/graphs/contributors)
# readme table of contents
## readme toc
### 1. TOP ([START HERE](#quickstart))
* [**quickstart**](#quickstart) - just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** — that's it! 🎉
* [at home](#at-home) - make it accessible over the internet
* [on servers](#on-servers) - you may also want these, especially on servers
* [features](#features) - also see [comparison to similar software](./docs/versus.md)
* [testimonials](#testimonials) - small collection of user feedback
### 2. [MOTIVATIONS](#motivations) - project goals / philosophy
* [notes](#notes) - general notes
### 3. [BUGS](#bugs) - roughly sorted by chance of encounter
* [not my bugs](#not-my-bugs) - same order here too
### 4. [BREAKING CHANGES](#breaking-changes) - upgrade notes
### 5. [FAQ](#faq) - "frequently" asked questions
### 6. [ACCOUNTS & VOLUMES](#accounts-and-volumes) - per-folder, per-user permissions
* [shadowing](#shadowing) - hiding specific subfolders
* [dotfiles](#dotfiles) - unix-style hidden files/folders
### 7. [THE BROWSER](#the-browser) - accessing a copyparty server using a web browser
* [tabs](#tabs) - the main tabs in the ui
* [hotkeys](#hotkeys) - the browser has the following hotkeys
* [navpane](#navpane) - switching between breadcrumbs or navpane
* [thumbnails](#thumbnails) - press `g` or `田` to toggle grid-view instead of the file listing
* [zip downloads](#zip-downloads) - download folders (or file selections) as `zip` or `tar` files
* [uploading](#uploading) - drag files/folders into the web-browser to upload
* top
* [quickstart](#quickstart) - just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉
* [mirrors](#mirrors) - other places to download copyparty from
* [at home](#at-home) - make it accessible over the internet
* [on servers](#on-servers) - you may also want these, especially on servers
* [features](#features) - also see [comparison to similar software](./docs/versus.md)
* [testimonials](#testimonials) - small collection of user feedback
* [motivations](#motivations) - project goals / philosophy
* [notes](#notes) - general notes
* [bugs](#bugs) - roughly sorted by chance of encounter
* [not my bugs](#not-my-bugs) - same order here too
* [breaking changes](#breaking-changes) - upgrade notes
* [FAQ](#FAQ) - "frequently" asked questions
* [accounts and volumes](#accounts-and-volumes) - per-folder, per-user permissions
* [shadowing](#shadowing) - hiding specific subfolders
* [dotfiles](#dotfiles) - unix-style hidden files/folders
* [the browser](#the-browser) - accessing a copyparty server using a web-browser
* [tabs](#tabs) - the main tabs in the ui
* [hotkeys](#hotkeys) - the browser has the following hotkeys
* [navpane](#navpane) - switching between breadcrumbs or navpane
* [thumbnails](#thumbnails) - press `g` or `田` to toggle grid-view instead of the file listing
* [zip downloads](#zip-downloads) - download folders (or file selections) as `zip` or `tar` files
* [uploading](#uploading) - drag files/folders into the web-browser to upload
* [file-search](#file-search) - dropping files into the browser also lets you see if they exist on the server
* [unpost](#unpost) - undo/delete accidental uploads
* [self-destruct](#self-destruct) - uploads can be given a lifetime
* [race the beam](#race-the-beam) - download files while they're still uploading ([demo video](http://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm))
* [incoming files](#incoming-files) - the control-panel shows the ETA for all incoming files
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
* [shares](#shares) - share a file or folder by creating a temporary link
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
* [rss feeds](#rss-feeds) - monitor a folder with your RSS reader
* [recent uploads](#recent-uploads) - list all recent uploads
* [media player](#media-player) - plays almost every audio format there is
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
* [shares](#shares) - share a file or folder by creating a temporary link
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
* [rss feeds](#rss-feeds) - monitor a folder with your RSS reader
* [opds feeds](#opds-feeds) - browse and download files from your e-book reader
* [recent uploads](#recent-uploads) - list all recent uploads
* [media player](#media-player) - plays almost every audio format there is
* [playlists](#playlists) - create and play [m3u8](https://en.wikipedia.org/wiki/M3U) playlists
* [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
@ -72,9 +68,10 @@ made in Norway 🇳🇴
* [zeroconf](#zeroconf) - announce enabled services on the LAN ([pic](https://user-images.githubusercontent.com/241032/215344737-0eae8d98-9496-4256-9aa8-cd2f6971810d.png))
* [mdns](#mdns) - LAN domain-name and feature announcer
* [ssdp](#ssdp) - windows-explorer announcer
* [qr-code](#qr-code) - print a qr code [(screenshot)](https://user-images.githubusercontent.com/241032/194728533-6f00849b-c6ac-43c6-9359-83e454d11e00.png) for quick access
* [ftp server](#ftp-server) - an FTP server can be started using `--ftp 3921`
* [webdav server](#webdav-server) - with read-write support
* [qr-code](#qr-code) - print a qr-code [(screenshot)](https://user-images.githubusercontent.com/241032/194728533-6f00849b-c6ac-43c6-9359-83e454d11e00.png) for quick access
* [ftp server](#ftp-server) - an FTP server can be started using `--ftp 3921`
* [sftp server](#sftp-server) - goes roughly 700 MiB/s (slower than webdav and ftp)
* [webdav server](#webdav-server) - with read-write support
* [connecting to webdav from windows](#connecting-to-webdav-from-windows) - using the GUI
* [tftp server](#tftp-server) - a TFTP server (read/write) can be started using `--tftp 3969`
* [smb server](#smb-server) - unsafe, slow, not recommended for wan
@ -116,30 +113,25 @@ made in Norway 🇳🇴
* [GDPR compliance](#gdpr-compliance) - imagine using copyparty professionally...
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
### 9. [PACKAGES](#packages) - the party might be closer than you think
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
* [fedora package](#fedora-package) - does not exist yet
* [homebrew formulae](#homebrew-formulae) - `brew install copyparty ffmpeg`
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
* [nixos module](#nixos-module)
### 10. [BROWSER SUPPORT](#browser-support) - TLDR: yes
### 11. [CLIENT EXAMPLES](#client-examples) - interact with copyparty using non-browser clients
* [folder sync](#folder-sync) - sync folders to/from copyparty
* [mount as drive](#mount-as-drive) - a remote copyparty server as a local filesystem
### 12. [ANDROID APP](#android-app) - upload to copyparty with one tap
* [ios shortcuts](#ios-shortcuts) - there is no iPhone app, but
### 13. [PERFORMANCE](#performance) - defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
* [client-side](#client-side) - when uploading files
### 14. [SECURITY](#security) - there is a [discord server](https://discord.gg/25J8CdTT6G)
* [gotchas](#gotchas) - behavior that might be unexpected
* [cors](#cors) - cross-site request config
* [filekeys](#filekeys) - prevent filename bruteforcing
* [packages](#packages) - the party might be closer than you think
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
* [fedora package](#fedora-package) - does not exist yet
* [homebrew formulae](#homebrew-formulae) - `brew install copyparty ffmpeg`
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
* [nixos module](#nixos-module)
* [browser support](#browser-support) - TLDR: yes
* [server hall of fame](#server-hall-of-fame) - unexpected things that run copyparty
* [client examples](#client-examples) - interact with copyparty using non-browser clients
* [folder sync](#folder-sync) - sync folders to/from copyparty
* [mount as drive](#mount-as-drive) - a remote copyparty server as a local filesystem
* [android app](#android-app) - upload to copyparty with one tap
* [iOS shortcuts](#iOS-shortcuts) - there is no iPhone app, but
* [performance](#performance) - defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
* [client-side](#client-side) - when uploading files
* [security](#security) - there is a [discord server](https://discord.gg/25J8CdTT6G) with announcements
* [gotchas](#gotchas) - behavior that might be unexpected
* [cors](#cors) - cross-site request config
* [filekeys](#filekeys) - prevent filename bruteforcing
* [dirkeys](#dirkeys) - share specific folders in a volume
* [password hashing](#password-hashing) - you can hash passwords
* [https](#https) - both HTTP and HTTPS are accepted
@ -150,21 +142,17 @@ made in Norway 🇳🇴
### 16. [HTTP API](#HTTP-API) - see [devnotes](./docs/devnotes.md#http-api)
* [dependencies](#dependencies) - mandatory deps
* [optional dependencies](#optional-dependencies) - install these to enable bonus features
* [optional dependencies](#optional-dependencies) - enable bonus features
* [dependency chickenbits](#dependency-chickenbits) - prevent loading an optional dependency
* [optional gpl stuff](#optional-gpl-stuff)
### 17. [SFX](#sfx) - the self-contained "binary" (recommended!)
* [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
* [zipapp](#zipapp) - another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz)
### 18. [INSTALL ON ANDROID](#install-on-android)
### 19. [INSTALL ON ios](#install-on-ios)
### 20. [REPORTING BUGS](#reporting-bugs) - ideas for context to include, and where to submit them
### 21. [DEV NOTES](#devnotes) - for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
* [dependency unvendoring](#dependency-unvendoring) - force use of system modules
* [optional gpl stuff](#optional-gpl-stuff)
* [sfx](#sfx) - the self-contained "binary" (recommended!)
* [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
* [zipapp](#zipapp) - another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz)
* [install on android](#install-on-android)
* [install on iOS](#install-on-iOS)
* [reporting bugs](#reporting-bugs) - ideas for context to include, and where to submit them
* [devnotes](#devnotes) - for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
# quickstart
@ -175,7 +163,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
* or install through [pypi](https://pypi.org/project/copyparty/): `python3 -m pip install --user -U copyparty`
* or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
* or install [on arch](#arch-package) [on NixOS](#nixos-module) [through nix](#nix-package)
* or install [on arch](#arch-package) / [homebrew](#homebrew-formulae) [on NixOS](#nixos-module) [through nix](#nix-package)
* or if you are on android, [install copyparty in termux](#install-on-android)
* or maybe an iPhone or iPad? [install in a-Shell on ios](#install-on-ios)
* or maybe you have a [synology nas / dsm](./docs/synology-dsm.md)
@ -210,7 +198,19 @@ some recommended options:
* `-e2ts` enables audio metadata indexing (needs either FFprobe or Mutagen)
* `-v /mnt/music:/music:r:rw,foo -a foo:bar` shares `/mnt/music` as `/music`, `r`eadable by anyone, and read-write for user `foo`, password `bar`
* replace `:r:rw,foo` with `:r,foo` to only make the folder readable by `foo` and nobody else
* see [accounts and volumes](#accounts-and-volumes) (or `--help-accounts`) for the syntax and other permissions
* see [accounts and volumes](#accounts-and-volumes) (or [`--help-accounts`](https://copyparty.eu/cli/#accounts-help-page)) for the syntax and other permissions
### mirrors
other places to download copyparty from (non-github links):
* https://copyparty.eu/ (hetzner, finland, official mirror):
* https://copyparty.eu/py = https://copyparty.eu/copyparty-sfx.py = the sfx
* https://copyparty.eu/en = https://copyparty.eu/copyparty-en.py = the english-only sfx
* https://copyparty.eu/pyz = https://copyparty.eu/copyparty.pyz = the zipapp
* https://copyparty.eu/enz = https://copyparty.eu/copyparty-en.pyz = the enterprise pyz
* https://copyparty.eu/cli = online cli helptext
### at home
@ -232,6 +232,7 @@ you may also want these, especially on servers:
* [contrib/systemd/copyparty.service](contrib/systemd/copyparty.service) to run copyparty as a systemd service (see guide inside)
* [contrib/systemd/prisonparty.service](contrib/systemd/prisonparty.service) to run it in a chroot (for extra security)
* [contrib/podman-systemd/](contrib/podman-systemd/) to run copyparty in a Podman container as a systemd service (see guide inside)
* [contrib/openrc/copyparty](contrib/openrc/copyparty) to run copyparty on Alpine / Gentoo
* [contrib/rc/copyparty](contrib/rc/copyparty) to run copyparty on FreeBSD
* [nixos module](#nixos-module) to run copyparty on NixOS hosts
@ -239,12 +240,12 @@ you may also want these, especially on servers:
and remember to open the ports you want; here's a complete example including every feature copyparty has to offer:
```
firewall-cmd --permanent --add-port={80,443,3921,3923,3945,3990}/tcp # --zone=libvirt
firewall-cmd --permanent --add-port={80,443,3921,3922,3923,3945,3990}/tcp # --zone=libvirt
firewall-cmd --permanent --add-port=12000-12099/tcp # --zone=libvirt
firewall-cmd --permanent --add-port={69,1900,3969,5353}/udp # --zone=libvirt
firewall-cmd --reload
```
(69:tftp, 1900:ssdp, 3921:ftp, 3923:http/https, 3945:smb, 3969:tftp, 3990:ftps, 5353:mdns, 12000:passive-ftp)
(69:tftp, 1900:ssdp, 3921:ftp, 3922:sftp, 3923:http/https, 3945:smb, 3969:tftp, 3990:ftps, 5353:mdns, 12000:passive-ftp)
## features
@ -264,7 +265,7 @@ also see [comparison to similar software](./docs/versus.md)
* ☑ [upnp / zeroconf / mdns / ssdp](#zeroconf)
* ☑ [event hooks](#event-hooks) / script runner
* ☑ [reverse-proxy support](https://github.com/9001/copyparty#reverse-proxy)
* ☑ cross-platform (Windows, Linux, Macos, Android, ios, FreeBSD, arm32/arm64, ppc64le, s390x, risc-v/riscv64)
* ☑ cross-platform (Windows, Linux, Macos, Android, iOS, FreeBSD, arm32/arm64, ppc64le, s390x, risc-v/riscv64, SGI IRIX)
* upload
* ☑ basic: plain multipart, ie6 support
* ☑ [up2k](#uploading): js, resumable, multithreaded
@ -326,7 +327,7 @@ small collection of user feedback
project goals / philosophy
* inverse linux philosophy — do all the things, and do an *okay* job
* inverse unix philosophy -- do all the things, and do an *okay* job
* quick drop-in service to get a lot of features in a pinch
* some of [the alternatives](./docs/versus.md) might be a better fit for you
* run anywhere, support everything
@ -454,6 +455,12 @@ upgrade notes
* CopyParty?
* **nope**! the name is either copyparty (all-lowercase) or Copyparty -- it's [one word](https://en.wiktionary.org/wiki/copyparty) after all :>
* what is a volflag?
* per-volume configuration; many (not all) global-options can be set as volflags, and most (not all) volflags can be set as global-options; [complete list of volflags](https://copyparty.eu/cli/#flags-help-page)
* what is a volume?
* a mapping from a URL (`/music/`) to a folder on your server's local filesystem (`C:\Users\ed\Music`) which can then be accessed through copyparty, depending on the permissions and options you set on it -- see [accounts and volumes](#accounts-and-volumes)
* can I change the 🌲 spinning pine-tree loading animation?
* [yeah...](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#boring-loader-spinner) :-(
@ -464,6 +471,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 `--usernames` then do `?pw=username:password` instead
* `?pw` can be disabled with `--pw-urlp=A` but this breaks support for many clients
* 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)
@ -501,7 +509,7 @@ per-folder, per-user permissions - if your setup is getting complex, consider m
* much easier to manage, and you can modify the config at runtime with `systemctl reload copyparty` or more conveniently using the `[reload cfg]` button in the control-panel (if the user has `a`/admin in any volume)
* changes to the `[global]` config section requires a restart to take effect
a quick summary can be seen using `--help-accounts`
a quick summary can be seen using [`--help-accounts`](https://copyparty.eu/cli/#accounts-help-page)
configuring accounts/volumes with arguments:
* `-a usr:pwd` adds account `usr` with password `pwd`
@ -540,6 +548,9 @@ examples:
if you want to grant access to all users who are logged in, the group `acct` will always contain all known users, so for example `-v /mnt/music:music:r,@acct`
* to do the opposite, granting access to everyone who is NOT logged in. `*,-@acct` does the trick, for example `-v /srv/welcome:welcome:r,*,-@acct`
* single users can also be subtracted from a group: `@admins,-james`
anyone trying to bruteforce a password gets banned according to `--ban-pw`; default is 24h ban for 9 failed attempts in 1 hour
and if you want to use config files instead of commandline args (good!) then here's the same examples as a configfile; save it as `foobar.conf` and use it like this: `python copyparty-sfx.py -c foobar.conf`
@ -635,7 +646,7 @@ the main tabs in the ui
* `[🧯]` [unpost](#unpost): undo/delete accidental uploads
* `[🚀]` and `[🎈]` are the [uploaders](#uploading)
* `[📂]` mkdir: create directories
* `[📝]` new-md: create a new markdown document
* `[📝]` new-file: create a new textfile
* `[📟]` send-msg: either to server-log or into textfiles if `--urlform save`
* `[🎺]` audio-player config options
* `[⚙️]` general client config options
@ -748,6 +759,10 @@ to show `/icons/exe.png` and `/icons/elf.gif` as the thumbnail for all `.exe` an
* the supported image formats are [jpg, png, gif, webp, ico](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types)
* be careful with svg; chrome will crash if you have too many unique svg files showing on the same page (the limit is 250 or so) -- showing the same handful of svg files thousands of times is ok however
note:
* heif/heifs/heic/heics images usually require the `libvips` [optional dependency](#optional-dependencies) (available in the `iv` docker image, `withFastThumbnails` in nixos)
* technical trivia: FFmpeg has basic support for tiled heic as of v7.0; need `-show_stream_groups` for correct resolution
config file example:
```yaml
@ -802,6 +817,7 @@ you can also zip a selection of files or folders by clicking them in the browser
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
* and url-param `&nodot` skips dotfiles/dotfolders; they are included by default if your account has permission to see them
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
@ -888,6 +904,8 @@ the files will be hashed on the client-side, and each hash is sent to the server
files go into `[ok]` if they exist (and you get a link to where it is), otherwise they land in `[ng]`
* the main reason filesearch is combined with the uploader is cause the code was too spaghetti to separate it out somewhere else, this is no longer the case but now i've warmed up to the idea too much
if you have a "wark" (file-identifier/checksum) then you can also search for that in the [🔎] tab by putting `w = kFpDiztbZc8Z1Lzi` in the `raw` field
### unpost
@ -1014,6 +1032,8 @@ available functions:
* `$lpad(text, length, pad_char)`
* `$rpad(text, length, pad_char)`
two counters are available; `.n.s` is the nth file in the selection, and `.n.d` the nth file in the folder, for example rename-output `file(.n.d).(ext)` gives `file5.bin`, and `beach-$lpad((.n.s),3,0).(ext)` is `beach-017.jpg` and the initial value of each counter can be set in the textboxes underneath the preset dropdown
so,
say you have a file named [`meganeko - Eclipse - 07 Sirius A.mp3`](https://www.youtube.com/watch?v=-dtb0vDPruI) (absolutely fantastic album btw) and the tags are: `Album:Eclipse`, `Artist:meganeko`, `Title:Sirius A`, `tn:7`
@ -1049,6 +1069,8 @@ url parameters:
* `pw=hunter2` for password auth
* if you enabled `--usernames` then do `pw=username:password` instead
* `nopw` disables embedding the password (if provided) into item-URLs in the feed
* `nopw=a` disables mentioning the password anywhere at all in the feed; may break some readers
* `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)
@ -1060,6 +1082,28 @@ url parameters:
* uppercase = reverse-sort; `M` = oldest file first
## opds feeds
browse and download files from your e-book reader
enabled with the `opds` volflag or `--opds` global option
add `?opds` to the end of the url you would like to browse, then input that in your opds client.
for example: `https://copyparty.example/books/?opds`.
to log in with a password, enter it into either of the username or password fields in your client.
- if you've enabled `--usernames`, then you need to enter both username and password .
note: some clients (e.g. Moon+ Reader) will not send the password when downloading cover images, which will
cause your ip to be banned by copyparty. to work around this, you can grant the [`g` permission](#accounts-and-volumes)
to unauthenticated requests and enable [filekeys](#filekeys) to prevent guessing filenames. for example:
`-vbooks:books:r,ed:g:c,fk,opds`
by default, not all file types will be listed in opds feeds. to change this, add the extension to
`--opds-exts` (volflag: `opds_exts`), or empty the list to list everything
## recent uploads
list all recent uploads by clicking "show recent uploads" in the controlpanel
@ -1093,6 +1137,7 @@ some highlights:
* shows the audio waveform in the seekbar
* not perfectly gapless but can get really close (see settings + eq below); good enough to enjoy gapless albums as intended
* videos can be played as audio, without wasting bandwidth on the video
* adding `?v` to the end of an audio/video/image link will make it open in the mediaplayer
click the `play` link next to an audio file, or copy the link target to [share it](https://a.ocv.me/pub/demo/music/Ubiktune%20-%20SOUNDSHOCK%202%20-%20FM%20FUNK%20TERRROR!!/#af-1fbfba61&t=18) (optionally with a timestamp to start playing from, like that example does)
@ -1230,7 +1275,7 @@ see [./srv/expand/](./srv/expand/) for usage and examples
* and `PREADME.md` / `preadme.md` is shown above directory listings unless `--no-readme` or `.prologue.html`
* `README.md` and `*logue.html` can contain placeholder values which are replaced server-side before embedding into directory listings; see `--help-exp`
* `README.md` and `*logue.html` can contain placeholder values which are replaced server-side before embedding into directory listings; see [`--help-exp`](https://copyparty.eu/cli/#exp-help-page)
## searching
@ -1260,10 +1305,9 @@ using arguments or config files, or a mix of both:
* or click the `[reload cfg]` button in the control-panel if the user has `a`/admin in any volume
* changes to the `[global]` config section requires a restart to take effect
**NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
**NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with [`--help`](https://copyparty.eu/cli/) (or click that link) to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in [`--help-flags`](https://copyparty.eu/cli/#flags-help-page) can be used in volumes as volflags (per-volume configuration).
* if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
* or see this: https://ocv.me/copyparty/helptext.html
* or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
* or if you prefer plaintext, https://copyparty.eu/helptext.txt
## zeroconf
@ -1360,6 +1404,26 @@ config file example, which restricts FTP to only use ports 3921 and 12000-12099
```
## sftp server
goes roughly 700 MiB/s (slower than webdav and ftp)
> this is **not** [ftps](#ftp-server) (which copyparty also supports); [ftps](#ftp-server) is ftp-tls (think http/https), while **sftp** is ssh-based and (preferably) uses ssh-keys for authentication
the sftp-server requires the optional dependency [paramiko](https://pypi.org/project/paramiko/);
* if you are **not** using docker, then install paramiko somehow
* if you **are** using docker, then use one of the following image variants: `ac` / `im` / `iv` / `dj`
enable sftpd with `--sftp 3922` to listen on port 3922;
* use global-option `sftp-key` to associate an ssh-key with a user;
* commandline: `--sftp-key 'david ssh-ed25519 AAAAC3NzaC...'`
* config-file: `sftp-key: david ssh-ed25519 AAAAC3NzaC...`
* `--sftp-pw` enables login with passwords (default is ssh-keys only)
* `--sftp-anon foo` enables login with username `foo` and no password; gives the same access/permissions as the website does when not logged in
see the [sftp section in --help](https://copyparty.eu/cli/#g-sftp) for the other options
## webdav server
with read-write support, supports winXP and later, macos, nautilus/gvfs ... a great way to [access copyparty straight from the file explorer in your OS](#mount-as-drive)
@ -1373,7 +1437,7 @@ general usage:
on macos, connect from finder:
* [Go] -> [Connect to Server...] -> http://192.168.123.1:3923/
in order to grant full write-access to webdav clients, the volflag `daw` must be set and the account must also have delete-access (otherwise the client won't be allowed to replace the contents of existing files, which is how webdav works)
to upload or edit files with WebDAV clients, enable the `daw` volflag (because most WebDAV clients expect this) and give your account the delete-permission. This avoids getting several copies of the same file on the server. HOWEVER: This will also make all PUT-uploads overwrite existing files if the user has delete-access, so use with caution.
> note: if you have enabled [IdP authentication](#identity-providers) then that may cause issues for some/most webdav clients; see [the webdav section in the IdP docs](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#connecting-webdav-clients)
@ -1434,7 +1498,7 @@ unsafe, slow, not recommended for wan, enable with `--smb` for read-only or `--
click the [connect](http://127.0.0.1:3923/?hc) button in the control-panel to see connection instructions for windows, linux, macos
dependencies: `python3 -m pip install --user -U impacket==0.11.0`
dependencies: `python3 -m pip install --user -U impacket==0.13.0`
* newer versions of impacket will hopefully work just fine but there is monkeypatching so maybe not
some **BIG WARNINGS** specific to SMB/CIFS, in decreasing importance:
@ -1477,7 +1541,12 @@ tweaking the ui
* to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Circle,tags/.tn,tags/Artist,tags/Title,href`
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
see [./docs/rice](./docs/rice) for more, including:
* how to [hide ui-elements](./docs/rice/README.md#hide-ui-elements)
* [custom fonts](./docs/rice/README.md#custom-fonts)
* [custom loading-spinner](./docs/rice/README.md#boring-loader-spinner)
* adding stuff (css/`<meta>`/...) [to the html `<head>` tag](./docs/rice/README.md#head)
* [adding your own translation](./docs/rice/README.md#translations)
## opengraph
@ -1574,6 +1643,7 @@ the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`,
note:
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
* and file checksums can be shown with global-option `-e2d -mte +w` or volflag `e2d,mte=+w` (always active for users with permission `a`)
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
config file example (these options are recommended btw):
@ -1657,6 +1727,7 @@ set upload rules using volflags, some examples:
* `:c,nosub` disallow uploading into subdirectories; goes well with `rotn` and `rotf`:
* `:c,rotn=1000,2` moves uploads into subfolders, up to 1000 files in each folder before making a new one, two levels deep (must be at least 1)
* `:c,rotf=%Y/%m/%d/%H` enforces files to be uploaded into a structure of subfolders according to that date format
* `:c,rotf_tz=Europe/Oslo` sets the timezone (default is UTC unless global-option `rotf-tz` is changed)
* if someone uploads to `/foo/bar` the path would be rewritten to `/foo/bar/2021/08/06/23` for example
* but the actual value is not verified, just the structure, so the uploader can choose any values which conform to the format string
* just to avoid additional complexity in up2k which is enough of a mess already
@ -1743,6 +1814,8 @@ notes:
* `:c,magic` enables filetype detection for nameless uploads, same as `--magic`
* needs https://pypi.org/project/python-magic/ `python3 -m pip install --user -U python-magic`
* on windows grab this instead `python3 -m pip install --user -U python-magic-bin`
* `cachectl` changes how webbrowser will cache responses (the `Cache-Control` response-header); default is `no-cache` which will prevent repeated downloading of the same file unless necessary (browser will ask copyparty if the file has changed)
* adding `?cache` to a link will override this with "fully cache this for 69 seconds"; `?cache=321` is 321 seconds, and `?cache=i` is 7 days
## database location
@ -1849,7 +1922,7 @@ trigger a program on uploads, renames etc ([examples](./bin/hooks/))
you can set hooks before and/or after an event happens, and currently you can hook uploads, moves/renames, and deletes
there's a bunch of flags and stuff, see `--help-hooks`
there's a bunch of flags and stuff, see [`--help-hooks`](https://copyparty.eu/cli/#hooks-help-page)
if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
@ -2372,6 +2445,8 @@ it comes with a [systemd service](./contrib/systemd/copyparty@.service) as well
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)
> to start the systemd service, either do `systemctl start --user copyparty` to start it as your own user, or `systemctl start copyparty@bob` to use unix-user `bob`
## fedora package
@ -2458,6 +2533,10 @@ copyparty on NixOS is configured via `services.copyparty` options, for example:
```nix
services.copyparty = {
enable = true;
# the user to run the service as
user = "copyparty";
# the group to run the service as
group = "copyparty";
# directly maps to values in the [global] section of the copyparty config.
# see `copyparty --help` for available options
settings = {
@ -2482,6 +2561,12 @@ services.copyparty = {
k.passwordFile = "/run/keys/copyparty/k_password";
};
# create a group
groups = {
# users "ed" and "k" are part of the group g1
g1 = [ "ed" "k" ];
};
# create a volume
volumes = {
# create a volume at "/" (the webroot), which will
@ -2574,6 +2659,17 @@ quick summary of more eccentric web-browsers trying to view a directory index:
<p align="center"><img src="https://github.com/user-attachments/assets/88deab3d-6cad-4017-8841-2f041472b853" /></p>
# server hall of fame
unexpected things that run copyparty:
* an old [allwinner](https://a.ocv.me/pub/g/nerd-stuff/cpp/servers/aallwinner.jpg) android tv-box (ziptie-strapped to an HDD) running a firmware which flips the CPU into Big-Endian mode early during boot
* copyparty is [certified BE ready](https://a.ocv.me/pub/g/nerd-stuff/cpp/servers/be-ready.png) -- thanks, [Øl Telecom](http://ol-tele.com/)!
* an [SGI O2 (photo)](https://a.ocv.me/pub/g/nerd-stuff/cpp/servers/sgi-o2.jpg?cache) with a grand total of 64 MiB RAM running SGI IRIX; [screenshot](https://a.ocv.me/pub/g/nerd-stuff/cpp/servers/sgi-o2.png?cache)
* thanks again to the wonderful people at [Øl Telecom](http://ol-tele.com/)
* a [wristwatch](https://a.ocv.me/pub/g/nerd-stuff/cpp/servers/clockyparty.jpg)
# client examples
interact with copyparty using non-browser clients
@ -2594,6 +2690,10 @@ interact with copyparty using non-browser clients
* `chunk(){ curl -H pw:wark -T- http://127.0.0.1:3923/;}`
`chunk <movie.mkv`
* curl: append to existing file with `?apnd`
* `log(){ curl -H pw:wark -T- http://127.0.0.1:3923/logfile.txt?apnd;}`
`echo hey | log`
* bash: when curl and wget is not available or too boring
* `(printf 'PUT /junk?pw=wark HTTP/1.1\r\n\r\n'; cat movie.mkv) | nc 127.0.0.1 3923`
* `(printf 'PUT / HTTP/1.1\r\n\r\n'; cat movie.mkv) >/dev/tcp/127.0.0.1/3923`
@ -2725,6 +2825,10 @@ below are some tweaks roughly ordered by usefulness:
* using [pypy](https://www.pypy.org/) instead of [cpython](https://www.python.org/) *can* be 70% faster for some workloads, but slower for many others
* and pypy can sometimes crash on startup with `-j0` (TODO make issue)
* if you are running the copyparty server **on Windows or Macos:**
* `--casechk=n` makes it much faster, but also awakens [the usual surprises](https://github.com/9001/copyparty/issues/781) you expect from a case-insensitive filesystem
* this is the same as `casechk: n` in a config-file
## client-side
@ -2749,7 +2853,7 @@ when uploading files,
# security
there is a [discord server](https://discord.gg/25J8CdTT6G) with an `@everyone` for all important updates (at the lack of better ideas)
there is a [discord server](https://discord.gg/25J8CdTT6G) with announcements ; an `@everyone` for all important updates (at the lack of better ideas)
some notes on hardening
@ -2757,7 +2861,7 @@ some notes on hardening
* 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
* when running behind a reverse-proxy, listen on a unix-socket for tighter access control (and more performance); see [reverse-proxy](#reverse-proxy) or `--help-bind`
* when running behind a reverse-proxy, listen on a unix-socket for tighter access control (and more performance); see [reverse-proxy](#reverse-proxy) or [`--help-bind`](https://copyparty.eu/cli/#bind-help-page)
safety profiles:
@ -2845,7 +2949,7 @@ dirkeys are generated based on another salt (`--dk-salt`) + filesystem-path and
## password hashing
you can hash passwords before putting them into config files / providing them as arguments; see `--help-pwhash` for all the details
you can hash passwords before putting them into config files / providing them as arguments; see [`--help-pwhash`](https://copyparty.eu/cli/#pwhash-help-page) for all the details
`--ah-alg argon2` enables it, and if you have any plaintext passwords then it'll print the hashed versions on startup so you can replace them
@ -2871,6 +2975,11 @@ if [cfssl](https://github.com/cloudflare/cfssl/releases/latest) is installed, co
* this will be a self-signed certificate so you must install your `ca.pem` into all your browsers/devices
* if you want to avoid the hassle of distributing certs manually, please consider using a reverse proxy
to install cfssl on windows:
* [download](https://github.com/cloudflare/cfssl/releases/latest) `cfssl_windows_amd64.exe`, `cfssljson_windows_amd64.exe`, `cfssl-certinfo_windows_amd64.exe`
* rename them to `cfssl.exe`, `cfssljson.exe`, `cfssl-certinfo.exe`
* put them in PATH, for example inside `c:\windows\system32`
# recovering from crashes
@ -2905,7 +3014,7 @@ mandatory deps:
## optional dependencies
install these to enable bonus features
enable bonus features by installing these python-packages from pypi or so:
enable [hashed passwords](#password-hashing) in config: `argon2-cffi`
@ -2913,6 +3022,8 @@ enable [ftp-server](#ftp-server):
* for just plaintext FTP, `pyftpdlib` (is built into the SFX)
* with TLS encryption, `pyftpdlib pyopenssl`
enable [sftp-server](#sftp-server): `paramiko`
enable [music tags](#metadata-from-audio-files):
* either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
* or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
@ -2927,9 +3038,11 @@ enable [thumbnails](#thumbnails) of...
enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
enable [smb](#smb-server) support (**not** recommended): `impacket==0.13.0`
`pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
`pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram
* to install `pyvips` on Linux: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
* to install `pyvips` on windows: `pip install --user -U "pyvips[binary]"`
to install FFmpeg on Windows, grab [a recent build](https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z) -- you need `ffmpeg.exe` and `ffprobe.exe` from inside the `bin` folder; copy them into `C:\Windows\System32` or any other folder that's in your `%PATH%`
@ -2951,12 +3064,15 @@ set any of the following environment variables to disable its associated optiona
| `PRTY_NO_FFPROBE` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips, **metadata-scanning** must be handled by mutagen |
| `PRTY_NO_MAGIC` | do not use [magic](https://pypi.org/project/python-magic/) for filetype detection |
| `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
| `PRTY_NO_PARAMIKO` | disable sftp server ([paramiko](https://www.paramiko.org/)-based) |
| `PRTY_NO_PARTFTPY` | disable tftp server ([partftpy](https://github.com/9001/partftpy)-based) |
| `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
| `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
| `PRTY_NO_PIL_AVIF` | disable Pillow avif support (internal and/or [plugin](https://pypi.org/project/pillow-avif-plugin/)) |
| `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/pillow-heif/) |
| `PRTY_NO_PIL_WEBP` | disable use of native webp support in Pillow |
| `PRTY_NO_PSUTIL` | do not use [psutil](https://pypi.org/project/psutil/) for reaping stuck hooks and plugins on Windows |
| `PRTY_NO_PYFTPD` | disable ftp(s) server ([pyftpdlib](https://pypi.org/project/pyftpdlib/)-based) |
| `PRTY_NO_RAW` | disable all [rawpy](https://pypi.org/project/rawpy/)-based thumbnail support for RAW images |
| `PRTY_NO_VIPS` | disable all [libvips](https://pypi.org/project/pyvips/)-based thumbnail support; will fallback to Pillow or ffmpeg |
@ -2967,6 +3083,20 @@ example: `PRTY_NO_PIL=1 python3 copyparty-sfx.py`
* python2.7 on windows: `PRTY_NO_FFMPEG` + `PRTY_NO_FFPROBE` saves startup time
### dependency unvendoring
force use of system modules instead of the vendored versions:
| env-var | what it does |
| -------------------- | ------------ |
| `PRTY_SYS_ALL` | all of the below |
| `PRTY_SYS_DNSLIB` | replace [stolen/dnslib](./copyparty/stolen/dnslib) with [upstream](https://pypi.org/project/dnslib/) |
| `PRTY_SYS_IFADDR` | replace [stolen/ifaddr](./copyparty/stolen/ifaddr) with [upstream](https://pypi.org/project/ifaddr/) |
| `PRTY_SYS_QRCG` | replace [stolen/qrcodegen.py](./copyparty/stolen/qrcodegen.py) with [upstream](https://github.com/nayuki/QR-Code-generator/blob/master/python/qrcodegen.py) |
to debug, run copyparty with `PRTY_MODSPEC=1` to see where it's getting each module from
## optional gpl stuff
some bundled tools have copyleft dependencies, see [./bin/#mtag](bin/#mtag)
@ -3012,7 +3142,8 @@ another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty
run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails
it is a python [zipapp](https://docs.python.org/3/library/zipapp.html) meaning it doesn't have to unpack its own python code anywhere to run, so if the filesystem is busted it has a better chance of getting somewhere
* but note that it currently still needs to extract the web-resources somewhere (they'll land in the default TEMP-folder of your OS)
> there is also [copyparty-en.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty-en.pyz), english-only and without smb support (enterprise-friendly)
# install on android
@ -3029,6 +3160,8 @@ if you want thumbnails (photos+videos) and you're okay with spending another 132
* or if you want to use `vips` for photo-thumbs instead, `pkg install libvips && python -m pip install --user -U wheel && python -m pip install --user -U pyvips && (cd /data/data/com.termux/files/usr/lib/; ln -s libgobject-2.0.so{,.0}; ln -s libvips.so{,.42})`
if you are suddenly unable to access storage (permission issues), try forcequitting termux, revoke all of its permissions in android settings, and run the command `termux-setup-storage`
# install on ios
@ -3039,9 +3172,12 @@ first install one of the following:
and then copypaste the following command into `a-Shell`:
```sh
curl https://github.com/9001/copyparty/raw/refs/heads/hovudstraum/contrib/setup-ashell.sh | sh
curl -L https://github.com/9001/copyparty/raw/refs/heads/hovudstraum/contrib/setup-ashell.sh | sh
```
> if you want the latest copyparty beta, then do this instead:
> `curl -L https://copyparty.eu/beta/setup-ashell.sh | sh`
what this does:
* creates a basic [config file](#accounts-and-volumes) named `cpc` which you can edit with `vim cpc`
* adds the command `cpp` to launch copyparty with that config file

View file

@ -1,9 +1,7 @@
# Security Policy
if you hit something extra juicy pls let me know on either of the following
if you hit something extra juicy pls let me know on one of the following:
* email -- `copyparty@ocv.ze` except `ze` should be `me`
* [mastodon dm](https://layer8.space/@tripflag) -- `@tripflag@layer8.space`
* [github private vulnerability report](https://github.com/9001/copyparty/security/advisories/new), wow that form is complicated
* [twitter dm](https://twitter.com/tripflag) (if im somehow not banned yet)
no bug bounties sorry! all i can offer is greetz in the release notes

View file

@ -4,6 +4,11 @@ these programs either take zero arguments, or a filepath (the affected file), or
run copyparty with `--help-hooks` for usage details / hook type explanations (xm/xbu/xau/xiu/xbc/xac/xbr/xar/xbd/xad/xban)
in particular, if a hook is loaded into copyparty with the hook-flag `c` ("check") then its exit-code controls the action that launched the hook:
* exit-code `0` = allow the action, and/or continue running the next hook
* exit-code `100` = allow the action, and stop running any remaining consecutive hooks
* anything else = reject/prevent the original action, and don't run the remaining hooks
> **note:** in addition to event hooks (the stuff described here), copyparty has another api to run your programs/scripts while providing way more information such as audio tags / video codecs / etc and optionally daisychaining data between scripts in a processing pipeline; if that's what you want then see [mtp plugins](../mtag/) instead
@ -28,10 +33,19 @@ these are `--xiu` hooks; unlike `xbu` and `xau` (which get executed on every sin
* [reject-extension.py](reject-extension.py) rejects uploads if they match a list of file extensions
* [reloc-by-ext.py](reloc-by-ext.py) redirects an upload to another destination based on the file extension
* good example of the `reloc` [hook effect](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#hook-effects)
* [reject-and-explain.py](reject-and-explain.py) shows a custom error-message when it rejects an upload
* [reject-ramdisk.py](reject-ramdisk.py) rejects the upload if the destination is a ramdisk
* this hook uses the `I` flag which makes it 140x faster, but if the plugin has a bug it may crash copyparty
# on message
* [wget.py](wget.py) lets you download files by POSTing URLs to copyparty
* [wget-i.py](wget-i.py) is an import-safe modification of this hook (starts 140x faster, but higher chance of bugs)
* [qbittorrent-magnet.py](qbittorrent-magnet.py) starts downloading a torrent if you post a magnet url
* [usb-eject.py](usb-eject.py) adds web-UI buttons to safe-remove usb flashdrives shared through copyparty
* [msg-log.py](msg-log.py) is a guestbook; logs messages to a doc in the same folder
# general concept demos
* [import-me.py](import-me.py) shows how the `I` flag makes the hook 140x faster (but you need to be Very Careful when writing the plugin)
* [wget-i.py](wget-i.py) is an import-safe modification of [wget.py](wget.py)

55
bin/hooks/import-me.py Normal file
View file

@ -0,0 +1,55 @@
#!/usr/bin/env python3
from typing import Any
_ = r"""
the fastest hook in the west
(runs directly inside copyparty, not as a subprocess)
example usage as global config:
--xbu I,bin/hooks/import-me.py
example usage as a volflag (per-volume config):
-v srv/inc:inc:r:rw,ed:c,xbu=I,bin/hooks/import-me.py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(share filesystem-path srv/inc as volume /inc,
readable by everyone, read-write for user 'ed',
running this plugin on all uploads with the params listed below)
example usage as a volflag in a copyparty config file:
[/inc]
srv/inc
accs:
r: *
rw: ed
flags:
xbu: I,bin/hooks/import-me.py
parameters explained,
I = import; do not fork / subprocess
IMPORTANT NOTE:
because this hook is running inside copyparty, you need to
be EXCEPTIONALLY CAREFUL to avoid side-effects, for example
DO NOT os.chdir() or anything like that, and also make sure
that the name of this file is unique (cannot be the same as
an existing python module/library)
"""
def main(ka: dict[str, Any]) -> dict[str, Any]:
# "ka" is a dictionary with info from copyparty...
# but because we are running inside copyparty, we don't need such courtesies;
import inspect
cf = inspect.currentframe().f_back.f_back.f_back
t = "hello from hook; I am able to peek into copyparty's memory like so:\n function name: %s\n variables:\n %s\n"
t2 = "\n ".join([("%r: %r" % (k, v))[:99] for k, v in cf.f_locals.items()][:9])
logger = ka["log"]
logger(t % (cf.f_code, t2))
# must return a dictionary with:
# "rc": the retcode; 0 is ok
return {"rc": 0}

View file

@ -0,0 +1,60 @@
#!/usr/bin/env python3
import json
import os
import re
import sys
_ = r"""
reject file upload (with a nice explanation why)
example usage as global config:
--xbu j,c1,bin/hooks/reject-and-explain.py
example usage as a volflag (per-volume config):
-v srv/inc:inc:r:rw,ed:c,xbu=j,c1,bin/hooks/reject-and-explain.py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(share filesystem-path srv/inc as volume /inc,
readable by everyone, read-write for user 'ed',
running this plugin on all uploads with the params listed below)
example usage as a volflag in a copyparty config file:
[/inc]
srv/inc
accs:
r: *
rw: ed
flags:
xbu: j,c1,bin/hooks/reject-and-explain.py
parameters explained,
xbu = execute-before-upload (can also be xau, execute-after-upload)
j = this hook needs upload information as json (not just the filename)
c1 = this hook returns json on stdout, so tell copyparty to read that
"""
def main():
inf = json.loads(sys.argv[1])
vdir, fn = os.path.split(inf["vp"])
print("inf[vp] = %r" % (inf["vp"],), file=sys.stderr)
# the following is what decides if we'll accept the upload or reject it:
# we check if the upload-folder url matches the following regex-pattern:
ok = re.search(r"(^|/)day[0-9]+$", vdir, re.IGNORECASE)
if ok:
# allow the upload
print("{}")
return
# the upload was rejected; display the following errortext:
errmsg = "Files can only be uploaded into a folder named 'DayN' where N is a number, for example 'Day573'. This file was REJECTED: "
errmsg += inf["vp"] # if you want to mention the file's url
print(json.dumps({"rejectmsg": errmsg}))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,72 @@
#!/usr/bin/env python3
import os
import threading
from argparse import Namespace
from jinja2.nodes import Name
from copyparty.fsutil import Fstab
from typing import Any, Optional
_ = r"""
reject an upload if the target folder is on a ramdisk; useful when you
have a volume where some folders inside are ramdisks but others aren't
example usage as global config:
--xbu I,bin/hooks/reject-ramdisk.py
example usage as a volflag (per-volume config):
-v srv/inc:inc:r:rw,ed:c,xbu=I,bin/hooks/reject-ramdisk.py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(share filesystem-path srv/inc as volume /inc,
readable by everyone, read-write for user 'ed',
running this plugin on all uploads with the params listed below)
example usage as a volflag in a copyparty config file:
[/inc]
srv/inc
accs:
r: *
rw: ed
flags:
xbu: I,bin/hooks/reject-ramdisk.py
parameters explained,
I = import; do not fork / subprocess
IMPORTANT NOTE:
because this hook is imported inside copyparty, you need to
be EXCEPTIONALLY CAREFUL to avoid side-effects, for example
DO NOT os.chdir() or anything like that, and also make sure
that the name of this file is unique (cannot be the same as
an existing python module/library)
"""
mutex = threading.Lock()
fstab: Optional[Fstab] = None
def main(ka: dict[str, Any]) -> dict[str, Any]:
global fstab
with mutex:
log = ka["log"] # this is a copyparty NamedLogger function
if not fstab:
log("<HOOK:RAMDISK> creating fstab", 6)
args = Namespace()
args.mtab_age = 1 # cache the filesystem info for 1 sec
fstab = Fstab(log, args, False)
ap = ka["ap"] # abspath the upload is going to
fs, mp = fstab.get(ap) # figure out what the filesystem is
ramdisk = fs in ("tmpfs", "overlay") # looks like a ramdisk?
# log("<HOOK:RAMDISK> fs=%r" % (fs,))
if ramdisk:
t = "Upload REJECTED because destination is a ramdisk"
return {"rc": 1, "rejectmsg": t}
return {"rc": 0}

View file

@ -34,7 +34,10 @@ MOUNT_BASE = b"/run/media/egon/"
def main():
try:
label = sys.argv[1].split(":usb-eject:")[1].split(":")[0]
msg = sys.argv[1]
if msg.startswith("upload-queue-empty;"):
return
label = msg.split(":usb-eject:")[1].split(":")[0]
mp = MOUNT_BASE + unquote(label)
# print("ejecting [%s]... " % (mp,), end="")
mp = os.path.abspath(os.path.realpath(mp))

100
bin/hooks/wget-i.py Executable file
View file

@ -0,0 +1,100 @@
#!/usr/bin/env python3
import os
import threading
import subprocess as sp
_ = r"""
use copyparty as a file downloader by POSTing URLs as
application/x-www-form-urlencoded (for example using the
📟 message-to-server-log in the web-ui)
this hook is a modified copy of wget.py, modified to
make it import-safe so it can be run with the 'I' flag,
which speeds up the startup time of the hook by 140x
example usage as global config:
--xm aw,I,bin/hooks/wget-i.py
parameters explained,
xm = execute on message-to-server-log
aw = only users with write-access can use this
I = import; do not fork / subprocess
example usage as a volflag (per-volume config):
-v srv/inc:inc:r:rw,ed:c,xm=aw,I,bin/hooks/wget.py
^^^^^^^^^^^^^^^^^^^^^^^^^^^
(share filesystem-path srv/inc as volume /inc,
readable by everyone, read-write for user 'ed',
running this plugin on all messages with the params explained above)
example usage as a volflag in a copyparty config file:
[/inc]
srv/inc
accs:
r: *
rw: ed
flags:
xm: aw,I,bin/hooks/wget.py
the volflag examples only kicks in if you send the message
while you're in the /inc folder (or any folder below there)
IMPORTANT NOTE:
because this hook uses the 'I' flag to run inside copyparty,
many other flags will not work (f,j,c3,t3600 as seen in the
original wget.py), and furthermore + more importantly we
need to be EXCEPTIONALLY CAREFUL to avoid side-effects, so
the os.chdir has been replaced with cwd=dirpath for example
"""
def do_stuff(inf):
"""
worker function which is executed in another thread to
avoid blocking copyparty while the download is running,
since we cannot use the 'f,t3600' hook-flags with 'I'
"""
# first things first; grab the logger-function which copyparty is letting us borrow
log = inf["log"]
url = inf["txt"]
if url.startswith("upload-queue-empty;"):
return
if "://" not in url:
url = "https://" + url
proto = url.split("://")[0].lower()
if proto not in ("http", "https", "ftp", "ftps"):
raise Exception("bad proto {}".format(proto))
dirpath = inf["ap"]
name = url.split("?")[0].split("/")[-1]
msg = "-- DOWNLOADING " + name
log(msg)
tfn = os.path.join(dirpath, msg)
open(tfn, "wb").close()
cmd = ["wget", "--trust-server-names", "-nv", "--", url]
try:
# two things to note here:
# - cannot use the `c3` hook-flag with `I` so mute output with stdout=sp.DEVNULL instead;
# - MUST NOT use os.chdir with 'I' so use cwd=dirpath instead
sp.check_call(cmd, cwd=dirpath, stdout=sp.DEVNULL)
except:
t = "-- FAILED TO DOWNLOAD " + name
log(t, 3) # 3=yellow=warning
open(os.path.join(dirpath, t), "wb").close()
raise # have copyparty scream about the details in the log
os.unlink(tfn)
def main(inf):
threading.Thread(target=do_stuff, args=(inf,), daemon=True).start()

View file

@ -47,6 +47,9 @@ while you're in the /inc folder (or any folder below there)
def main():
inf = json.loads(sys.argv[1])
url = inf["txt"]
if url.startswith("upload-queue-empty;"):
return
if "://" not in url:
url = "https://" + url

View file

@ -68,3 +68,8 @@ instead of affecting all volumes, you can set the options for just one volume li
* `:c,mtp=key=f,audio-key.py`
* `:c,mtp=.bpm=f,audio-bpm.py`
* `:c,mtp=ahash,vhash=f,media-hash.py`
# tips & tricks
* to delete tags for all files below `blog*` and rescan that, `sqlite3 .hist/up2k.db "delete from mt where w in (select substr(w,1,16) from up where rd like 'blog%')";`

View file

@ -4,13 +4,19 @@ import os
import sys
import tempfile
import subprocess as sp
import keyfinder
try:
import keyfinder
PKF = True
except:
PKF = False
from copyparty.util import fsenc
"""
dep: github/mixxxdj/libkeyfinder
dep: pypi/keyfinder
dep: pypi/keyfinder -OR- EvanPurkhiser/keyfinder-cli
dep: ffmpeg
"""
@ -35,7 +41,17 @@ def det(tf):
])
# fmt: on
print(keyfinder.key(tf).camelot())
if PKF:
print(keyfinder.key(tf).camelot())
else:
# fmt: off
sp.check_call([
b"keyfinder-cli",
b"-n",
b"camelot",
fsenc(tf)
])
# fmt: on
def main():

53
bin/mtag/geotag.py Executable file
View file

@ -0,0 +1,53 @@
import json
import re
import sys
from copyparty.util import fsenc, runcmd
"""
uses exiftool to geotag images based on embedded gps coordinates in exif data
adds four new metadata keys:
.gps_lat = latitute
.gps_lon = longitude
.masl = meters above sea level
city = "city, subregion, region"
usage: -mtp .masl,.gps_lat,.gps_lon,city=ad,t10,bin/mtag/geotag.py
example: https://a.ocv.me/pub/blog/j7/8/?grid=0
"""
def main():
cmd = b"exiftool -api geolocation -n".split(b" ")
rc, so, se = runcmd(cmd + [fsenc(sys.argv[1])])
ptn = re.compile("([^:]*[^ :]) *: (.*)")
city = ["", "", ""]
ret = {}
for ln in so.split("\n"):
m = ptn.match(ln)
if not m:
continue
k, v = m.groups()
if k == "Geolocation City":
city[2] = v
elif k == "Geolocation Subregion":
city[1] = v
elif k == "Geolocation Region":
city[0] = v
elif k == "GPS Latitude":
ret[".gps_lat"] = "%.04f" % (float(v),)
elif k == "GPS Longitude":
ret[".gps_lon"] = "%.04f" % (float(v),)
elif k == "GPS Altitude":
ret[".masl"] = str(int(float(v)))
v = ", ".join(city).strip(", ")
if v:
ret["city"] = v
print(json.dumps(ret))
if __name__ == "__main__":
main()

View file

@ -155,6 +155,11 @@ install_keyfinder() {
return
}
(cat /etc/alpine-release || echo a) 2>&1 | grep -E '3\.2[3-9]' && {
echo "alpine too new; ffmpeg8 is keyfinder-py incompat; giving up"
return
}
cd "$td"
github_tarball https://api.github.com/repos/mixxxdj/libkeyfinder/releases/latest
ls -al
@ -189,7 +194,7 @@ install_keyfinder() {
exit 1
}
x=${-//[^x]/}; set -x; cat /etc/alpine-release
x=${-//[^x]/}; set -x; cat /etc/alpine-release || true
# rm -rf /Users/ed/Library/Python/3.9/lib/python/site-packages/*keyfinder*
CFLAGS="-I$h/pe/keyfinder/include -I/opt/local/include -I/usr/include/ffmpeg" \
CXXFLAGS="-I$h/pe/keyfinder/include -I/opt/local/include -I/usr/include/ffmpeg" \

View file

@ -6,8 +6,8 @@ __copyright__ = 2019
__license__ = "MIT"
__url__ = "https://github.com/9001/copyparty/"
S_VERSION = "2.1"
S_BUILD_DT = "2025-09-06"
S_VERSION = "2.2"
S_BUILD_DT = "2025-12-16"
"""
mount a copyparty server (local or remote) as a filesystem
@ -284,8 +284,8 @@ class Gateway(object):
if ar.td:
self.ssl_context = ssl._create_unverified_context()
elif ar.te:
self.ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
self.ssl_context.load_verify_locations(ar.te)
self.ssl_context = ssl.create_default_context(cafile=ar.te)
self.ssl_context.check_hostname = ar.teh
self.conns = {}
@ -1165,6 +1165,7 @@ NOTE: if server has --usernames enabled, then password is "username:password"
ap2 = ap.add_argument_group("https/TLS")
ap2.add_argument("-te", metavar="PEMFILE", help="certificate to expect/verify")
ap2.add_argument("-teh", action="store_true", help="require correct hostname in -te cert")
ap2.add_argument("-td", action="store_true", help="disable certificate check")
ap2 = ap.add_argument_group("cache/perf")

View file

@ -1,8 +1,8 @@
#!/usr/bin/env python3
from __future__ import print_function, unicode_literals
S_VERSION = "2.13"
S_BUILD_DT = "2025-09-05"
S_VERSION = "2.18"
S_BUILD_DT = "2026-01-02"
"""
u2c.py: upload to copyparty
@ -165,8 +165,8 @@ class HCli(object):
elif self.verify is True:
self.ctx = None
else:
self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
self.ctx.load_verify_locations(self.verify)
self.ctx = ssl.create_default_context(cafile=self.verify)
self.ctx.check_hostname = ar.teh
self.base_hdrs = {
"Accept": "*/*",
@ -196,6 +196,8 @@ class HCli(object):
hdrs.update(self.base_hdrs)
if self.ar.a:
hdrs["PW"] = self.ar.a
if self.ar.ba:
hdrs["Authorization"] = self.ar.ba
if ctype:
hdrs["Content-Type"] = ctype
if meth == "POST" and CLEN not in hdrs:
@ -232,6 +234,7 @@ class HCli(object):
MJ = "application/json"
MO = "application/octet-stream"
MM = "application/x-www-form-urlencoded"
CLEN = "Content-Length"
web = None # type: HCli
@ -491,6 +494,12 @@ print = safe_print if VT100 else flushing_print
def termsize():
try:
w, h = os.get_terminal_size()
return w, h
except:
pass
env = os.environ
def ioctl_GWINSZ(fd):
@ -850,7 +859,7 @@ def handshake(ar, file, search):
return [], False
elif sc == 409 or "<pre>upload rejected, file already exists" in txt:
return [], False
elif sc == 403:
elif sc == 403 or sc == 401:
print("\nERROR: login required, or wrong password:\n%s" % (txt,))
raise BadAuth()
@ -979,6 +988,7 @@ class Ctl(object):
self.nfiles, self.nbytes = self.stats
self.filegen = walkdirs([], ar.files, ar.x)
self.recheck = [] # type: list[File]
self.last_file = None
if ar.safe:
self._safe()
@ -1015,6 +1025,11 @@ class Ctl(object):
self._fancy()
file = self.last_file
if self.up_br and file:
zs = quotep(file.name.encode("utf-8", WTF8))
web.req("POST", file.url, {}, b"msg=upload-queue-empty;" + zs, MM)
self.ok = not self.errs
def _safe(self):
@ -1225,9 +1240,7 @@ class Ctl(object):
while req:
print("DELETING ~%s#%s" % (srd, len(req)))
body = json.dumps(req).encode("utf-8")
sc, txt = web.req(
"POST", self.ar.url + "?delete", {}, body, MJ
)
sc, txt = web.req("POST", "/?delete", {}, body, MJ)
if sc == 413 and "json 2big" in txt:
print(" (delete request too big; slicing...)")
req = req[: len(req) // 2]
@ -1455,6 +1468,7 @@ class Ctl(object):
file = fsl.file
cids = fsl.cids
self.last_file = file
with self.mutex:
if not self.uploader_busy:
@ -1538,7 +1552,8 @@ NOTE: if server has --usernames enabled, then password is "username:password"
ap.add_argument("url", type=unicode, help="server url, including destination folder")
ap.add_argument("files", type=files_decoder, nargs="+", help="files and/or folders to process")
ap.add_argument("-v", action="store_true", help="verbose")
ap.add_argument("-a", metavar="PASSWD", help="password or $filepath")
ap.add_argument("-a", metavar="PASSWD", default="", help="password (or $filepath) for copyparty (is sent in header 'PW')")
ap.add_argument("--ba", metavar="PASSWD", default="", help="password (or $filepath) for basic-auth (usually not necessary)")
ap.add_argument("-s", action="store_true", help="file-search (disables upload)")
ap.add_argument("-x", type=unicode, metavar="REGEX", action="append", help="skip file if filesystem-abspath matches REGEX (option can be repeated), example: '.*/\\.hist/.*'")
ap.add_argument("--ok", action="store_true", help="continue even if some local files are inaccessible")
@ -1581,6 +1596,7 @@ NOTE: if server has --usernames enabled, then password is "username:password"
ap = app.add_argument_group("tls")
ap.add_argument("-te", metavar="PATH", help="path to ca.pem or cert.pem to expect/verify")
ap.add_argument("-teh", action="store_true", help="require correct hostname in -te cert")
ap.add_argument("-td", action="store_true", help="disable certificate check")
# fmt: on
@ -1676,11 +1692,15 @@ NOTE: if server has --usernames enabled, then password is "username:password"
print("\n\n %s\n\n" % (t,))
raise
if ar.a and ar.a.startswith("$"):
fn = ar.a[1:]
print("reading password from file [{0}]".format(fn))
with open(fn, "rb") as f:
ar.a = f.read().decode("utf-8").strip()
for k in ("a", "ba"):
zs = getattr(ar, k)
if zs.startswith("$"):
print("reading password from file [%s]" % (zs[1:],))
with open(zs[1:], "rb") as f:
setattr(ar, k, f.read().decode("utf-8").strip())
if ar.ba:
ar.ba = "Basic " + base64.b64encode(ar.ba.encode("utf-8")).decode("utf-8")
for n in range(ar.rh):
try:

View file

@ -61,6 +61,8 @@ def rep_server():
print("copyparty says %r" % (sck.recv_string(),))
reply = b"thx"
# reply = b"return 1" # non-zero to block an upload
# reply = b'{"rc":1}' # or as json, that's fine too
# reply = b'{"rejectmsg":"naw dude"}' # or custom message
sck.send(reply)

View file

@ -7,6 +7,12 @@
* works on windows, linux and macos
* assumes `copyparty-sfx.py` was renamed to `copyparty.py` in the same folder as `copyparty.bat`
### [`setup-ashell.sh`](setup-ashell.sh)
* run copyparty on an iPhone/iPad using [a-Shell](https://holzschu.github.io/a-Shell_iOS/)
* not very useful due to limitations in iOS:
* not able to share all of your phone's storage
* cannot run in the background
### [`index.html`](index.html)
* drop-in redirect from an httpd to copyparty
* assumes the webserver and copyparty is running on the same server/IP

View file

@ -6,7 +6,7 @@
#
# to reverse-proxy a specific path/subpath/location below a domain
# (rather than a complete subdomain), for example "/qw/er", you must
# run copyparty with --rp-loc /qw/as and also change the following:
# run copyparty with --rp-loc /qw/er and also change the following:
# location / {
# proxy_pass http://cpp_tcp;
# to this:

View file

@ -48,10 +48,13 @@ let
accountsWithPlaceholders = mapAttrs (name: attrs: passwordPlaceholder name);
volumesWithoutVariables = filterAttrs (k: v: !(hasInfix "\${" v.path)) cfg.volumes;
configStr = ''
${mkSection "global" cfg.settings}
${cfg.globalExtraConfig}
${mkSection "accounts" (accountsWithPlaceholders cfg.accounts)}
${mkSection "groups" cfg.groups}
${concatStringsSep "\n" (mapAttrsToList mkVolume cfg.volumes)}
'';
@ -167,6 +170,19 @@ in
'';
};
groups = mkOption {
type = types.attrsOf (types.listOf types.str);
description = ''
A set of copyparty groups to create and the users that should be part of each group.
'';
default = { };
example = literalExpression ''
{
group_name = [ "user1" "user2" ];
};
'';
};
volumes = mkOption {
type = types.attrsOf (
types.submodule (
@ -311,7 +327,7 @@ in
BindPaths =
(if cfg.settings ? hist then [ cfg.settings.hist ] else [ ])
++ [ externalStateDir ]
++ (mapAttrsToList (k: v: v.path) cfg.volumes);
++ (mapAttrsToList (k: v: v.path) volumesWithoutVariables);
# ProtectSystem = "strict";
# Note that unlike what 'ro' implies,
# this actually makes it impossible to read anything in the root FS,
@ -350,18 +366,32 @@ in
#: in front of things means it wont change it if the directory already exists.
group = ":${cfg.group}";
user = ":${cfg.user}";
mode = ":755";
mode = ":${
# Use volume permissions if set
if (value.flags ? chmod_d) then
value.flags.chmod_d
# Else, use global permission if set
else if (cfg.settings ? chmod-d) then
cfg.settings.chmod-d
# Else, use the default permission
else
"755"
}";
};
}
) cfg.volumes
) volumesWithoutVariables
);
users.groups.copyparty = lib.mkIf (cfg.user == "copyparty" && cfg.group == "copyparty") { };
users.users.copyparty = lib.mkIf (cfg.user == "copyparty" && cfg.group == "copyparty") {
description = "Service user for copyparty";
group = "copyparty";
home = externalStateDir;
isSystemUser = true;
users.groups = lib.mkIf (cfg.group == "copyparty") {
copyparty = { };
};
users.users = lib.mkIf (cfg.user == "copyparty") {
copyparty = {
description = "Service user for copyparty";
group = cfg.group;
home = externalStateDir;
isSystemUser = true;
};
};
environment.systemPackages = lib.mkIf cfg.mkHashWrapper [
(pkgs.writeShellScriptBin "copyparty-hash" ''
@ -380,4 +410,3 @@ in
}
);
}

View file

@ -3,9 +3,9 @@
# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead.
pkgname=copyparty
pkgver="1.19.7"
pkgver="1.20.0"
pkgrel=1
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
arch=("any")
url="https://github.com/9001/${pkgname}"
license=('MIT')
@ -14,6 +14,7 @@ makedepends=("python-wheel" "python-setuptools" "python-build" "python-installer
optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tags"
"cfssl: generate TLS certificates on startup"
"python-mutagen: music tags (alternative)"
"python-paramiko: sftp server",
"python-pillow: thumbnails for images"
"python-pyvips: thumbnails for images (higher quality, faster, uses more ram)"
"libkeyfinder: detection of musical keys"
@ -23,7 +24,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
)
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
backup=("etc/${pkgname}/copyparty.conf" )
sha256sums=("229476fc111de22a46d56c564d5e615bce6ce222321bcb73b336a3ead03d01f9")
sha256sums=("a1fd3aab51f30435f07f1d128cf773262ee69a1554c9c32ea1e36d06438eb291")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -2,9 +2,9 @@
pkgname=copyparty
pkgver=1.19.7
pkgver=1.20.0
pkgrel=1
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
arch=("any")
url="https://github.com/9001/${pkgname}"
license=('MIT')
@ -13,6 +13,7 @@ makedepends=("python3-wheel" "python3-setuptools" "python3-build" "python3-insta
optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tags"
"golang-cfssl: generate TLS certificates on startup"
"python3-mutagen: music tags (alternative)"
"python3-paramiko: sftp server"
"python3-pil: thumbnails for images"
"python3-openssl: ftps functionality"
"python3-zmq: send zeromq messages from event-hooks"
@ -20,7 +21,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
)
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
backup=("/etc/${pkgname}.d/init" )
sha256sums=("229476fc111de22a46d56c564d5e615bce6ce222321bcb73b336a3ead03d01f9")
sha256sums=("a1fd3aab51f30435f07f1d128cf773262ee69a1554c9c32ea1e36d06438eb291")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -26,7 +26,7 @@ Environment=XDG_CONFIG_HOME=/home/cpp/.config
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
ExecStart=/usr/bin/python3 /usr/local/bin/copyparty -c /etc/copyparty.d/init
[Install]
WantedBy=multi-user.target

View file

@ -15,6 +15,7 @@
pyzmq,
ffmpeg,
mutagen,
paramiko,
pyftpdlib,
magic,
partftpy,
@ -44,6 +45,9 @@
# send ZeroMQ messages from event-hooks
withZeroMQ ? true,
# enable SFTP server
withSFTP ? false,
# enable FTP server
withFTP ? true,
@ -67,24 +71,71 @@
# additional dependencies
extraPythonPackages ? (_p: [ ]),
# to build stable + unstable with the same file
stable ? true,
# for commit date, only used when stable = false
copypartyFlake ? null,
nix-gitignore,
}:
let
pinData = lib.importJSON ./pin.json;
runtimeDeps = ([ util-linux ] ++ extraPackages ++ lib.optional withMediaProcessing ffmpeg);
inherit (copypartyFlake) lastModifiedDate;
# ex: "1970" "01" "01"
dateStringsZeroPrefixed = {
year = builtins.substring 0 4 lastModifiedDate;
month = builtins.substring 4 2 lastModifiedDate;
day = builtins.substring 6 2 lastModifiedDate;
};
# ex: "1970" "1" "1"
dateStringsShort = builtins.mapAttrs (_: val: toString (lib.toIntBase10 val)) dateStringsZeroPrefixed;
unstableVersion =
if copypartyFlake == null then
"${pinData.version}-unstable"
else
with dateStringsZeroPrefixed; "${pinData.version}-unstable-${year}-${month}-${day}"
;
version = if stable then pinData.version else unstableVersion;
stableSrc = fetchurl {
inherit (pinData) url hash;
};
root = ../../../..;
unstableSrc = nix-gitignore.gitignoreSource [] root;
src = if stable then stableSrc else unstableSrc;
rev = copypartyFlake.shortRev or copypartyFlake.dirtyShortRev or "unknown";
unstableCodename = "unstable" + (lib.optionalString (copypartyFlake != null) "-${rev}");
in
buildPythonApplication {
pname = "copyparty";
inherit (pinData) version;
src = fetchurl {
inherit (pinData) url hash;
};
inherit version src;
postPatch = lib.optionalString (!stable) ''
old_src="$(mktemp -d)"
tar -C "$old_src" -xf ${stableSrc}
declare -a folders
folders=("$old_src"/*)
count_folders="''${#folders[@]}"
if [[ $count_folders != 1 ]]; then
declare -p folders
echo "Expected 1 folder, found $count_folders" >&2
exit 1
fi
old_src_folder="''${folders[0]}"
cp -r "$old_src_folder"/copyparty/web/deps copyparty/web/deps
sed -i 's/^CODENAME =.*$/CODENAME = "${unstableCodename}"/' copyparty/__version__.py
${lib.optionalString (copypartyFlake != null) (with dateStringsShort; ''
sed -i 's/^BUILD_DT =.*$/BUILD_DT = (${year}, ${month}, ${day})/' copyparty/__version__.py
'')}
'';
dependencies =
[
jinja2
fusepy
]
++ lib.optional withSMB impacket
++ lib.optional withSFTP paramiko
++ lib.optional withFTP pyftpdlib
++ lib.optional withFTPS pyopenssl
++ lib.optional withTFTP partftpy
@ -106,7 +157,7 @@ buildPythonApplication {
meta = {
description = "Turn almost any device into a file server";
longDescription = ''
Portable file server with accelerated resumable uploads, dedup, WebDAV,
Portable file server with accelerated resumable uploads, dedup, WebDAV, SFTP,
FTP, TFTP, zeroconf, media indexer, thumbnails++ all in one file, no deps
'';
homepage = "https://github.com/9001/copyparty";

View file

@ -1,5 +1,5 @@
{
"url": "https://github.com/9001/copyparty/releases/download/v1.19.7/copyparty-1.19.7.tar.gz",
"version": "1.19.7",
"hash": "sha256-IpR2/BEd4ipG1WxWTV5hW85s4iIyG8tzszaj6tA9Afk="
"url": "https://github.com/9001/copyparty/releases/download/v1.20.0/copyparty-1.20.0.tar.gz",
"version": "1.20.0",
"hash": "sha256-of06q1HzBDXwfx0SjPdzJi7mmhVUycMuoeNtBkOOspE="
}

View file

@ -1,8 +1,29 @@
final: prev: {
copyparty = final.python3.pkgs.callPackage ./copyparty {
ffmpeg = final.ffmpeg-full;
final: prev:
let
fullAttrs = {
withHashedPasswords = true;
withCertgen = true;
withThumbnails = true;
withFastThumbnails = true;
withMediaProcessing = true;
withBasicAudioMetadata = true;
withZeroMQ = true;
withSFTP = true;
withFTP = true;
withFTPS = true;
withTFTP = true;
withSMB = true;
withMagic = true;
};
call = attrs: final.python3.pkgs.callPackage ./copyparty ({ ffmpeg = final.ffmpeg-full; } // attrs);
in
{
copyparty = call { stable = true; };
copyparty-unstable = call { stable = false; };
copyparty-full = call (fullAttrs // { stable = true; });
copyparty-unstable-full = call (fullAttrs // { stable = false; });
python3 = prev.python3.override {
packageOverrides = pyFinal: pyPrev: {
partftpy = pyFinal.callPackage ./partftpy { };

View file

@ -5,15 +5,15 @@ License: MIT
Group: Utilities
URL: https://github.com/9001/copyparty
Source0: copyparty-$pkgver.tar.gz
Summary: File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++
Summary: File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++
BuildArch: noarch
BuildRequires: python3, python3-devel, pyproject-rpm-macros, python-setuptools, python-wheel, make
Requires: python3, (python3-jinja2 or python-jinja2), lsof
Recommends: ffmpeg, (golang-github-cloudflare-cfssl or cfssl), python-mutagen, python-pillow, python-pyvips
Recommends: qm-vamp-plugins, python-argon2-cffi, (python-pyopenssl or pyopenssl), python-impacket
Recommends: qm-vamp-plugins, python-argon2-cffi, (python-pyopenssl or pyopenssl), python-paramiko, python-impacket
%description
Portable file server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++ all in one file, no deps
Portable file server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++ all in one file, no deps
See release at https://github.com/9001/copyparty/releases

View file

@ -39,3 +39,9 @@ point `--css-browser` to one of these by URL:
* turns copyparty into chromecast just more flexible (and probably way more buggy)
* usage: put the js somewhere in the webroot and `--js-browser /memes/meadup.js`
# junk
* [**rave.js**](./rave.js): april-fools joke, [demo (epilepsy warning)](https://cd.ocv.me/b/d2/d21/#af-9b927c42,sorthref), not maintained, very buggy

View file

@ -0,0 +1,173 @@
# copyparty with Podman and Systemd
Use this configuration if you want to run copyparty in a Podman container, with the reliability of running the container under a systemd service.
Documentation for `.container` files can be found in the [Container unit](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#container-units-container) docs. Systemd does not understand `.container` files natively, so Podman converts these to `.service` files with a [systemd-generator](https://www.freedesktop.org/software/systemd/man/latest/systemd.generator.html). This process is transparent, but sometimes needs to be debugged in case your `.container` file is malformed. There are instructions to debug the systemd generator in the Troubleshooting section below.
To run copyparty in this way, you must already have podman installed. To install Podman, see: https://podman.io/docs/installation
There is a sample configuration file in the same directory as this file (`copyparty.conf`).
## Run the container as root
Running the container as the root user is easy to set up, but less secure. There are instructions in the next section to run the container as a rootless user if you'd rather run the container like that.
First, change this line in the `copyparty.container` file to reflect the directory you want to share. By default, it shares `/mnt/` but you'll probably want to change that.
```
# Change /mnt to something you want to share
Volume=/mnt:/w:z
```
Note that you can select the owner and group of this volume by changing the `uid:` and `gid:` of the volume in `copyparty.conf`, but for simplicity let's assume you want it to be owned by `root:root`.
To install and start copyparty with Podman and systemd as the root user, run the following:
```shell
sudo mkdir -pv /etc/containers/systemd/ /etc/copyparty/
sudo cp -v copyparty.container /etc/containers/systemd/
sudo cp -v copyparty.conf /etc/copyparty/
sudo systemctl daemon-reload
sudo systemctl start copyparty
```
Note: You can't "enable" this kind of Podman service. The `[Install]` section of the `.container` file effectively handles enabling the service so that it starts when the server reboots.
You can see the status of the service with:
```shell
sudo systemctl status -a copyparty
```
You can see (and follow) the logs with either of these commands:
```shell
sudo podman logs -f copyparty
# -a is required or else you'll get output like: copyparty[549025]: [649B blob data]
sudo journalctl -a -f -u copyparty
```
## Run the container as a non-root user
This configuration is more secure, but is more involved and requires ensuring files have proper permissions. You will need a root user account to do some of this setup.
First, you need a user to run the container as. In this example we'll create a "podman" user with UID=1001 and GID=1001.
```shell
sudo groupadd -g 1001 podman
sudo useradd -u 1001 -m podman
sudo usermod -aG podman podman
sudo loginctl enable-linger podman
# Set a strong password for this user
sudo -u podman passwd
```
The `enable-linger` command allows the podman user to run systemd user services that persist even when the user is not logged in. You could use a user that already exists in the system to run this service as, just make sure to run `loginctl enable-linger USERNAME` for that user.
Next, change these lines in the `copyparty.container` file to reflect the config directory and the directory you want to share. By default, the config shares `/home/podman/copyparty/sharing/` but you'll probably want to change this:
```
# Change to reflect your non-root user's home directory
Volume=/home/podman/copyparty/config:/cfg:z
# Change to the directory you want to share
Volume=/home/podman/copyparty/sharing:/w:z
```
Make sure the podman user has read/write access to both of these directories.
Next, **log in to the server as the podman user**.
To install and start copyparty as the non-root podman user, run the following:
```shell
mkdir -pv /home/podman/.config/containers/systemd/ /home/podman/copyparty/config
cp -v copyparty.container /home/podman/.config/containers/systemd/copyparty.container
cp -v copyparty.conf /home/podman/copyparty/config
systemctl --user daemon-reload
systemctl --user start copyparty
```
**Important note: Never use `sudo` with `systemctl --user`!**
You can check the status of the user service with:
```shell
systemctl --user status -a copyparty
```
You can see (and follow) the logs with:
```shell
podman logs -f copyparty
journalctl --user -a -f -u copyparty
```
## Troubleshooting
If the container fails to start, and you've modified the `.container` service, it's likely that your `.container` file failed to be translated into a `.service` file. You can debug the podman service generator with this command:
```shell
sudo /usr/lib/systemd/system-generators/podman-system-generator --dryrun
```
## Allowing Traffic from Outside your Server
To allow traffic on port 3923 of your server, you should run:
```shell
sudo firewall-cmd --permanent --add-port=3923/tcp
sudo firewall-cmd --reload
```
Otherwise, you won't be able to access the copyparty server from anywhere other than the server itself.
## Updating copyparty
To update the version of copyparty used in the container, you can:
```shell
# If root:
sudo podman pull docker.io/copyparty/ac:latest
sudo systemctl restart copyparty
# If non-root:
podman pull docker.io/copyparty/ac:latest
systemctl --user restart copyparty
```
Or, you can change the pinned version of the image in the `[Container]` section of the `.container` file and run:
```shell
# If root:
sudo systemctl daemon-reload
sudo systemctl restart copyparty
# If non-root:
systemctl --user daemon-reload
systemctl --user restart copyparty
```
Podman will pull the image you've specified when restarting. If you have it set to `:latest`, Podman does not know to re-pull the container.
### Enabling auto-update
Alternatively, you can enable auto-updates by un-commenting this line:
```
# AutoUpdate=registry
```
You will also need to enable the [podman auto-updater service](https://docs.podman.io/en/latest/markdown/podman-auto-update.1.html) with:
```shell
# If root:
sudo systemctl enable podman-auto-update.timer podman-auto-update.service
# If non-root:
systemctl --user enable podman-auto-update.timer podman-auto-update.service
```
This works best if you always want the latest version of copyparty. The auto-updater runs once every 24 hours.

View file

@ -0,0 +1,36 @@
[global]
e2dsa # enable file indexing and filesystem scanning
e2ts # and enable multimedia indexing
ansi # and colors in log messages
# uncomment the line starting with q, lo: to log to a file instead of stdout/journalctl;
# $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
/w # share the contents of the "/w" folder
accs:
rw: * # everyone gets read-write access, but
rwmda: ed # the user "ed" gets read-write-move-delete-admin
# uid: 1000 # If you're running as root, you can change the owner of this volume here
# gid: 1000 # If you're running as root, you can change the group of this volume here

View file

@ -0,0 +1,55 @@
[Container]
# It's recommended to replace :latest with a specific version
# for example: docker.io/copyparty/ac:1.19.15
Image=docker.io/copyparty/ac:latest
ContainerName=copyparty
# Uncomment to enable auto-updates
# AutoUpdate=registry
# Environment variables
# enable mimalloc by replacing "NOPE" with "2" for a nice speed-boost (will use twice as much ram)
Environment=LD_PRELOAD=/usr/lib/libmimalloc-secure.so.NOPE
# ensures log-messages are not delayed (but can reduce speed a tiny bit)
Environment=PYTHONUNBUFFERED=1
# Ports
PublishPort=3923:3923
# Volumes (PLEASE LOOK!)
# Rootful setup:
# Leave as-is
# Non-root setup:
# Change /etc/copyparty to /home/<USER>/copyparty/config
Volume=/etc/copyparty:/cfg:z
# Rootful setup:
# Change /mnt to the directory you want to share
# Non-root setup:
# Change /mnt to something owned by your user, e.g., /home/<USER>/copyparty/sharing:/w:z
Volume=/mnt:/w:z
# Give the container time to stop in case the thumbnailer is still running.
# It's allowed to continue finishing up for 10s after the shutdown signal, give it a 5s buffer
StopTimeout=15
# hide it from logs with "/._" so it matches the default --lf-url filter
HealthCmd="wget --spider -q 127.0.0.1:3923/?reset=/._"
HealthInterval=1m
HealthTimeout=2s
HealthRetries=5
HealthStartPeriod=15s
[Unit]
After=default.target
[Install]
# Start by default on boot
WantedBy=default.target
[Service]
# Give the container time to start in case it needs to pull the image
TimeoutStartSec=600

View file

@ -10,7 +10,7 @@ name="copyparty"
rcvar="copyparty_enable"
copyparty_user="copyparty"
copyparty_args="-e2dsa -v /storage:/storage:r" # change as you see fit
copyparty_command="/usr/local/bin/python3.9 /usr/local/copyparty/copyparty-sfx.py ${copyparty_args}"
copyparty_command="/usr/local/bin/python3.11 /usr/local/copyparty/copyparty-sfx.py ${copyparty_args}"
pidfile="/var/run/copyparty/${name}.pid"
command="/usr/sbin/daemon"
command_args="-P ${pidfile} -r -f ${copyparty_command}"

View file

@ -6,7 +6,7 @@
# https://apps.apple.com/us/app/a-shell/id1473805438
#
# step 2: copypaste the following command into a-Shell:
# curl https://github.com/9001/copyparty/raw/refs/heads/hovudstraum/contrib/setup-ashell.sh
# curl -L https://github.com/9001/copyparty/raw/refs/heads/hovudstraum/contrib/setup-ashell.sh | sh
#
# step 3: launch copyparty with this command: cpp
#

View file

@ -55,7 +55,7 @@ except:
zs = """
web/a/partyfuse.py
web/a/u2c.py
web/a/webdav-cfg.bat
web/a/webdav-cfg.txt
web/baguettebox.js
web/browser.css
web/browser.html
@ -86,8 +86,8 @@ web/md2.js
web/mde.css
web/mde.html
web/mde.js
web/msg.css
web/msg.html
web/opds.xml
web/rups.css
web/rups.html
web/rups.js
@ -99,12 +99,37 @@ web/splash.html
web/splash.js
web/svcs.html
web/svcs.js
web/tl/chi.js
web/tl/cze.js
web/tl/deu.js
web/tl/epo.js
web/tl/fin.js
web/tl/fra.js
web/tl/grc.js
web/tl/ita.js
web/tl/kor.js
web/tl/nld.js
web/tl/nno.js
web/tl/nor.js
web/tl/pol.js
web/tl/por.js
web/tl/rus.js
web/tl/spa.js
web/tl/swe.js
web/tl/tur.js
web/tl/ukr.js
web/tl/vie.js
web/ui.css
web/up2k.js
web/util.js
web/w.hash.js
"""
RES = set(zs.strip().split("\n"))
RESM = {
"web/a/partyfuse.txt": "web/a/partyfuse.py",
"web/a/u2c.txt": "web/a/u2c.py",
"web/a/webdav-cfg.bat": "web/a/webdav-cfg.txt",
}
class EnvParams(object):

View file

@ -48,6 +48,7 @@ from .util import (
HAVE_IPV6,
IMPLICATIONS,
JINJA_VER,
MIKO_VER,
MIMES,
PARTFTPY_VER,
PY_DESC,
@ -649,8 +650,11 @@ def get_sects():
if no accounts or volumes are configured,
current folder will be read/write for everyone
the group @acct will always have every user with an account
(the name of that group can be changed with --grp-all)
the group \033[33m@acct\033[0m will always have every user with an account
(the name of that group can be changed with \033[32m--grp-all\033[0m)
to hide a volume from authenticated users, specify \033[33m*,-@acct\033[0m
to subtract \033[33m@acct\033[0m from \033[33m*\033[0m (can subtract users from groups too)
consider the config file for more flexible account/volume management,
including dynamic reload at runtime (and being more readable w)
@ -672,12 +676,12 @@ def get_sects():
send the password in the '\033[36mPW\033[0m' http-header:
\033[36mPW: \033[35mhunter2\033[0m
or if you have \033[33m--accounts\033[0m enabled,
or if you have \033[33m--usernames\033[0m enabled,
\033[36mPW: \033[35med:hunter2\033[0m
send the password in the URL itself:
\033[36mhttp://127.0.0.1:3923/\033[35m?pw=hunter2\033[0m
or if you have \033[33m--accounts\033[0m enabled,
or if you have \033[33m--usernames\033[0m enabled,
\033[36mhttp://127.0.0.1:3923/\033[35m?pw=ed:hunter2\033[0m
use basic-authentication:
@ -806,16 +810,19 @@ def get_sects():
\033[0m
hooks specified as commandline --args are appended to volflags;
each commandline --arg and volflag can be specified multiple times,
each hook will execute in order unless one returns non-zero
each hook will execute in order unless one returns non-zero, or
"100" which means "stop daisychaining and return 0 (success/OK)"
optionally prefix the command with comma-sep. flags similar to -mtp:
\033[36mf\033[35m forks the process, doesn't wait for completion
\033[36mc\033[35m checks return code, blocks the action if non-zero
\033[36mj\033[35m provides json with info as 1st arg instead of filepath
\033[36ms\033[35m provides input data on stdin (instead of 1st arg)
\033[36mwN\033[35m waits N sec after command has been started before continuing
\033[36mtN\033[35m sets an N sec timeout before the command is abandoned
\033[36miN\033[35m xiu only: volume must be idle for N sec (default = 5)
\033[36mI\033[35m import and run as module, not as subprocess
\033[36mar\033[35m only run hook if user has read-access
\033[36marw\033[35m only run hook if user has read-write-access
@ -845,6 +852,9 @@ def get_sects():
the \033[33m--\033[35m stops notify-send from reading the message as args
and the alert will be "hey" followed by the messagetext
\033[36m--xm s,,tee,-a,log.txt\033[35m appends each msg to log.txt;
\033[36m--xm s,j,,tee,-a,log.txt\033[35m writes it as json instead
\033[36m--xau zmq:pub:tcp://*:5556\033[35m announces uploads on zeromq;
\033[36m--xau t3,zmq:push:tcp://*:5557\033[35m also works, and you can
\033[36m--xau t3,j,zmq:req:tcp://localhost:5555\033[35m too for example
@ -854,7 +864,8 @@ def get_sects():
as soon as the volume has been idle for iN seconds (5 by default)
\033[36mxiu\033[0m is also unique in that it will pass the metadata to the
executed program on STDIN instead of as argv arguments, and
executed program on STDIN instead of as argv arguments (so
just like the \033[36ms\033[0m option does for the other hook types), and
it also includes the wark (file-id/hash) as a json property
\033[36mxban\033[0m can be used to overrule / cancel a user ban event;
@ -865,6 +876,12 @@ def get_sects():
on new uploads, but with certain limitations. See
bin/hooks/reloc* and docs/devnotes.md#hook-effects
the \033[36mI\033[0m option will override most other options, because
it entirely hands over control to the hook, which is
then able to tamper with copyparty's internal memory
and wreck havoc if it wants to -- but this is worh it
because it makes the hook 140x faster
except for \033[36mxm\033[0m, only one hook / one action can run at a time,
so it's recommended to use the \033[36mf\033[0m flag unless you really need
to wait for the hook to finish before continuing (without \033[36mf\033[0m
@ -956,7 +973,7 @@ def get_sects():
\033[36m{{vf.thsize}} \033[35mthumbnail size
\033[36m{{srv.itime}} \033[35mserver time in seconds
\033[36m{{srv.htime}} \033[35mserver time as YY-mm-dd, HH:MM:SS (UTC)
\033[36m{{hdr.cf_ipcountry}} \033[35mthe "CF-IPCountry" client header (probably blank)
\033[36m{{hdr.cf-ipcountry}} \033[35mthe "CF-IPCountry" client header (probably blank)
\033[0m
so the following types of placeholders can be added to the lists:
* any client header can be accessed through {{hdr.*}}
@ -1145,7 +1162,6 @@ def add_general(ap, nc, srvname):
ap2 = ap.add_argument_group("general options")
ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="\033[34mREPEATABLE:\033[0m add config file")
ap2.add_argument("-nc", metavar="NUM", type=int, default=nc, help="max num clients")
ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores, 0=all")
ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]")
ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
@ -1155,11 +1171,15 @@ def add_general(ap, nc, srvname):
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("--name-url", metavar="TXT", type=u, help="URL for server name hyperlink (displayed topleft in browser)")
ap2.add_argument("--name-html", type=u, help=argparse.SUPPRESS)
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="\033[34mREPEATABLE:\033[0m map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)")
ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="num cpu-cores for uploads/downloads (0=all); keeping the default is almost always best")
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
ap2.add_argument("--version", action="store_true", help="show versions and exit")
ap2.add_argument("--versionb", action="store_true", help="show version and exit")
def add_qr(ap, tty):
@ -1177,11 +1197,15 @@ def add_qr(ap, tty):
ap2.add_argument("--qr-every", metavar="SEC", type=float, default=0, help="print the qr-code every \033[33mSEC\033[0m (try this with/without --qr-pin in case of issues)")
ap2.add_argument("--qr-winch", metavar="SEC", type=float, default=0, help="when --qr-pin is enabled, check for terminal size change every \033[33mSEC\033[0m")
ap2.add_argument("--qr-file", metavar="TXT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m write qr-code to file.\n └─To create txt or svg, \033[33mTXT\033[0m is Filepath:Zoom:Pad, for example [\033[32mqr.txt:1:2\033[0m]\n └─To create png or gif, \033[33mTXT\033[0m is Filepath:Zoom:Pad:Foreground:Background, for example [\033[32mqr.png:8:2:333333:ffcc55\033[0m], or [\033[32mqr.png:8:2::ffcc55\033[0m] for transparent")
ap2.add_argument("--qr-stdout", action="store_true", help="always display the QR-code on STDOUT in the terminal, even if \033[33m-q\033[0m")
ap2.add_argument("--qr-stderr", action="store_true", help="always display the QR-code on STDERR in the terminal, even if \033[33m-q\033[0m")
def add_fs(ap):
ap2 = ap.add_argument_group("filesystem options")
rm_re_def = "15/0.1" if ANYWIN else "0/0"
ap2.add_argument("--casechk", metavar="N", type=u, default="auto", help="detect and prevent CI (case-insensitive) behavior if the underlying filesystem is CI? [\033[32my\033[0m] = detect and prevent, [\033[32mn\033[0m] = ignore and allow, [\033[32mauto\033[0m] = \033[32my\033[0m if CI fs detected. NOTE: \033[32my\033[0m is very slow but necessary for correct WebDAV behavior on Windows/Macos (volflag=casechk)")
ap2.add_argument("--fsnt", metavar="OS", type=u, default="auto", help="which characters to allow in file/folder names; [\033[32mwin\033[0m] = windows (not <>:|?*\"\\/), [\033[32mmac\033[0m] = macos (not :), [\033[32mlin\033[0m] = linux (anything goes) (volflag=fsnt)")
ap2.add_argument("--rm-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be deleted because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=rm_retry)")
ap2.add_argument("--mv-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be renamed because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=mv_retry)")
ap2.add_argument("--iobuf", metavar="BYTES", type=int, default=256*1024, help="file I/O buffer-size; if your volumes are on a network drive, try increasing to \033[32m524288\033[0m or even \033[32m4194304\033[0m (and let me know if that improves your performance)")
@ -1193,6 +1217,7 @@ def add_share(ap):
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-who", metavar="TXT", type=u, default="auth", help="who can create a share? [\033[32mno\033[0m]=nobody, [\033[32ma\033[0m]=admin-permission, [\033[32mauth\033[0m]=authenticated (volflag=shr_who)")
ap2.add_argument("--shr-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to view/delete any share")
ap2.add_argument("--shr-rt", metavar="MIN", type=int, default=1440, help="shares can be revived by their owner if they expired less than MIN minutes ago; [\033[32m60\033[0m]=hour, [\033[32m1440\033[0m]=day, [\033[32m10080\033[0m]=week")
ap2.add_argument("--shr-v", action="store_true", help="debug")
@ -1207,6 +1232,7 @@ def add_upload(ap):
ap2.add_argument("--bup-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for bup/basic-uploader: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=bup_ck)")
ap2.add_argument("--unpost", metavar="SEC", type=int, default=3600*12, help="grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled, default=12h")
ap2.add_argument("--unp-who", metavar="NUM", type=int, default=1, help="clients can undo recent uploads by using the unpost tab (requires \033[33m-e2d\033[0m). [\033[32m0\033[0m] = never allowed (disable feature), [\033[32m1\033[0m] = allow if client has the same IP as the upload AND is using the same account, [\033[32m2\033[0m] = just check the IP, [\033[32m3\033[0m] = just check account-name (volflag=unp_who)")
ap2.add_argument("--apnd-who", metavar="NUM", type=u, default="dw", help="who can append to existing files? [\033[32mno\033[0m]=nobody, [\033[32maw\033[0m]=admin+write, [\033[32mdw\033[0m]=delete+write, [\033[32mw\033[0m]=write (volflag=apnd_who)")
ap2.add_argument("--u2abort", metavar="NUM", type=int, default=1, help="clients can abort incomplete uploads by using the unpost tab (requires \033[33m-e2d\033[0m). [\033[32m0\033[0m] = never allowed (disable feature), [\033[32m1\033[0m] = allow if client has the same IP as the upload AND is using the same account, [\033[32m2\033[0m] = just check the IP, [\033[32m3\033[0m] = just check account-name (volflag=u2abort)")
ap2.add_argument("--blank-wt", metavar="SEC", type=int, default=300, help="file write grace period (any client can write to a blank file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
ap2.add_argument("--reg-cap", metavar="N", type=int, default=38400, help="max number of uploads to keep in memory when running without \033[33m-e2d\033[0m; roughly 1 MiB RAM per 600")
@ -1216,17 +1242,21 @@ def add_upload(ap):
ap2.add_argument("--chmod-d", metavar="UGO", type=u, default="755", help="unix file permissions to use when creating directories; see --help-chmod. Examples: [\033[32m755\033[0m] = owner-RW + all-R, [\033[32m777\033[0m] = full-yolo (volflag=chmod_d)")
ap2.add_argument("--uid", metavar="N", type=int, default=-1, help="unix user-id to chown new files/folders to; default = -1 = do-not-change (volflag=uid)")
ap2.add_argument("--gid", metavar="N", type=int, default=-1, help="unix group-id to chown new files/folders to; default = -1 = do-not-change (volflag=gid)")
ap2.add_argument("--wram", action="store_true", help="allow uploading even if a volume is inside a ramdisk, meaning that all data will be lost on the next server reboot (volflag=wram)")
ap2.add_argument("--dedup", action="store_true", help="enable symlink-based upload deduplication (volflag=dedup)")
ap2.add_argument("--safe-dedup", metavar="N", type=int, default=50, help="how careful to be when deduplicating files; [\033[32m1\033[0m] = just verify the filesize, [\033[32m50\033[0m] = verify file contents have not been altered (volflag=safededup)")
ap2.add_argument("--hardlink", action="store_true", help="enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) (volflag=hardlink)")
ap2.add_argument("--hardlink-only", action="store_true", help="do not fallback to symlinks when a hardlink cannot be made (volflag=hardlinkonly)")
ap2.add_argument("--reflink", action="store_true", help="enable reflink-based dedup; will fallback on full copies when that is impossible (non-CoW filesystem) (volflag=reflink)")
ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
ap2.add_argument("--no-dupe-m", action="store_true", help="also reject dupes when moving a file into another volume (volflag=nodupem)")
ap2.add_argument("--no-clone", action="store_true", help="do not use existing data on disk to satisfy dupe uploads; reduces server HDD reads in exchange for much more network load (volflag=noclone)")
ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every \033[33mSEC\033[0m seconds; allows resuming incomplete uploads after a server crash")
ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440.0, help="forget unfinished uploads after \033[33mMIN\033[0m minutes; impossible to resume them after that (360=6h, 1440=24h)")
ap2.add_argument("--rm-partial", action="store_true", help="delete the .PARTIAL file when an unfinished upload expires after \033[33m--snap-drop\033[0m (volflag=rm_partial)")
ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)")
ap2.add_argument("--rotf-tz", metavar="TXT", type=u, default="UTC", help="default timezone for the rotf upload rule; examples: [\033[32mEurope/Oslo\033[0m], [\033[32mAmerica/Toronto\033[0m], [\033[32mAntarctica/South_Pole\033[0m] (volflag=rotf_tz)")
ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)")
ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)")
@ -1248,9 +1278,16 @@ def add_network(ap):
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=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("--xf-host", metavar="NAME", type=u, default="x-forwarded-host", help="if reverse-proxied, which http header to read the correct Host value from; this header must contain the server's external domain name")
ap2.add_argument("--xf-proto", metavar="NAME", type=u, default="x-forwarded-proto", help="if reverse-proxied, which http header to read the correct protocol value from; this header must contain either 'http' or 'https'")
ap2.add_argument("--xf-proto-fb", metavar="T", type=u, default="", help="protocol to assume if the X-Forwarded-Proto header (\033[33m--xf-proto\033[0m) is not provided by the reverseproxy; either 'http' or 'https'")
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("--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]\n └─for performance and security, this only looks at the TCP/Network-level IP, and will NOT work behind a reverseproxy")
ap2.add_argument("--ipar", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated).\n └─this is reverseproxy-compatible; reads client-IP from 'X-Forwarded-For' if possible, with TCP/Network IP as fallback")
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]")
ap2.add_argument("--cachectl", metavar="TXT", default="no-cache", help="default-value of the 'Cache-Control' response-header (controls caching in webbrowsers). Default prevents repeated downloading of the same file unless necessary (browser will ask copyparty if the file has changed). Examples: [\033[32mmax-age=604869\033[0m] will cache for 7 days, [\033[32mno-store, max-age=0\033[0m] will always redownload. (volflag=cachectl)")
ap2.add_argument("--http-vary", metavar="TXT", type=u, default="Origin, PW, Cookie", help="value of the 'Vary' response-header; a hint for caching proxies")
ap2.add_argument("--http-no-tcp", action="store_true", help="do not listen on TCP/IP for http/https; only listen on unix-domain-sockets")
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")
elif not MACOS:
@ -1305,6 +1342,7 @@ def add_auth(ap):
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")
ap2.add_argument("--idp-gsep", metavar="RE", type=u, default="|:;+,", help="if there are multiple groups in \033[33m--idp-h-grp\033[0m, they are separated by one of the characters in \033[33mRE\033[0m")
ap2.add_argument("--idp-chsub", metavar="TXT", type=u, default="", help="characters to replace in usernames/groupnames; a list of pairs of characters separated by | so for example | _| will replace spaces with _ to make configuration easier, or |%%_|^_|@_| will replace %%/^/@ with _")
ap2.add_argument("--idp-db", metavar="PATH", type=u, default=idp_db, help="where to store the known IdP users/groups (if you run multiple copyparty instances, make sure they use different DBs)")
ap2.add_argument("--idp-store", metavar="N", type=int, default=1, help="how to use \033[33m--idp-db\033[0m; [\033[32m0\033[0m] = entirely disable, [\033[32m1\033[0m] = write-only (effectively disabled), [\033[32m2\033[0m] = remember users, [\033[32m3\033[0m] = remember users and groups.\nNOTE: Will remember and restore the IdP-volumes of all users for all eternity if set to 2 or 3, even when user is deleted from your IdP")
ap2.add_argument("--idp-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to use /?idp (the cache management UI)")
@ -1313,6 +1351,8 @@ def add_auth(ap):
ap2.add_argument("--idp-login-t", metavar="T", type=u, default="Login with SSO", help="the label/text for the idp-login button")
ap2.add_argument("--idp-logout", metavar="L", type=u, default="", help="replace all logout-buttons with a link to URL \033[33mL\033[0m")
ap2.add_argument("--auth-ord", metavar="TXT", type=u, default="idp,ipu", help="controls auth precedence; examples: [\033[32mpw,idp,ipu\033[0m], [\033[32mipu,pw,idp\033[0m], see --help-auth-ord")
ap2.add_argument("--pw-hdr", metavar="NAME", type=u, default="pw", help="lowercase name of password-header (NAME: foo); \033[1;31mWARNING:\033[0m Changing this will break support for many clients")
ap2.add_argument("--pw-urlp", metavar="NAME", type=u, default="pw", help="lowercase name of password url-param (?NAME=foo); \033[1;31mWARNING:\033[0m Changing this will break support for many clients")
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
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)")
@ -1358,6 +1398,8 @@ def add_zc_mdns(ap):
ap2.add_argument("--zm6", action="store_true", help="IPv6 only")
ap2.add_argument("--zmv", action="store_true", help="verbose mdns")
ap2.add_argument("--zmvv", action="store_true", help="verboser mdns")
ap2.add_argument("--zm-http", metavar="PORT", type=int, default=-1, help="port to announce for http/webdav; [\033[32m-1\033[0m] = auto, [\033[32m0\033[0m] = disabled, [\033[32m4649\033[0m] = port 4649")
ap2.add_argument("--zm-https", metavar="PORT", type=int, default=-1, help="port to announce for https/webdavs; [\033[32m-1\033[0m] = auto, [\033[32m0\033[0m] = disabled, [\033[32m4649\033[0m] = port 4649")
ap2.add_argument("--zm-no-pe", action="store_true", help="mute parser errors (invalid incoming MDNS packets)")
ap2.add_argument("--zm-nwa-1", action="store_true", help="disable workaround for avahi-bug #379 (corruption in Avahi's mDNS reflection feature)")
ap2.add_argument("--zms", metavar="dhf", type=u, default="", help="list of services to announce -- d=webdav h=http f=ftp s=smb -- lowercase=plaintext uppercase=TLS -- default: all enabled services except http/https (\033[32mDdfs\033[0m if \033[33m--ftp\033[0m and \033[33m--smb\033[0m is set, \033[32mDd\033[0m otherwise)")
@ -1382,13 +1424,28 @@ def add_zc_ssdp(ap):
ap2.add_argument("--zsid", metavar="UUID", type=u, default=zsid, help="USN (device identifier) to announce")
def add_sftp(ap):
ap2 = ap.add_argument_group("SFTP options")
ap2.add_argument("--sftp", metavar="PORT", type=int, default=0, help="enable SFTP server on \033[33mPORT\033[0m, for example \033[32m3922")
ap2.add_argument("--sftpv", action="store_true", help="verbose")
ap2.add_argument("--sftpvv", action="store_true", help="verboser")
ap2.add_argument("--sftp4", action="store_true", help="only listen on IPv4")
ap2.add_argument("--sftp-key", metavar="U K", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add ssh-key \033[33mK\033[0m for user \033[33mU\033[0m (username, space, key-type, space, base64); if user has multiple keys, then repeat this option for each key\n └─commandline example: --sftp-key 'david ssh-ed25519 AAAAC3NzaC...'\n └─config-file example: sftp-key: david ssh-ed25519 AAAAC3NzaC...")
ap2.add_argument("--sftp-key2u", action="append", help=argparse.SUPPRESS)
ap2.add_argument("--sftp-pw", action="store_true", help="allow password-authentication with sftp (not just ssh-keys)")
ap2.add_argument("--sftp-anon", metavar="TXT", type=u, default="", help="allow anonymous/unauthenticated connections with \033[33mTXT\033[0m as username")
ap2.add_argument("--sftp-hostk", metavar="FP", type=u, default=E.cfg, help="path to folder with hostkeys, for example 'ssh_host_rsa_key'; missing keys will be generated")
ap2.add_argument("--sftp-banner", metavar="T", type=u, default="", help="bannertext to send when someone connects; can be @filepath")
ap2.add_argument("--sftp-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 / \033[33m--ipar\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
def add_ftp(ap):
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 (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-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 / \033[33m--ipar\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")
@ -1402,7 +1459,10 @@ def add_webdav(ap):
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)")
ap2.add_argument("--dav-rt", action="store_true", help="show symlink-destination's lastmodified instead of the link itself; always enabled for recursive listings (volflag=davrt)")
ap2.add_argument("--dav-auth", action="store_true", help="force auth for all folders (required by davfs2 when only some folders are world-readable) (volflag=davauth)")
ap2.add_argument("--dav-ua1", metavar="PTN", type=u, default=r" kioworker/", help="regex of tricky user-agents which expect 401 from GET requests; disable with [\033[32mno\033[0m] or blank")
ap2.add_argument("--dav-ua1", metavar="PTN", type=u, default=r" kioworker/", help="regex of user-agents which ARE webdav-clients, and expect 401 from GET requests; disable with [\033[32mno\033[0m] or blank")
ap2.add_argument("--dav-port", metavar="P", type=int, default=0, help="additional port to listen on for misbehaving webdav clients which pretend they are graphical browsers; an alternative/supplement to dav-ua1")
ap2.add_argument("--ua-nodav", metavar="PTN", type=u, default=r"^(Mozilla/|NetworkingExtension/|com\.apple\.WebKit)", help="regex of user-agents which are NOT webdav-clients")
ap2.add_argument("--p-nodav", metavar="P,P", type=u, default="", help="server-ports (comma-sep.) which are NOT webdav-clients; an alternative/supplement to ua-nodav")
def add_tftp(ap):
@ -1414,7 +1474,7 @@ 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 (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-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 / \033[33m--ipar\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")
@ -1431,6 +1491,10 @@ def add_smb(ap):
ap2.add_argument("--smbvv", action="store_true", help="verboser")
ap2.add_argument("--smbvvv", action="store_true", help="verbosest")
def add_opds(ap):
ap2 = ap.add_argument_group("OPDS options")
ap2.add_argument("--opds", action="store_true", help="enable opds -- allows e-book readers to browse and download files (volflag=opds)")
ap2.add_argument("--opds-exts", metavar="T,T", type=u, default="epub,cbz,pdf", help="file formats to list in OPDS feeds; leave empty to show everything (volflag=opds_exts)")
def add_handlers(ap):
ap2 = ap.add_argument_group("handlers (see --help-handlers)")
@ -1458,6 +1522,7 @@ def add_hooks(ap):
def add_stats(ap):
ap2 = ap.add_argument_group("grafana/prometheus metrics endpoint")
ap2.add_argument("--stats", action="store_true", help="enable openmetrics at /.cpr/metrics for admin accounts")
ap2.add_argument("--stats-u", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to access /.cpr/metrics even if they aren't admin")
ap2.add_argument("--nos-hdd", action="store_true", help="disable disk-space metrics (used/free space)")
ap2.add_argument("--nos-vol", action="store_true", help="disable volume size metrics (num files, total bytes, vmaxb/vmaxn)")
ap2.add_argument("--nos-vst", action="store_true", help="disable volume state metrics (indexing, analyzing, activity)")
@ -1500,12 +1565,13 @@ def add_optouts(ap):
ap2.add_argument("--no-pipe", action="store_true", help="disable race-the-beam (lockstep download of files which are currently being uploaded) (volflag=nopipe)")
ap2.add_argument("--no-tail", action="store_true", help="disable streaming a growing files with ?tail (volflag=notail)")
ap2.add_argument("--no-db-ip", action="store_true", help="do not write uploader-IP into the database; will also disable unpost, you may want \033[32m--forget-ip\033[0m instead (volflag=no_db_ip)")
ap2.add_argument("--no-zls", action="store_true", help="disable browsing the contents of zip/cbz files, does not affect thumbnails")
def add_safety(ap):
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 requires login, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --dav-auth --vague-403 -nih")
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav requires login, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --reflink --dav-auth --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")
ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, default="", help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m (see \033[33m--help-ls\033[0m); example [\033[32m**,*,ln,p,r\033[0m]")
ap2.add_argument("--xvol", action="store_true", help="never follow symlinks leaving the volume root, unless the link is into another volume where the user has similar access (volflag=xvol)")
@ -1514,10 +1580,12 @@ def add_safety(ap):
ap2.add_argument("--no-dot-ren", action="store_true", help="disallow renaming dotfiles; makes it impossible to turn something into a dotfile")
ap2.add_argument("--no-logues", action="store_true", help="disable rendering .prologue/.epilogue.html into directory listings")
ap2.add_argument("--no-readme", action="store_true", help="disable rendering readme/preadme.md into directory listings")
ap2.add_argument("--vague-403", action="store_true", help="send 404 instead of 403 (security through ambiguity, very enterprise)")
ap2.add_argument("--vague-403", action="store_true", help="send 404 instead of 403 (security through ambiguity, very enterprise). \033[1;31mWARNING:\033[0m Not compatible with WebDAV")
ap2.add_argument("--force-js", action="store_true", help="don't send folder listings as HTML, force clients to use the embedded json instead -- slight protection against misbehaving search engines which ignore \033[33m--no-robots\033[0m")
ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
ap2.add_argument("--dont-ban", metavar="TXT", type=u, default="no", help="anyone at this accesslevel or above will not get banned: [\033[32mav\033[0m]=admin-in-volume, [\033[32maa\033[0m]=has-admin-anywhere, [\033[32mrw\033[0m]=read-write, [\033[32mauth\033[0m]=authenticated, [\033[32many\033[0m]=disable-all-bans, [\033[32mno\033[0m]=anyone-can-get-banned")
ap2.add_argument("--banmsg", metavar="TXT", type=u, default="thank you for playing \u00a0 (see serverlog and readme)", help="the response to send to banned users; can be @ban.html to send the contents of ban.html")
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
ap2.add_argument("--ban-pwc", metavar="N,W,B", type=u, default="5,60,1440", help="more than \033[33mN\033[0m password-changes in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
@ -1525,7 +1593,7 @@ def add_safety(ap):
ap2.add_argument("--ban-422", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 422's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (invalid requests, attempted exploits ++)")
ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; applies only to permissions g/G/h (decent replacement for \033[33m--ban-404\033[0m if that can't be used)")
ap2.add_argument("--sus-urls", metavar="R", type=u, default=r"\.php$|(^|/)wp-(admin|content|includes)/", help="URLs which are considered sus / eligible for banning; disable with blank or [\033[32mno\033[0m]")
ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon\.ico|robots\.txt)$|^apple-touch-icon|^\.well-known", help="harmless URLs ignored from 404-bans; disable with blank or [\033[32mno\033[0m]")
ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon\..{3}|robots\.txt)$|^apple-touch-icon|^\.well-known", help="harmless URLs ignored from 403/404-bans; disable with blank or [\033[32mno\033[0m]")
ap2.add_argument("--early-ban", action="store_true", help="if a client is banned, reject its connection as soon as possible; not a good idea to enable when proxied behind cloudflare since it could ban your reverse-proxy")
ap2.add_argument("--cookie-nmax", metavar="N", type=int, default=50, help="reject HTTP-request from client if they send more than N cookies")
ap2.add_argument("--cookie-cmax", metavar="N", type=int, default=8192, help="reject HTTP-request from client if more than N characters in Cookie header")
@ -1566,6 +1634,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-date", metavar="TXT", type=u, default="", help="date-format, for example [\033[32m%%Y-%%m-%%d\033[0m] (default is disabled; no date, just HH:MM:SS)")
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-badxml", action="store_true", help="log any invalid XML received from a client")
ap2.add_argument("--log-conn", action="store_true", help="debug: print tcp-server msgs")
@ -1573,18 +1642,23 @@ def add_logging(ap):
ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
ap2.add_argument("--ohead", metavar="HEADER", type=u, action='append', help="print response \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
ap2.add_argument("--lf-url", metavar="RE", type=u, default=r"^/\.cpr/|[?&]th=[wjp]|/\.(_|ql_|DS_Store$|localized$)", help="dont log URLs matching regex \033[33mRE\033[0m")
ap2.add_argument("--scan-st-r", metavar="SEC", type=float, default=0.1, help="fs-indexing: wait \033[33mSEC\033[0m between each status-message")
ap2.add_argument("--scan-pr-r", metavar="SEC", type=float, default=10, help="fs-indexing: wait \033[33mSEC\033[0m between each 'progress:' message")
ap2.add_argument("--scan-pr-s", metavar="MiB", type=float, default=1, help="fs-indexing: say 'file: <name>' when a file larger than \033[33mMiB\033[0m is about to be hashed")
def add_admin(ap):
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)")
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks); same as --stack-who=no")
ap2.add_argument("--no-ups-page", action="store_true", help="disable ?ru (list of recent uploads)")
ap2.add_argument("--no-up-list", action="store_true", help="don't show list of incoming files in controlpanel")
ap2.add_argument("--dl-list", metavar="LVL", type=int, default=2, help="who can see active downloads in the controlpanel? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone")
ap2.add_argument("--ups-who", metavar="LVL", type=int, default=2, help="who can see recent uploads on the ?ru page? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone (volflag=ups_who)")
ap2.add_argument("--ups-when", action="store_true", help="let everyone see upload timestamps on the ?ru page, not just admins")
ap2.add_argument("--stack-who", metavar="LVL", type=u, default="a", help="who can see the ?stack page (list of threads)? [\033[32mno\033[0m]=nobody, [\033[32ma\033[0m]=admins, [\033[32mrw\033[0m]=read+write, [\033[32mall\033[0m]=everyone")
ap2.add_argument("--stack-v", action="store_true", help="verbose ?stack")
def add_thumbnail(ap):
@ -1601,6 +1675,7 @@ def add_thumbnail(ap):
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=th_ram, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32my\033[0m]=crop, [\033[32mn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32my\033[0m]=yes, [\033[32mn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
ap2.add_argument("--th-qv", metavar="N", type=int, default=40, help="thumbnail quality (10~90); higher is larger filesize and better quality (volflag=th_qv)")
ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,raw,ff", help="image decoders, in order of preference")
ap2.add_argument("--th-no-jpg", action="store_true", help="disable jpg output")
ap2.add_argument("--th-no-webp", action="store_true", help="disable webp output")
@ -1653,7 +1728,9 @@ def add_rss(ap):
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")
ap2.add_argument("--rss-sort", metavar="ORD", type=u, default="m", help="default sort order (url-param 'sort'); [\033[32mm\033[0m]=last-modified [\033[32mu\033[0m]=upload-time [\033[32mn\033[0m]=filename [\033[32ms\033[0m]=filesize; Uppercase=oldest-first. Note that upload-time is 0 for non-uploaded files")
ap2.add_argument("--rss-sort", metavar="ORD", type=u, default="m", help="default sort order (url-param 'sort'); [\033[32mm\033[0m]=last-modified [\033[32mu\033[0m]=upload-time [\033[32mn\033[0m]=filename [\033[32ms\033[0m]=filesize; Uppercase=oldest-first. Note that upload-time is 0 for non-uploaded files (volflag=rss_sort)")
ap2.add_argument("--rss-fmt-t", metavar="TXT", type=u, default="{fname}", help="title format (url-param 'rss_fmt_t') (volflag=rss_fmt_t)")
ap2.add_argument("--rss-fmt-d", metavar="TXT", type=u, default="{artist} - {title}", help="description format (url-param 'rss_fmt_d') (volflag=rss_fmt_d)")
def add_db_general(ap, hcores):
@ -1680,6 +1757,7 @@ def add_db_general(ap, hcores):
ap2.add_argument("--hash-mt", metavar="CORES", type=int, default=hcores, help="num cpu cores to use for file hashing; set 0 or 1 for single-core hashing")
ap2.add_argument("--re-maxage", metavar="SEC", type=int, default=0, help="rescan filesystem for changes every \033[33mSEC\033[0m seconds; 0=off (volflag=scan)")
ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
ap2.add_argument("--srch-icase", action="store_true", help="case-insensitive search for all unicode characters (the default is icase for just ascii). NOTE: will make searches much slower (around 4x), and NOTE: only applies to filenames/paths, not tags")
ap2.add_argument("--srch-time", metavar="SEC", type=int, default=45, help="search deadline -- terminate searches running for more than \033[33mSEC\033[0m seconds")
ap2.add_argument("--srch-hits", metavar="N", type=int, default=7999, help="max search results to allow clients to fetch; 125 results will be shown initially")
ap2.add_argument("--srch-excl", metavar="PTN", type=u, default="", help="regex: exclude files from search results if the file-URL matches \033[33mPTN\033[0m (case-sensitive). Example: [\033[32mpassword|logs/[0-9]\033[0m] any URL containing 'password' or 'logs/DIGIT' (volflag=srch_excl)")
@ -1734,12 +1812,13 @@ def add_og(ap):
ap2.add_argument("--uqe", action="store_true", help="query-string parceling; translate a request for \033[33m/foo/.uqe/BASE64\033[0m into \033[33m/foo?TEXT\033[0m, or \033[33m/foo/?TEXT\033[0m if the first character in \033[33mTEXT\033[0m is a slash. Automatically enabled for \033[33m--og\033[0m")
def add_ui(ap, retry):
def add_ui(ap, retry: int):
THEMES = 10
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")
ap2.add_argument("--ui-filesz", metavar="FMT", type=u, default="1", help="default filesize format; one of these: 0, 1, 2, 2c, 3, 3c, 4, 4c, 5, 5c, fuzzy (see UI)")
ap2.add_argument("--lang", metavar="LANG", type=u, default="eng", help="language, for example \033[32meng\033[0m / \033[32mnor\033[0m / ...")
ap2.add_argument("--theme", metavar="NUM", type=int, default=0, help="default theme to use (0..%d)" % (THEMES - 1,))
ap2.add_argument("--themes", metavar="NUM", type=int, default=THEMES, help="number of themes installed")
@ -1749,18 +1828,26 @@ def add_ui(ap, retry):
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
ap2.add_argument("--see-dots", action="store_true", help="default-enable seeing dotfiles; only takes effect if user has the necessary permissions")
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("--dlni", action="store_true", help="force download (don't show inline) when files are clicked (volflag:dlni)")
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("--ufavico", metavar="TXT", type=u, default="", help="URL to .ico/png/gif/svg file; \033[33m--favico\033[0m takes precedence unless disabled (volflag=ufavico)")
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="\033[34mREPEATABLE:\033[0m use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
ap2.add_argument("--mpmc", type=u, default="", help=argparse.SUPPRESS)
ap2.add_argument("--notooltips", action="store_true", help="tooltips disabled as default")
ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]")
ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html")
ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html")
ap2.add_argument("--js-other", metavar="L", type=u, default="", help="URL to additional JS to include in all other pages")
ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)")
ap2.add_argument("--html-head-s", metavar="T", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); similar to (and can be combined with) --html-head but only accepts static text (volflag=html_head_s)")
ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI, or add ?v to URL for override)")
ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")
ap2.add_argument("--prologues", metavar="T,T", type=u, default=".prologue.html", help="comma-sep. list of filenames to scan for and use as prologues (embed above/before directory listing) (volflag=prologues)")
ap2.add_argument("--epilogues", metavar="T,T", type=u, default=".epilogue.html", help="comma-sep. list of filenames to scan for and use as epilogues (embed below/after directory listing) (volflag=epilogues)")
ap2.add_argument("--preadmes", metavar="T,T", type=u, default="preadme.md,PREADME.md", help="comma-sep. list of filenames to scan for and use as preadmes (embed above/before directory listing) (volflag=preadmes)")
ap2.add_argument("--readmes", metavar="T,T", type=u, default="readme.md,README.md", help="comma-sep. list of filenames to scan for and use as readmes (embed below/after directory listing) (volflag=readmes)")
ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
ap2.add_argument("--bname", metavar="TXT", type=u, default="--name", help="server name (displayed in filebrowser document title)")
ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-nb\033[0m")
@ -1778,6 +1865,15 @@ def add_ui(ap, retry):
ap2.add_argument("--lg-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for prologue/epilogue docs (volflag=lg_sba); see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#iframes")
ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
ap2.add_argument("--no-sb-lg", action="store_true", help="don't sandbox prologue/epilogue docs (volflags: no_sb_lg | sb_lg); enables non-js support")
ap2.add_argument("--ui-nombar", action="store_true", help="hide top-menu in the UI (volflag=ui_nombar)")
ap2.add_argument("--ui-noacci", action="store_true", help="hide account-info in the UI (volflag=ui_noacci)")
ap2.add_argument("--ui-nosrvi", action="store_true", help="hide server-info in the UI (volflag=ui_nosrvi)")
ap2.add_argument("--ui-nonav", action="store_true", help="hide navpane+breadcrumbs (volflag=ui_nonav)")
ap2.add_argument("--ui-notree", action="store_true", help="hide navpane in the UI (volflag=ui_notree)")
ap2.add_argument("--ui-nocpla", action="store_true", help="hide cpanel-link in the UI (volflag=ui_nocpla)")
ap2.add_argument("--ui-nolbar", action="store_true", help="hide link-bar in the UI (volflag=ui_nolbar)")
ap2.add_argument("--ui-noctxb", action="store_true", help="hide context-buttons in the UI (volflag=ui_noctxb)")
ap2.add_argument("--ui-norepl", action="store_true", help="hide repl-button in the UI (volflag=ui_norepl)")
ap2.add_argument("--have-unlistc", action="store_true", help=argparse.SUPPRESS)
@ -1809,7 +1905,7 @@ def add_debug(ap):
def run_argparse(
argv: list[str], formatter: Any, retry: bool, nc: int, verbose=True
argv: list[str], formatter: Any, retry: int, nc: int, verbose=True
) -> argparse.Namespace:
ap = argparse.ArgumentParser(
formatter_class=formatter,
@ -1851,10 +1947,12 @@ def run_argparse(
add_thumbnail(ap)
add_transcoding(ap)
add_rss(ap)
add_sftp(ap)
add_ftp(ap)
add_webdav(ap)
add_tftp(ap)
add_smb(ap)
add_opds(ap)
add_safety(ap)
add_salt(ap, fk_salt, dk_salt, ah_salt)
add_optouts(ap)
@ -1876,18 +1974,21 @@ def run_argparse(
for k, h, _ in sects:
ap2.add_argument("--help-" + k, action="store_true", help=h)
try:
if not retry:
raise Exception()
if retry:
a = ["ascii", "replace"]
for x in ap._actions:
if not x.help:
continue
try:
x.default = x.default.encode(*a).decode(*a)
except:
pass
a = ["ascii", "replace"]
x.help = x.help.encode(*a).decode(*a) + "\033[0m"
except:
pass
try:
if x.help and x.help is not argparse.SUPPRESS:
x.help = x.help.replace("└─", "`-").encode(*a).decode(*a)
if retry > 2:
x.help = RE_ANSI.sub("", x.help)
except:
pass
ret = ap.parse_args(args=argv[1:])
for k, h, t in sects:
@ -1901,16 +2002,20 @@ def run_argparse(
def main(argv: Optional[list[str]] = None) -> None:
if argv is None:
argv = sys.argv
if "--versionb" in argv:
print(S_VERSION)
sys.exit(0)
time.strptime("19970815", "%Y%m%d") # python#7980
if WINDOWS:
os.system("rem") # enables colors
init_E(E)
if argv is None:
argv = sys.argv
f = '\033[36mcopyparty v{} "\033[35m{}\033[36m" ({})\n{}\033[0;36m\n sqlite {} | jinja {} | pyftpd {} | tftp {}\n\033[0m'
f = '\033[36mcopyparty v{} "\033[35m{}\033[36m" ({})\n{}\033[0;36m\n sqlite {} | jinja {} | pyftpd {} | tftp {} | miko {}\n\033[0m'
f = f.format(
S_VERSION,
CODENAME,
@ -1920,6 +2025,7 @@ def main(argv: Optional[list[str]] = None) -> None:
JINJA_VER,
PYFTPD_VER,
PARTFTPY_VER,
MIKO_VER,
)
lprint(f)
@ -1997,7 +2103,7 @@ def main(argv: Optional[list[str]] = None) -> None:
except:
nc = 486 # mdns/ssdp restart headroom; select() maxfd is 512 on windows
retry = False
retry = 0
for fmtr in [RiceFormatter, RiceFormatter, Dodge11874, BasicDodge11874]:
try:
al = run_argparse(argv, fmtr, retry, nc)
@ -2006,8 +2112,9 @@ def main(argv: Optional[list[str]] = None) -> None:
except SystemExit:
raise
except:
retry = True
lprint("\n[ {} ]:\n{}\n".format(fmtr, min_ex()))
retry += 1
t = "WARNING: due to limitations in your terminal and/or OS, the helptext cannot be displayed correctly. Will show a simplified version due to the following error:\n[ %s ]:\n%s\n"
lprint(t % (fmtr, min_ex()))
try:
assert al # type: ignore
@ -2035,7 +2142,7 @@ def main(argv: Optional[list[str]] = None) -> None:
# propagate implications
for k1, k2 in IMPLICATIONS:
if getattr(al, k1):
if getattr(al, k1, None):
setattr(al, k2, True)
# propagate unplications

View file

@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (1, 19, 7)
CODENAME = "usernames"
BUILD_DT = (2025, 8, 28)
VERSION = (1, 20, 0)
CODENAME = "sftp is fine too"
BUILD_DT = (2026, 1, 2)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View file

@ -13,7 +13,7 @@ import threading
import time
from datetime import datetime
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, WINDOWS, E
from .__init__ import ANYWIN, MACOS, PY2, TYPE_CHECKING, WINDOWS, E
from .bos import bos
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
from .pwhash import PWHash
@ -21,8 +21,10 @@ from .util import (
DEF_MTE,
DEF_MTH,
EXTS,
FAVICON_MIMES,
HAVE_SQLITE3,
IMPLICATIONS,
META_NOBOTS,
MIMES,
SQLITE_VER,
UNPLICATIONS,
@ -91,6 +93,13 @@ LEELOO_DALLAS = "leeloo_dallas"
## thanks for coming to my ted talk
UP_MTE_MAP = { # db-order
"w": "substr(w,1,16)",
"up_ip": "ip",
".up_at": "at",
"up_by": "un",
}
SEE_LOG = "see log for details"
SEESLOG = " (see serverlog for details)"
SSEELOG = " ({})".format(SEE_LOG)
@ -99,6 +108,8 @@ SBADCFG = " ({})".format(BAD_CFG)
PTN_U_GRP = re.compile(r"\$\{u(%[+-][^}]+)\}")
PTN_G_GRP = re.compile(r"\$\{g(%[+-][^}]+)\}")
PTN_U_ANY = re.compile(r"(\${[u][}%])")
PTN_G_ANY = re.compile(r"(\${[g][}%])")
PTN_SIGIL = re.compile(r"(\${[ug][}%])")
@ -156,6 +167,9 @@ class Lim(object):
self.vbmax = 0 # volume bytes max
self.vnmax = 0 # volume max num files
self.c_vb_v = 0 # cache: volume bytes used (value)
self.c_vb_r = 0 # cache: volume bytes used (ref)
self.smin = 0 # filesize min
self.smax = 0 # filesize max
@ -167,14 +181,19 @@ class Lim(object):
self.rotn = 0 # rot num files
self.rotl = 0 # rot depth
self.rotf = "" # rot datefmt
self.rotf_tz = UTC # rot timezone
self.rot_re = re.compile("") # rotf check
def log(self, msg: str, c: Union[int, str] = 0) -> None:
if self.log_func:
self.log_func("up-lim", msg, c)
def set_rotf(self, fmt: str) -> None:
def set_rotf(self, fmt: str, tz: str) -> None:
self.rotf = fmt
if tz != "UTC":
from zoneinfo import ZoneInfo
self.rotf_tz = ZoneInfo(tz)
r = re.escape(fmt).replace("%Y", "[0-9]{4}").replace("%j", "[0-9]{3}")
r = re.sub("%[mdHMSWU]", "[0-9]{2}", r)
self.rot_re = re.compile("(^|/)" + r + "$")
@ -278,7 +297,7 @@ class Lim(object):
if self.rot_re.search(path.replace("\\", "/")):
return path, ""
suf = datetime.now(UTC).strftime(self.rotf)
suf = datetime.now(self.rotf_tz).strftime(self.rotf)
if path:
path += "/"
@ -389,6 +408,9 @@ class VFS(object):
self.vpath = vpath # absolute path in the virtual filesystem
self.vpath0 = vpath0 # original vpath (before idp expansion)
self.axs = axs
self.uaxs: dict[
str, tuple[bool, bool, bool, bool, bool, bool, bool, bool, bool]
] = {}
self.flags = flags # config options
self.root = self
self.dev = 0 # st_dev
@ -414,6 +436,7 @@ class VFS(object):
self.js_htm = ""
self.all_vols: dict[str, VFS] = {} # flattened recursive
self.all_nodes: dict[str, VFS] = {} # also jumpvols/shares
self.all_fvols: dict[str, VFS] = {} # volumes which are files
if realpath:
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
@ -424,10 +447,14 @@ class VFS(object):
self.all_nodes[vpath] = self
self.all_aps = [(rp, [self])]
self.all_vps = [(vp, self)]
self.canonical = self._canonical
self.dcanonical = self._dcanonical
else:
self.histpath = self.dbpath = ""
self.all_aps = []
self.all_vps = []
self.canonical = self._canonical_null
self.dcanonical = self._dcanonical_null
self.get_dbv = self._get_dbv
self.ls = self._ls
@ -542,29 +569,19 @@ class VFS(object):
def can_access(
self, vpath: str, uname: str
) -> tuple[bool, bool, bool, bool, bool, bool, bool, bool]:
"""can Read,Write,Move,Delete,Get,Upget,Admin,Dot"""
) -> tuple[bool, bool, bool, bool, bool, bool, bool, bool, bool]:
"""can Read,Write,Move,Delete,Get,Upget,Html,Admin,Dot"""
# NOTE: only used by get_perms, which is only used by hooks; the lowest of fruits
if vpath:
vn, _ = self._find(undot(vpath))
else:
vn = self
c = vn.axs
return (
uname in c.uread,
uname in c.uwrite,
uname in c.umove,
uname in c.udel,
uname in c.uget,
uname in c.upget,
uname in c.uadmin,
uname in c.udot,
)
# skip uhtml because it's rarely needed
return vn.uaxs[uname]
def get_perms(self, vpath: str, uname: str) -> str:
zbl = self.can_access(vpath, uname)
ret = "".join(ch for ch, ok in zip("rwmdgGa.", zbl) if ok)
ret = "".join(ch for ch, ok in zip("rwmdgGha.", zbl) if ok)
if "rwmd" in ret and "a." in ret:
ret += "A"
return ret
@ -624,7 +641,39 @@ class VFS(object):
vrem = vjoin(self.vpath[len(dbv.vpath) :].lstrip("/"), vrem)
return dbv, vrem
def canonical(self, rem: str, resolve: bool = True) -> str:
def casechk(self, rem: str, do_stat: bool) -> bool:
ap = self.canonical(rem, False)
if do_stat and not bos.path.exists(ap):
return True # doesn't exist at all; good to go
dp, fn = os.path.split(ap)
if not fn:
return True # filesystem root
try:
fns = os.listdir(dp)
except:
return True # maybe chmod 111; assume ok
if fn in fns:
return True
hit = "<?>"
lfn = fn.lower()
for zs in fns:
if lfn == zs.lower():
hit = zs
break
if not hit:
return True # NFC/NFD or something, can't be helped either way
if self.log:
t = "returning 404 due to underlying case-insensitive filesystem:\n http-req: %r\n local-fs: %r"
self.log("vfs", t % (fn, hit))
return False
def _canonical_null(self, rem: str, resolve: bool = True) -> str:
return ""
def _dcanonical_null(self, rem: str) -> str:
return ""
def _canonical(self, rem: str, resolve: bool = True) -> str:
"""returns the canonical path (fully-resolved absolute fs path)"""
ap = self.realpath
if rem:
@ -632,7 +681,7 @@ class VFS(object):
return absreal(ap) if resolve else ap
def dcanonical(self, rem: str) -> str:
def _dcanonical(self, rem: str) -> str:
"""resolves until the final component (filename)"""
ap = self.realpath
if rem:
@ -641,6 +690,44 @@ class VFS(object):
ad, fn = os.path.split(ap)
return os.path.join(absreal(ad), fn)
def _canonical_shr(self, rem: str, resolve: bool = True) -> str:
"""returns the canonical path (fully-resolved absolute fs path)"""
ap = self.realpath
if rem:
ap += "/" + rem
rap = absreal(ap)
if self.shr_files:
assert self.shr_src # !rm
vn, rem = self.shr_src
chk = absreal(os.path.join(vn.realpath, rem))
if chk != rap:
# not the dir itself; assert file allowed
ad, fn = os.path.split(rap)
if chk != ad or fn not in self.shr_files:
return "\n\n"
return rap if resolve else ap
def _dcanonical_shr(self, rem: str) -> str:
"""resolves until the final component (filename)"""
ap = self.realpath
if rem:
ap += "/" + rem
ad, fn = os.path.split(ap)
ad = absreal(ad)
if self.shr_files:
assert self.shr_src # !rm
vn, rem = self.shr_src
chk = absreal(os.path.join(vn.realpath, rem))
if chk != absreal(ap):
# not the dir itself; assert file allowed
if ad != chk or fn not in self.shr_files:
return "\n\n"
return os.path.join(ad, fn)
def _ls_nope(
self, *a, **ka
) -> tuple[str, list[tuple[str, os.stat_result]], dict[str, "VFS"]]:
@ -673,8 +760,12 @@ class VFS(object):
"""return user-readable [fsdir,real,virt] items at vpath"""
virt_vis = {} # nodes readable by user
abspath = self.canonical(rem)
real = list(statdir(self.log, scandir, lstat, abspath, throw))
real.sort()
if abspath:
real = list(statdir(self.log, scandir, lstat, abspath, throw))
real.sort()
else:
real = []
if not rem:
# no vfs nodes in the list of real inodes
real = [x for x in real if x[0] not in self.nodes]
@ -685,20 +776,17 @@ class VFS(object):
virt_vis[name] = vn2
continue
ok = False
zx = vn2.axs
axs = [zx.uread, zx.uwrite, zx.umove, zx.udel, zx.uget]
u_has = vn2.uaxs.get(uname) or [False] * 9
for pset in permsets:
ok = True
for req, lst in zip(pset, axs):
if req and uname not in lst:
for req, zb in zip(pset, u_has):
if req and not zb:
ok = False
break
if ok:
virt_vis[name] = vn2
break
if ok:
virt_vis[name] = vn2
if ".hist" in abspath:
p = abspath.replace("\\", "/") if WINDOWS else abspath
if p.endswith("/.hist"):
@ -809,6 +897,7 @@ class VFS(object):
flt: set[str],
uname: str,
dirs: bool,
dots: int,
scandir: bool,
wrap: bool = True,
) -> Generator[dict[str, Any], None, None]:
@ -817,7 +906,7 @@ class VFS(object):
# if single folder: the folder itself is the top-level item
folder = "" if flt or not wrap else (vpath.split("/")[-1].lstrip(".") or "top")
g = self.walk(folder, vrem, [], uname, [[True, False]], 1, scandir, False)
g = self.walk(folder, vrem, [], uname, [[True, False]], dots, scandir, False)
for _, _, vpath, apath, files, rd, vd in g:
if flt:
files = [x for x in files if x[0] in flt]
@ -976,6 +1065,16 @@ class AuthSrv(object):
self.indent = ""
self.is_lxc = args.c == ["/z/initcfg"]
self._vf0b = {
"cachectl": self.args.cachectl,
"tcolor": self.args.tcolor,
"du_iwho": self.args.du_iwho,
"shr_who": self.args.shr_who if self.args.shr else "no",
"ls_q_m": ("", ""),
}
self._vf0 = self._vf0b.copy()
self._vf0["d2d"] = True
# fwd-decl
self.vfs = VFS(log_func, "", "", "", AXS(), {})
self.acct: dict[str, str] = {} # uname->pw
@ -1014,17 +1113,14 @@ class AuthSrv(object):
yield prev, True
def vf0(self):
return {"d2d": True, "tcolor": self.args.tcolor, "du_iwho": self.args.du_iwho}
return self._vf0.copy()
def vf0b(self):
return {"tcolor": self.args.tcolor, "du_iwho": self.args.du_iwho}
return self._vf0b.copy()
def idp_checkin(
self, broker: Optional["BrokerCli"], uname: str, gname: str
) -> bool:
if uname in self.acct:
return False
if self.idp_usr_gh.get(uname) == gname:
return False
@ -1083,6 +1179,16 @@ class AuthSrv(object):
src0 = src # abspath
dst0 = dst # vpath
zsl = []
for ptn, sigil in ((PTN_U_ANY, "${u}"), (PTN_G_ANY, "${g}")):
if bool(ptn.search(src)) != bool(ptn.search(dst)):
zsl.append(sigil)
if zsl:
t = "ERROR: if %s is mentioned in a volume definition, it must be included in both the filesystem-path [%s] and the volume-url [/%s]"
t = "\n".join([t % (x, src, dst) for x in zsl])
self.log(t, 1)
raise Exception(t)
un_gn = [(un, gn) for un, gns in un_gns.items() for gn in gns]
if not un_gn:
# ensure volume creation if there's no users
@ -1175,8 +1281,8 @@ class AuthSrv(object):
self.log(t, c=3)
raise Exception(BAD_CFG)
if not bos.path.isdir(src):
self.log("warning: filesystem-path does not exist: {}".format(src), 3)
if not bos.path.exists(src):
self.log("warning: filesystem-path did not exist: %r" % (src,), 3)
mount[dst] = (src, dst0)
daxs[dst] = AXS()
@ -1362,7 +1468,10 @@ class AuthSrv(object):
t = "group [%s] = " % (gn,)
t += ", ".join("user [%s]" % (x,) for x in uns)
self._l(ln, 5, t)
grps[gn] = uns
if gn in grps:
grps[gn].extend(uns)
else:
grps[gn] = uns
except:
t = 'lines inside the [groups] section must be "groupname: user1, user2, user..."'
raise Exception(t + SBADCFG)
@ -1494,7 +1603,7 @@ class AuthSrv(object):
uns = [x[0] for x in un_gns.items() if grp in x[1]]
if grp == "${g}":
unames.append(un)
elif not uns and not self.args.idp_h_grp:
elif not uns and not self.args.idp_h_grp and grp != self.args.grp_all:
t = "group [%s] must be defined with --grp argument (or in a [groups] config section)"
raise CfgEx(t % (grp,))
@ -1714,10 +1823,18 @@ class AuthSrv(object):
self.log("\n{0}\n{1}{0}".format(t, "\n".join(slns)))
raise
self.args.have_idp_hdrs = bool(self.args.idp_h_usr or self.args.idp_hm_usr)
self.args.have_ipu_or_ipr = bool(self.args.ipu or self.args.ipr)
derive_args(self.args)
self.setup_auth_ord()
if self.args.ipu and not self.args.have_idp_hdrs:
# syntax (CIDR=UNAME) is verified in load_ipu
zsl = [x.split("=", 1)[1] for x in self.args.ipu]
zsl = [x for x in zsl if x not in acct]
if zsl:
t = "ERROR: unknown users in ipu: %s" % (zsl,)
self.log(t, 1)
raise Exception(t)
self.setup_pwhash(acct)
defpw = acct.copy()
self.setup_chpw(acct)
@ -1798,7 +1915,7 @@ class AuthSrv(object):
vol.all_vps.sort(key=lambda x: len(x[0]), reverse=True)
vol.root = vfs
zs = "neversymlink"
zs = "du_iwho ls_q_m neversymlink"
k_ign = set(zs.split())
for vol in vfs.all_vols.values():
unknown_flags = set()
@ -1868,9 +1985,18 @@ class AuthSrv(object):
axs_key = "u" + perm
for vp, vol in vfs.all_vols.items():
zx = getattr(vol.axs, axs_key)
if "*" in zx:
if "*" in zx and "-@acct" not in zx:
for usr in unames:
zx.add(usr)
for zs in list(zx):
if zs.startswith("-"):
zx.discard(zs)
zs = zs[1:]
zx.discard(zs)
if zs.startswith("@"):
zs = zs[1:]
for zs in grps.get(zs) or []:
zx.discard(zs)
# aread,... = dict[uname, list[volnames] or []]
umap: dict[str, list[str]] = {x: [] for x in unames}
@ -1882,6 +2008,23 @@ class AuthSrv(object):
umap[usr].sort()
setattr(vfs, "a" + perm, umap)
for vol in vfs.all_nodes.values():
za = vol.axs
vol.uaxs = {
un: (
un in za.uread,
un in za.uwrite,
un in za.umove,
un in za.udel,
un in za.uget,
un in za.upget,
un in za.uhtml,
un in za.uadmin,
un in za.udot,
)
for un in unames
}
all_users = {}
missing_users = {}
associated_users = {}
@ -1950,6 +2093,8 @@ class AuthSrv(object):
promote = []
demote = []
for vol in vfs.all_vols.values():
if not vol.realpath:
continue
hid = self.hid_cache.get(vol.realpath)
if not hid:
zb = hashlib.sha512(afsenc(vol.realpath)).digest()
@ -1988,6 +2133,8 @@ class AuthSrv(object):
vol.histpath = absreal(vol.histpath)
for vol in vfs.all_vols.values():
if not vol.realpath:
continue
hid = self.hid_cache[vol.realpath]
vflag = vol.flags.get("dbpath")
if vflag == "-":
@ -2116,7 +2263,7 @@ class AuthSrv(object):
zs = vol.flags.get("rotf")
if zs:
use = True
lim.set_rotf(zs)
lim.set_rotf(zs, vol.flags.get("rotf_tz") or "UTC")
zs = vol.flags.get("maxn")
if zs:
@ -2211,6 +2358,10 @@ class AuthSrv(object):
free_umask = False
have_reflink = False
for vol in vfs.all_nodes.values():
if os.path.isfile(vol.realpath):
vol.flags["is_file"] = True
vol.flags["d2d"] = True
if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
vol.flags["e2ds"] = True
@ -2247,7 +2398,7 @@ class AuthSrv(object):
if vf not in vol.flags:
vol.flags[vf] = getattr(self.args, ga)
zs = "forget_ip gid nrand tail_who th_spec_p u2abort u2ow uid unp_who ups_who zip_who"
zs = "forget_ip gid nrand tail_who th_qv th_spec_p u2abort u2ow uid unp_who ups_who zip_who"
for k in zs.split():
if k in vol.flags:
vol.flags[k] = int(vol.flags[k])
@ -2298,6 +2449,9 @@ class AuthSrv(object):
vol.flags["du_iwho"] = n_du_who(vol.flags["du_who"])
if not enshare:
vol.flags["shr_who"] = self.args.shr_who = "no"
if vol.flags.get("og"):
self.args.uqe = True
@ -2384,6 +2538,57 @@ class AuthSrv(object):
t = "WARNING: volume [/%s]: invalid value specified for ext-th: %s"
self.log(t % (vol.vpath, etv), 3)
zsl1 = [x for x in vol.flags["preadmes"].split(",") if x]
zsl2 = [x for x in vol.flags["readmes"].split(",") if x]
zsl3 = list(set([x.lower() for x in zsl1]))
zsl4 = list(set([x.lower() for x in zsl2]))
vol.flags["emb_mds"] = [[0, zsl1, zsl3], [1, zsl2, zsl4]]
zsl1 = [x for x in vol.flags["prologues"].split(",") if x]
zsl2 = [x for x in vol.flags["epilogues"].split(",") if x]
zsl3 = list(set([x.lower() for x in zsl1]))
zsl4 = list(set([x.lower() for x in zsl2]))
vol.flags["emb_lgs"] = [[0, zsl1, zsl3], [1, zsl2, zsl4]]
zs = str(vol.flags.get("html_head") or "")
if zs and zs[:1] in "%@":
vol.flags["html_head_d"] = zs
head_s = str(vol.flags.get("html_head_s") or "")
else:
zs2 = str(vol.flags.get("html_head_s") or "")
if zs2 and zs:
head_s = "%s\n%s\n" % (zs2.strip(), zs.strip())
else:
head_s = zs2 or zs
if head_s and not head_s.endswith("\n"):
head_s += "\n"
if "norobots" in vol.flags:
head_s += META_NOBOTS
ico_url = vol.flags.get("ufavico")
if ico_url:
ico_h = ""
ico_ext = ico_url.split("?")[0].split(".")[-1].lower()
if ico_ext in FAVICON_MIMES:
zs = '<link rel="icon" type="%s" href="%s">\n'
ico_h = zs % (FAVICON_MIMES[ico_ext], ico_url)
elif ico_ext == "ico":
zs = '<link rel="shortcut icon" href="%s">\n'
ico_h = zs % (ico_url,)
if ico_h:
vol.flags["ufavico_h"] = ico_h
head_s += ico_h
if head_s:
vol.flags["html_head_s"] = head_s
else:
vol.flags.pop("html_head_s", None)
if not vol.flags.get("html_head_d"):
vol.flags.pop("html_head_d", None)
vol.check_landmarks()
# d2d drops all database features for a volume
@ -2425,18 +2630,25 @@ class AuthSrv(object):
vol.flags[k] = int(vol.flags[k])
if "e2d" not in vol.flags:
if "lifetime" in vol.flags:
t = 'removing lifetime config from volume "/{}" because e2d is disabled'
self.log(t.format(vol.vpath), 1)
del vol.flags["lifetime"]
zs = "lifetime rss"
drop = [x for x in zs.split() if x in vol.flags]
needs_e2d = [x for x in hooks if x in ("xau", "xiu")]
drop = [x for x in needs_e2d if vol.flags.get(x)]
if drop:
t = 'removing [{}] from volume "/{}" because e2d is disabled'
self.log(t.format(", ".join(drop), vol.vpath), 1)
for x in drop:
vol.flags.pop(x)
zs = "xau xiu"
drop += [x for x in zs.split() if vol.flags.get(x)]
for k in drop:
t = 'cannot enable [%s] for volume "/%s" because this requires one of the following: e2d / e2ds / e2dsa (either as volflag or global-option)'
self.log(t % (k, vol.vpath), 1)
vol.flags.pop(k)
zi = vol.flags.get("lifetime") or 0
zi2 = time.time() // (86400 * 365)
zi3 = zi2 * 86400 * 365
if zi < 0 or zi > zi3:
t = "the lifetime of volume [/%s] (%d) exceeds max value (%d years; %d)"
t = t % (vol.vpath, zi, zi2, zi3)
self.log(t, 1)
raise Exception(t)
# verify tags mentioned by -mt[mp] are used by -mte
local_mtp = {}
@ -2473,6 +2685,64 @@ class AuthSrv(object):
self.log(t.format(vol.vpath, mtp), 1)
errors = True
mte = vol.flags.get("mte") or {}
up_m = [x for x in UP_MTE_MAP if x in mte]
up_q = [UP_MTE_MAP[x] for x in up_m]
zs = "select %s from up where rd=? and fn=?" % (", ".join(up_q),)
vol.flags["ls_q_m"] = (zs if up_m else "", up_m)
vfs.all_fvols = {
zs: vol for zs, vol in vfs.all_vols.items() if "is_file" in vol.flags
}
for vol in vfs.all_nodes.values():
if not vol.flags.get("is_file"):
continue
zs = "og opds xlink"
for zs in zs.split():
vol.flags.pop(zs, None)
for vol in vfs.all_nodes.values():
if not vol.realpath or vol.flags.get("is_file"):
continue
ccs = vol.flags["casechk"][:1].lower()
if ccs in ("y", "n"):
if ccs == "y":
vol.flags["bcasechk"] = True
continue
try:
bos.makedirs(vol.realpath, vf=vol.flags)
files = os.listdir(vol.realpath)
for fn in files:
fn2 = fn.lower()
if fn == fn2:
fn2 = fn.upper()
if fn == fn2 or fn2 in files:
continue
is_ci = os.path.exists(os.path.join(vol.realpath, fn2))
ccs = "y" if is_ci else "n"
break
if ccs not in ("y", "n"):
ap = os.path.join(vol.realpath, "casechk")
open(ap, "wb").close()
ccs = "y" if os.path.exists(ap[:-1] + "K") else "n"
os.unlink(ap)
except Exception as ex:
if ANYWIN:
zs = "Windows"
ccs = "y"
elif MACOS:
zs = "Macos"
ccs = "y"
else:
zs = "Linux"
ccs = "n"
t = "unable to determine if filesystem at %r is case-insensitive due to %r; assuming casechk=%s due to %s"
self.log(t % (vol.realpath, ex, ccs, zs), 3)
vol.flags["casechk"] = ccs
if ccs == "y":
vol.flags["bcasechk"] = True
tags = self.args.mtp or []
tags = [x.split("=")[0] for x in tags]
tags = [y for x in tags for y in x.split(",")]
@ -2563,9 +2833,13 @@ class AuthSrv(object):
["uadmin", "uadmin"],
]:
u = list(sorted(getattr(zv.axs, attr)))
u = ["*"] if "*" in u else u
u = ", ".join("\033[35meverybody\033[0m" if x == "*" else x for x in u)
u = u if u else "\033[36m--none--\033[0m"
if u == ["*"] and acct:
u = ["\033[35monly-anonymous\033[0m"]
elif "*" in u:
u = ["\033[35meverybody\033[0m"]
if not u:
u = ["\033[36m--none--\033[0m"]
u = ", ".join(u)
t += "\n| {}: {}".format(txt, u)
if "e2d" in zv.flags:
@ -2576,7 +2850,11 @@ class AuthSrv(object):
if "dedup" in zv.flags:
have_dedup = True
if "e2d" not in zv.flags and "hardlink" not in zv.flags:
if (
"e2d" not in zv.flags
and "hardlink" not in zv.flags
and "reflink" not in zv.flags
):
unsafe_dedup.append("/" + zv.vpath)
t += "\n"
@ -2673,8 +2951,6 @@ class AuthSrv(object):
if have_reflink:
t = "WARNING: Reflink-based dedup was requested, but %s. This will not work; files will be full copies instead."
if sys.version_info < (3, 14):
self.log(t % "your python version is not new enough", 1)
if not sys.platform.startswith("linux"):
self.log(t % "your OS is not Linux", 1)
@ -2694,9 +2970,11 @@ class AuthSrv(object):
pwds.extend([x.split(":", 1)[1] for x in pwds if ":" in x])
if pwds:
if self.ah.on:
zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)"
zs = r"(\[H\] %s:.*|[?&]%s=)([^&]+)"
zs = zs % (self.args.pw_hdr, self.args.pw_urlp)
else:
zs = r"(\[H\] pw:.*|=)(" + "|".join(pwds) + r")([]&; ]|$)"
zs = r"(\[H\] %s:.*|=)(" % (self.args.pw_hdr,)
zs += "|".join(pwds) + r")([]&; ]|$)"
self.re_pwd = re.compile(zs)
@ -2740,13 +3018,23 @@ class AuthSrv(object):
shn.shr_files = set(fns)
shn.ls = shn._ls_shr
shn.canonical = shn._canonical_shr
shn.dcanonical = shn._dcanonical_shr
else:
shn.ls = shn._ls
shn.canonical = shn._canonical
shn.dcanonical = shn._dcanonical
shn.shr_owner = s_un
shn.shr_src = (s_vfs, s_rem)
shn.realpath = s_vfs.canonical(s_rem)
o_vn, _ = shn._get_share_src("")
shn.lim = o_vn.lim
shn.flags = o_vn.flags.copy()
shn.dbpath = o_vn.dbpath
shn.histpath = o_vn.histpath
# root.all_aps doesn't include any shares, so make a copy where the
# share appears in all abspaths it can provide (for example for chk_ap)
ap = shn.realpath
@ -2798,17 +3086,23 @@ class AuthSrv(object):
vn.js_ls = {
"idx": "e2d" in vf,
"itag": "e2t" in vf,
"dlni": "dlni" in vf,
"dgrid": "grid" in vf,
"dnsort": "nsort" in vf,
"dhsortn": vf["hsortn"],
"dsort": vf["sort"],
"dcrop": vf["crop"],
"dth3x": vf["th3x"],
"u2ts": vf["u2ts"],
"shr_who": vf["shr_who"],
"frand": bool(vf.get("rand")),
"lifetime": vf.get("lifetime") or 0,
"unlist": vf.get("unlist") or "",
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
}
if "ufavico_h" in vf:
vn.js_ls["ufavico"] = vf["ufavico_h"]
js_htm = {
"SPINNER": self.args.spinner,
"s_name": self.args.bname,
@ -2818,14 +3112,17 @@ class AuthSrv(object):
"have_c2flac": self.args.allow_flac,
"have_c2wav": self.args.allow_wav,
"have_shr": self.args.shr,
"shr_who": vf["shr_who"],
"have_zip": not self.args.no_zip,
"have_zls": not self.args.no_zls,
"have_mv": not self.args.no_mv,
"have_del": not self.args.no_del,
"have_unpost": int(self.args.unpost),
"have_emp": int(self.args.emp),
"md_no_br": int(vf.get("md_no_br") or 0),
"ext_th": vf.get("ext_th_d") or {},
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
"sb_lg": vn.js_ls["sb_lg"],
"sb_md": vn.js_ls["sb_md"],
"sba_md": vf.get("md_sba") or "",
"sba_lg": vf.get("lg_sba") or "",
"txt_ext": self.args.textfiles.replace(",", " "),
@ -2833,7 +3130,8 @@ class AuthSrv(object):
"unlist0": vf.get("unlist") or "",
"see_dots": self.args.see_dots,
"dqdel": self.args.qdel,
"dgrid": "grid" in vf,
"dlni": vn.js_ls["dlni"],
"dgrid": vn.js_ls["dgrid"],
"dgsel": "gsel" in vf,
"dnsort": "nsort" in vf,
"dhsortn": vf["hsortn"],
@ -2843,6 +3141,7 @@ class AuthSrv(object):
"dvol": self.args.au_vol,
"idxh": int(self.args.ih),
"dutc": not self.args.localtime,
"dfszf": self.args.ui_filesz.strip("-"),
"themes": self.args.themes,
"turbolvl": self.args.turbo,
"nosubtle": self.args.nosubtle,
@ -2854,6 +3153,14 @@ class AuthSrv(object):
"lifetime": vn.js_ls["lifetime"],
"u2sort": self.args.u2sort,
}
zs = "ui_noacci ui_nocpla ui_noctxb ui_nolbar ui_nombar ui_nonav ui_notree ui_norepl ui_nosrvi"
for zs in zs.split():
if vf.get(zs):
js_htm[zs] = 1
zs = "notooltips"
for zs in zs.split():
if getattr(self.args, zs, False):
js_htm[zs] = 1
vn.js_htm = json_hesc(json.dumps(js_htm))
vols = list(vfs.all_nodes.values())
@ -2864,7 +3171,10 @@ class AuthSrv(object):
self.log("BUG: /%s not in all_nodes" % (vol.vpath,), 1)
vols.append(vol)
if shr in vfs.all_nodes:
self.log("BUG: %s found in all_nodes" % (shr,), 1)
t = "invalid config: a volume is overlapping with the --shr global-option (/%s)"
t = t % (shr,)
self.log(t, 1)
raise Exception(t)
for vol in vols:
dbv = vol.get_dbv("")[0]
@ -3023,7 +3333,7 @@ class AuthSrv(object):
pwdb = {}
else:
jtxt = read_utf8(self.log, ap, True)
pwdb = json.loads(jtxt)
pwdb = json.loads(jtxt) if jtxt.strip() else {}
pwdb = [x for x in pwdb if x[0] != uname]
pwdb.append((uname, self.defpw[uname], hpw))
@ -3047,7 +3357,7 @@ class AuthSrv(object):
return
jtxt = read_utf8(self.log, ap, True)
pwdb = json.loads(jtxt)
pwdb = json.loads(jtxt) if jtxt.strip() else {}
useen = set()
urst = set()
@ -3202,7 +3512,7 @@ class AuthSrv(object):
raise Exception("volume not found: " + zs)
self.log(str({"users": users, "vols": vols, "flags": flags}))
t = "/{}: read({}) write({}) move({}) del({}) dots({}) get({}) upGet({}) uadmin({})"
t = "/{}: read({}) write({}) move({}) del({}) dots({}) get({}) upGet({}) html({}) uadmin({})"
for k, zv in self.vfs.all_vols.items():
vc = zv.axs
vs = [
@ -3478,6 +3788,11 @@ class AuthSrv(object):
self.log("generated config:\n\n" + "\n".join(ret))
def derive_args(args: argparse.Namespace) -> None:
args.have_idp_hdrs = bool(args.idp_h_usr or args.idp_hm_usr)
args.have_ipu_or_ipr = bool(args.ipu or args.ipr)
def n_du_who(s: str) -> int:
if s == "all":
return 9

View file

@ -40,7 +40,7 @@ def makedirs(name: str, vf: dict[str, Any] = MKD_755, exist_ok: bool = True) ->
todo = []
bname = fsenc(name)
while bname:
if os.path.isdir(bname):
if os.path.isdir(bname) or bname in todo:
break
todo.append(bname)
bname = os.path.dirname(bname)
@ -104,7 +104,11 @@ def utime(
def utime_c(
log: Union["NamedLogger", Any], p: str, ts: int, follow_symlinks: bool = True, throw: bool = False
log: Union["NamedLogger", Any],
p: str,
ts: int,
follow_symlinks: bool = True,
throw: bool = False,
) -> Optional[int]:
clamp = 0
ov = ts

View file

@ -12,6 +12,7 @@ import queue
from .__init__ import ANYWIN
from .authsrv import AuthSrv
from .broker_util import BrokerCli, ExceptionalQueue, NotExQueue
from .fsutil import ramdisk_chk
from .httpsrv import HttpSrv
from .util import FAKE_MP, Daemon, HMaccas
@ -56,6 +57,7 @@ class MpWorker(BrokerCli):
# starting to look like a good idea
self.asrv = AuthSrv(args, None, False)
ramdisk_chk(self.asrv)
# instantiate all services here (TODO: inheritance?)
self.iphash = HMaccas(os.path.join(self.args.E.cfg, "iphash"), 8)
@ -99,6 +101,7 @@ class MpWorker(BrokerCli):
if dest == "reload":
self.logw("mpw.asrv reloading")
self.asrv.reload()
ramdisk_chk(self.asrv)
self.logw("mpw.asrv reloaded")
continue

View file

@ -2,6 +2,7 @@ import calendar
import errno
import json
import os
import shutil
import time
from .__init__ import ANYWIN
@ -19,6 +20,19 @@ else:
VF = {"mv_re_t": 0, "rm_re_t": 0}
def _sp_err(exe, what, rc, so, se, sin):
try:
zs = shutil.which(exe)
except:
zs = "<?>"
try:
zi = os.path.getsize(zs)
except:
zi = 0
t = "failed to %s; error %s using %s (%s):\n STDOUT: %s\n STDERR: %s\n STDIN: %s\n"
raise Exception(t % (what, rc, zs, zi, so, se, sin.decode("utf-8")))
def ensure_cert(log: "RootLogger", args) -> None:
"""
the default cert (and the entire TLS support) is only here to enable the
@ -107,13 +121,13 @@ def _gen_ca(log: "RootLogger", args):
cmd = "cfssl gencert -initca -"
rc, so, se = runcmd(cmd.split(), 30, sin=sin)
if rc:
raise Exception("failed to create ca-cert: {}, {}".format(rc, se), 3)
_sp_err("cfssl", "create ca-cert", rc, so, se, sin)
cmd = "cfssljson -bare ca"
sin = so.encode("utf-8")
rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir)
if rc:
raise Exception("failed to translate ca-cert: {}, {}".format(rc, se), 3)
_sp_err("cfssljson", "translate ca-cert", rc, so, se, sin)
bname = os.path.join(args.crt_dir, "ca")
try:
@ -201,13 +215,13 @@ def _gen_srv(log: "RootLogger", args, netdevs: dict[str, Netdev]):
acmd = cmd.split() + ["-hostname=" + ",".join(names), "-"]
rc, so, se = runcmd(acmd, 30, sin=sin, cwd=args.crt_dir)
if rc:
raise Exception("failed to create cert: {}, {}".format(rc, se))
_sp_err("cfssl", "create cert", rc, so, se, sin)
cmd = "cfssljson -bare srv"
sin = so.encode("utf-8")
rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir)
if rc:
raise Exception("failed to translate cert: {}, {}".format(rc, se))
_sp_err("cfssljson", "translate cert", rc, so, se, sin)
bname = os.path.join(args.crt_dir, "srv")
try:

View file

@ -19,6 +19,7 @@ def vf_bmap() -> dict[str, str]:
"no_clone": "noclone",
"no_dirsz": "nodirsz",
"no_dupe": "nodupe",
"no_dupe_m": "nodupem",
"no_forget": "noforget",
"no_pipe": "nopipe",
"no_robots": "norobots",
@ -29,6 +30,7 @@ def vf_bmap() -> dict[str, str]:
}
for k in (
"dedup",
"dlni",
"dotsrch",
"e2d",
"e2ds",
@ -52,11 +54,23 @@ def vf_bmap() -> dict[str, str]:
"og",
"og_no_head",
"og_s_title",
"opds",
"rand",
"reflink",
"rm_partial",
"rmagic",
"rss",
"ui_noacci",
"ui_nocpla",
"ui_nolbar",
"ui_nombar",
"ui_nonav",
"ui_notree",
"ui_norepl",
"ui_nosrvi",
"ui_noctxb",
"wo_up_readme",
"wram",
"xdev",
"xlink",
"xvol",
@ -80,14 +94,21 @@ def vf_vmap() -> dict[str, str]:
"th_x3": "th3x",
}
for k in (
"apnd_who",
"bup_ck",
"cachectl",
"casechk",
"chmod_d",
"chmod_f",
"dbd",
"du_who",
"epilogues",
"ufavico",
"forget_ip",
"fsnt",
"hsortn",
"html_head",
"html_head_s",
"lg_sbf",
"md_sbf",
"lg_sba",
@ -104,16 +125,25 @@ def vf_vmap() -> dict[str, str]:
"og_title_i",
"og_tpl",
"og_ua",
"opds_exts",
"prologues",
"preadmes",
"put_ck",
"put_name",
"readmes",
"mv_retry",
"rm_retry",
"rss_sort",
"rss_fmt_t",
"rss_fmt_d",
"shr_who",
"sort",
"tail_fd",
"tail_rate",
"tail_tmax",
"tail_who",
"tcolor",
"th_qv",
"th_spec_p",
"txt_eol",
"unlist",
@ -181,12 +211,17 @@ flagcats = {
"safededup": "verify on-disk data before using it for dedup",
"noclone": "take dupe data from clients, even if available on HDD",
"nodupe": "rejects existing files (instead of linking/cloning them)",
"nodupem": "rejects existing files during moves as well",
"casechk=auto": "actively prevent case-insensitive filesystem? y/n",
"chmod_d=755": "unix-permission for new dirs/folders",
"chmod_f=644": "unix-permission for new files",
"uid=573": "change owner of new files/folders to unix-user 573",
"gid=999": "change owner of new files/folders to unix-group 999",
"fsnt=auto": "filesystem filename traits (lin/win/mac/auto)",
"wram": "allow uploading into ramdisks",
"sparse": "force use of sparse files, mainly for s3-backed storage",
"nosparse": "deny use of sparse files, mainly for slow storage",
"rm_partial": "delete unfinished uploads from HDD when they timeout",
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
"nosub": "forces all uploads into the top folder of the vfs",
"magic": "enables filetype detection for nameless uploads",
@ -198,6 +233,7 @@ flagcats = {
"pk": "forces server-side compression, optional arg: xz,9",
},
"upload rules": {
"apnd_who=dw": "who can append? (aw/dw/w/no)",
"maxn=250,600": "max 250 uploads over 15min",
"maxb=1g,300": "max 1 GiB over 5min (suffixes: b, k, m, g, t)",
"vmaxb=1g": "total volume size max 1 GiB (suffixes: b, k, m, g, t)",
@ -215,6 +251,7 @@ flagcats = {
"upload rotation\n(moves all uploads into the specified folder structure)": {
"rotn=100,3": "3 levels of subfolders with 100 entries in each",
"rotf=%Y-%m/%d-%H": "date-formatted organizing",
"rotf_tz=Europe/Oslo": "timezone (default=UTC)",
"lifetime=3600": "uploads are deleted after 1 hour",
},
"database, general": {
@ -265,6 +302,7 @@ flagcats = {
"thsize": "thumbnail res; WxH",
"crop": "center-cropping (y/n/fy/fn)",
"th3x": "3x resolution (y/n/fy/fn)",
"th_qv=40": "thumbnail quality (10~90)",
"convt": "convert-to-image timeout in seconds",
"aconvt": "convert-to-audio timeout in seconds",
"th_spec_p=1": "make spectrograms? 0=never 1=fallback 2=always",
@ -293,8 +331,11 @@ flagcats = {
"sort": "default sort order",
"nsort": "natural-sort of leading digits in filenames",
"hsortn": "number of sort-rules to add to media URLs",
"ufavico=URL": "per-volume favicon (.ico/png/gif/svg)",
"unlist": "dont list files matching REGEX",
"dlni": "force-download (no-inline) files on click",
"html_head=TXT": "includes TXT in the <head>, or @PATH for file at PATH",
"html_head_s=TXT": "additional static text in the html <head>",
"tcolor=#fc0": "theme color (a hint for webbrowsers, discord, etc.)",
"nodirsz": "don't show total folder size",
"du_who=all": "show disk-usage info to everyone",
@ -302,6 +343,10 @@ flagcats = {
"norobots": "kindly asks search engines to leave",
"unlistcr": "don't list read-access in controlpanel",
"unlistcw": "don't list write-access in controlpanel",
"prologues=.prologue.html": "files to embed above/before files",
"epilogues=.epilogue.html": "files to embed below/after files",
"readmes=readme.md,README.md": "files to embed as readmes",
"preadmes=preadme.md,PREADME.md": "files to embed as preadmes",
"no_sb_md": "disable js sandbox for markdown files",
"no_sb_lg": "disable js sandbox for prologue/epilogue",
"sb_md": "enable js sandbox for markdown files (default)",
@ -311,6 +356,15 @@ flagcats = {
"md_sba": "value of iframe allow-prop for markdown-sandbox",
"lg_sba": "value of iframe allow-prop for *logue-sandbox",
"nohtml": "return html and markdown as text/html",
"ui_noacci": "hide account-info in the UI",
"ui_nocpla": "hide cpanel-link in the UI",
"ui_nolbar": "hide link-bar in the UI",
"ui_nombar": "hide top-menu in the UI",
"ui_nonav": "hide navpane+breadcrumbs in the UI",
"ui_notree": "hide navpane in the UI",
"ui_norepl": "hide repl-button in the UI",
"ui_nosrvi": "hide server-info in the UI",
"ui_noctxb": "hide context-buttons in the UI",
},
"opengraph (discord embeds)": {
"og": "enable OG (disables hotlinking)",
@ -326,6 +380,10 @@ flagcats = {
"og_no_head": "you want to add tags manually with og_tpl",
"og_ua": "if defined: only send OG html if useragent matches this regex",
},
"opds": {
"opds": "enable OPDS",
"opds_exts": "file formats to list in OPDS feeds; leave empty to show everything",
},
"textfiles": {
"md_no_br": "newline only on double-newline or two tailing spaces",
"md_hist": "where to put markdown backups; s=subfolder, v=volHist, n=nope",
@ -341,6 +399,12 @@ flagcats = {
"tail_tmax=30": "kill connection after 30 sec",
"tail_who=2": "restrict ?tail access (1=admins,2=authed,3=everyone)",
},
"rss": {
"rss": "allow '?rss' URL suffix (experimental)",
"rss_sort=m": "default sort-order (m/u/n/s)",
"rss_fmt_t={fname}": "default title-format",
"rss_fmt_d={album},{.tn}": "default description-format",
},
"others": {
"dots": "allow all users with read-access to\nenable the option to show dotfiles in listings",
"fk=8": 'generates per-file accesskeys,\nwhich are then required at the "g" permission;\nkeys are invalidated if filesize or inode changes',
@ -348,8 +412,8 @@ flagcats = {
"dk=8": 'generates per-directory accesskeys,\nwhich are then required at the "g" permission;\nkeys are invalidated if filesize or inode changes',
"dks": "per-directory accesskeys allow browsing into subdirs",
"dky": 'allow seeing files (not folders) inside a specific folder\nwith "g" perm, and does not require a valid dirkey to do so',
"rss": "allow '?rss' URL suffix (experimental)",
"rmagic": "expensive analysis for mimetype accuracy",
"shr_who=auth": "who can create shares? no/auth/a",
"unp_who=2": "unpost only if same... 1=ip+name, 2=ip, 3=name",
"ups_who=2": "restrict viewing the list of recent uploads",
"zip_who=2": "restrict access to download-as-zip/tar",
@ -358,6 +422,7 @@ flagcats = {
"zipmaxt=no": "reply with 'no' if download-as-zip exceeds max",
"zipmaxu": "zip-size-limit does not apply to authenticated users",
"nopipe": "disable race-the-beam (download unfinished uploads)",
"cachectl=no-cache": "controls caching in webbrowsers",
"mv_retry": "ms-windows: timeout for renaming busy files",
"rm_retry": "ms-windows: timeout for deleting busy files",
"davauth": "ask webdav clients to login for all folders",

View file

@ -2,14 +2,15 @@
from __future__ import print_function, unicode_literals
import argparse
import json
import os
import re
import time
from .__init__ import ANYWIN, MACOS
from .authsrv import AXS, VFS
from .authsrv import AXS, VFS, AuthSrv
from .bos import bos
from .util import chkcmd, min_ex, undot
from .util import chkcmd, json_hesc, min_ex, undot
if True: # pylint: disable=using-constant-test
from typing import Optional, Union
@ -18,22 +19,25 @@ if True: # pylint: disable=using-constant-test
class Fstab(object):
def __init__(self, log: "RootLogger", args: argparse.Namespace):
def __init__(self, log: "RootLogger", args: argparse.Namespace, verbose: bool):
self.log_func = log
self.verbose = verbose
self.warned = False
self.trusted = False
self.tab: Optional[VFS] = None
self.oldtab: Optional[VFS] = None
self.srctab = "a"
self.cache: dict[str, str] = {}
self.cache: dict[str, tuple[str, str]] = {}
self.age = 0.0
self.maxage = args.mtab_age
def log(self, msg: str, c: Union[int, str] = 0) -> None:
if not c or self.verbose:
return
self.log_func("fstab", msg, c)
def get(self, path: str) -> str:
def get(self, path: str) -> tuple[str, str]:
now = time.time()
if now - self.age > self.maxage or len(self.cache) > 9000:
self.age = now
@ -41,6 +45,7 @@ class Fstab(object):
self.tab = None
self.cache = {}
mp = ""
fs = "ext4"
msg = "failed to determine filesystem at %r; assuming %s\n%s"
@ -50,7 +55,7 @@ class Fstab(object):
path = self._winpath(path)
except:
self.log(msg % (path, fs, min_ex()), 3)
return fs
return fs, ""
path = undot(path)
try:
@ -59,14 +64,14 @@ class Fstab(object):
pass
try:
fs = self.get_w32(path) if ANYWIN else self.get_unix(path)
fs, mp = self.get_w32(path) if ANYWIN else self.get_unix(path)
except:
self.log(msg % (path, fs, min_ex()), 3)
fs = fs.lower()
self.cache[path] = fs
self.log("found %s at %r" % (fs, path))
return fs
self.cache[path] = (fs, mp)
self.log("found %s at %r, %r" % (fs, mp, path))
return fs, mp
def _winpath(self, path: str) -> str:
# try to combine volume-label + st_dev (vsn)
@ -81,34 +86,67 @@ class Fstab(object):
self.tab = VFS(self.log_func, "idk", "/", "/", AXS(), {})
self.trusted = False
def build_tab(self) -> None:
self.log("inspecting mtab for changes")
def _from_sp_mount(self) -> dict[str, str]:
sptn = r"^.*? on (.*) type ([^ ]+) \(.*"
if MACOS:
sptn = r"^.*? on (.*) \(([^ ]+), .*"
ptn = re.compile(sptn)
so, _ = chkcmd(["mount"])
tab1: list[tuple[str, str]] = []
atab = []
dtab: dict[str, str] = {}
for ln in so.split("\n"):
m = ptn.match(ln)
if not m:
continue
zs1, zs2 = m.groups()
tab1.append((str(zs1), str(zs2)))
atab.append(ln)
dtab[str(zs1)] = str(zs2)
return dtab
def _from_proc(self) -> dict[str, str]:
ret: dict[str, str] = {}
with open("/proc/self/mounts", "rb", 262144) as f:
src = f.read(262144).decode("utf-8", "replace").split("\n")
for zsl in [x.split(" ") for x in src]:
if len(zsl) < 3:
continue
zs = zsl[1]
zs = zs.replace("\\011", "\t").replace("\\040", " ").replace("\\134", "\\")
ret[zs] = zsl[2]
return ret
def build_tab(self) -> None:
self.log("inspecting mtab for changes")
dtab = self._from_sp_mount() if MACOS else self._from_proc()
# keep empirically-correct values if mounttab unchanged
srctab = "\n".join(sorted(atab))
srctab = str(sorted(dtab.items()))
if srctab == self.srctab:
self.tab = self.oldtab
return
self.log("mtab has changed; reevaluating support for sparse files")
try:
fuses = [mp for mp, fs in dtab.items() if fs == "fuseblk"]
if not fuses or MACOS:
raise Exception()
try:
so, _ = chkcmd(["lsblk", "-nrfo", "FSTYPE,MOUNTPOINT"]) # centos6
except:
so, _ = chkcmd(["lsblk", "-nrfo", "FSTYPE,MOUNTPOINTS"]) # future
for ln in so.split("\n"):
zsl = ln.split(" ", 1)
if len(zsl) != 2:
continue
fs, mp = zsl
if mp in fuses:
dtab[mp] = fs
except:
pass
tab1 = list(dtab.items())
tab1.sort(key=lambda x: (len(x[0]), x[0]))
path1, fs1 = tab1[0]
tab = VFS(self.log_func, fs1, path1, path1, AXS(), {})
@ -146,7 +184,7 @@ class Fstab(object):
vn.realpath = ptn.sub(nval, vn.realpath)
visit.extend(list(vn.nodes.values()))
def get_unix(self, path: str) -> str:
def get_unix(self, path: str) -> tuple[str, str]:
if not self.tab:
try:
self.build_tab()
@ -155,20 +193,73 @@ class Fstab(object):
# prisonparty or other restrictive environment
if not self.warned:
self.warned = True
self.log("failed to build tab:\n{}".format(min_ex()), 3)
t = "failed to associate fs-mounts with the VFS (this is fine):\n%s"
self.log(t % (min_ex(),), 6)
self.build_fallback()
assert self.tab # !rm
ret = self.tab._find(path)[0]
if self.trusted or path == ret.vpath:
return ret.realpath.split("/")[0]
return ret.realpath.split("/")[0], ret.vpath
else:
return "idk"
return "idk", ""
def get_w32(self, path: str) -> str:
def get_w32(self, path: str) -> tuple[str, str]:
if not self.tab:
self.build_fallback()
assert self.tab # !rm
ret = self.tab._find(path)[0]
return ret.realpath
return ret.realpath, ""
_fstab: Optional[Fstab] = None
winfs = set(("msdos", "vfat", "ntfs", "exfat"))
# "msdos" = vfat on macos
def ramdisk_chk(asrv: AuthSrv) -> None:
# should have been in authsrv but that's a circular import
global _fstab
mods = []
ramfs = ("tmpfs", "overlay")
log = asrv.log_func or print
if not _fstab:
_fstab = Fstab(log, asrv.args, False)
for vn in asrv.vfs.all_nodes.values():
if not vn.axs.uwrite or "wram" in vn.flags:
continue
ap = vn.realpath
if not ap or os.path.isfile(ap):
continue
fs, mp = _fstab.get(ap)
mp = "/" + mp.strip("/")
if fs == "tmpfs" or (mp == "/" and fs in ramfs):
mods.append((vn.vpath, ap, fs, mp))
vn.axs.uwrite.clear()
vn.axs.umove.clear()
for un, ztsp in list(vn.uaxs.items()):
zsl = list(ztsp)
zsl[1] = False
zsl[2] = False
vn.uaxs[un] = tuple(zsl) # type: ignore
if mods:
t = "WARNING: write-access was removed from the following volumes because they are not mapped to an actual HDD for storage! All uploaded data would live in RAM only, and all uploaded files would be LOST on next reboot. To allow uploading and ignore this hazard, enable the 'wram' option (global/volflag). List of affected volumes:"
t2 = ["\n volume=[/%s], abspath=%r, type=%s, root=%r" % x for x in mods]
log("vfs", t + "".join(t2) + "\n", 1)
assume = "mac" if MACOS else "lin"
for vol in asrv.vfs.all_nodes.values():
if not vol.realpath or vol.flags.get("is_file"):
continue
zs = vol.flags["fsnt"].strip()[:3].lower()
if ANYWIN and not zs:
zs = "win"
if zs in ("lin", "win", "mac"):
vol.flags["fsnt"] = zs
continue
fs = _fstab.get(vol.realpath)[0]
fs = "win" if fs in winfs else assume
htm = json.loads(vol.js_htm)
vol.flags["fsnt"] = vol.js_ls["fsnt"] = htm["fsnt"] = fs
vol.js_htm = json_hesc(json.dumps(htm))

View file

@ -86,7 +86,7 @@ class FtpAuth(DummyAuthorizer):
if args.usernames:
alts = ["%s:%s" % (username, password)]
else:
alts = password, username
alts = [password, username]
for zs in alts:
zs = asrv.iacct.get(asrv.ah.hash(zs), "")
@ -174,7 +174,7 @@ class FtpFs(AbstractedFS):
t = "Unsupported characters in [{}]"
raise FSE(t.format(vpath), 1)
fn = sanitize_fn(fn or "", "")
fn = sanitize_fn(fn or "")
vpath = vjoin(rd, fn)
vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
if (
@ -198,10 +198,13 @@ class FtpFs(AbstractedFS):
if not avfs:
raise FSE(t.format(vpath), 1)
cr, cw, cm, cd, _, _, _, _ = avfs.can_access("", self.h.uname)
cr, cw, cm, cd, _, _, _, _, _ = avfs.uaxs[self.h.uname]
if r and not cr or w and not cw or m and not cm or d and not cd:
raise FSE(t.format(vpath), 1)
if "bcasechk" in vfs.flags and not vfs.casechk(rem, True):
raise FSE("No such file or directory", 1)
return os.path.join(vfs.realpath, rem), vfs, rem
except Pebkac as ex:
raise FSE(str(ex))
@ -246,9 +249,36 @@ class FtpFs(AbstractedFS):
need_unlink = False
td = 0
if w and need_unlink:
xbu = vfs.flags.get("xbu")
if xbu:
hr = runhook(
self.log,
None,
self.hub.up2k,
"xbu.ftp",
xbu,
ap,
filename,
"",
"",
"",
0,
0,
"1.3.8.7",
time.time(),
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xbu server config: %r" % (filename,)
self.log(t, 3)
raise FSE(t)
if w and need_unlink: # type: ignore # !rm
assert td # type: ignore # !rm
if td >= -1 and td <= self.args.ftp_wt:
# within permitted timeframe; unlink and accept
# within permitted timeframe; allow overwrite or resume
do_it = True
elif self.args.no_del or self.args.ftp_no_ow:
# file too old, or overwrite not allowed; reject
@ -265,7 +295,9 @@ class FtpFs(AbstractedFS):
if not do_it:
raise FSE("File already exists")
wunlink(self.log, ap, VF_CAREFUL)
# Don't unlink file for append mode
elif "a" not in mode:
wunlink(self.log, ap, VF_CAREFUL)
ret = open(fsenc(ap), mode, self.args.iobuf)
if w and "fperms" in vfs.flags:
@ -276,6 +308,10 @@ class FtpFs(AbstractedFS):
def chdir(self, path: str) -> None:
nwd = join(self.cwd, path)
vfs, rem = self.hub.asrv.vfs.get(nwd, self.uname, False, False)
if not vfs.realpath:
self.cwd = nwd
return
ap = vfs.canonical(rem)
try:
st = bos.stat(ap)
@ -285,12 +321,9 @@ class FtpFs(AbstractedFS):
# returning 550 is library-default and suitable
raise FSE("No such file or directory")
if vfs.realpath:
avfs = vfs.chk_ap(ap, st)
if not avfs:
raise FSE("Permission denied", 1)
else:
avfs = vfs
avfs = vfs.chk_ap(ap, st)
if not avfs:
raise FSE("Permission denied", 1)
self.cwd = nwd
@ -489,24 +522,30 @@ class FtpHandler(FTPHandler):
return
self.vfs_map[ap] = vp
xbu = vfs.flags.get("xbu")
if xbu and not runhook(
None,
None,
self.hub.up2k,
"xbu.ftpd",
xbu,
ap,
vp,
"",
self.uname,
self.hub.asrv.vfs.get_perms(vp, self.uname),
0,
0,
self.cli_ip,
time.time(),
"",
):
raise FSE("Upload blocked by xbu server config")
if xbu:
hr = runhook(
None,
None,
self.hub.up2k,
"xbu.ftpd",
xbu,
ap,
vp,
"",
self.uname,
self.hub.asrv.vfs.get_perms(vp, self.uname),
0,
0,
self.cli_ip,
time.time(),
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "Upload blocked by xbu server config: %r" % (vp,)
self.respond("550 %s" % (t,), logging.info)
return
# print("ftp_STOR: {} {} => {}".format(vp, mode, ap))
ret = FTPHandler.ftp_STOR(self, file, mode)

File diff suppressed because it is too large Load diff

View file

@ -62,6 +62,7 @@ class HttpConn(object):
self.ipu_iu: Optional[dict[str, str]] = hsrv.ipu_iu
self.ipu_nm: Optional[NetMap] = hsrv.ipu_nm
self.ipa_nm: Optional[NetMap] = hsrv.ipa_nm
self.ipar_nm: Optional[NetMap] = hsrv.ipar_nm
self.xff_nm: Optional[NetMap] = hsrv.xff_nm
self.xff_lan: NetMap = hsrv.xff_lan # type: ignore
self.iphash: HMaccas = hsrv.broker.iphash

View file

@ -187,6 +187,7 @@ class HttpSrv(object):
"svcs",
]
self.j2 = {x: env.get_template(x + ".html") for x in jn}
self.j2["opds"] = env.get_template("opds.xml")
self.prism = has_resource(self.E, "web/deps/prism.js.gz")
if self.args.ipu:
@ -200,6 +201,7 @@ class HttpSrv(object):
self.ipr = None
self.ipa_nm = build_netmap(self.args.ipa)
self.ipar_nm = build_netmap(self.args.ipar)
self.xff_nm = build_netmap(self.args.xff_src)
self.xff_lan = build_netmap("lan")
@ -382,8 +384,8 @@ class HttpSrv(object):
if nloris < nconn / 2:
continue
t = "slowloris (idle-conn): {} banned for {} min"
self.log(self.name, t.format(ip, self.args.loris, nclose), 1)
t = "slow%s (idle-conn): %s banned for %d min" # slowloris
self.log(self.name, t % ("loris", ip, self.args.loris), 1)
self.bans[ip] = int(time.time() + self.args.loris * 60)
if self.args.log_conn:

View file

@ -2,6 +2,7 @@
from __future__ import print_function, unicode_literals
import errno
import os
import random
import select
import socket
@ -12,29 +13,64 @@ from ipaddress import IPv4Network, IPv6Network
from .__init__ import TYPE_CHECKING
from .__init__ import unicode as U
from .multicast import MC_Sck, MCast
from .stolen.dnslib import AAAA
from .stolen.dnslib import CLASS as DC
from .stolen.dnslib import (
NSEC,
PTR,
QTYPE,
RR,
SRV,
TXT,
A,
DNSHeader,
DNSQuestion,
DNSRecord,
set_avahi_379,
)
from .util import IP6_LL, CachedSet, Daemon, Netdev, list_ips, min_ex
try:
if os.getenv("PRTY_SYS_ALL") or os.getenv("PRTY_SYS_DNSLIB"):
raise ImportError()
from .stolen.dnslib import (
AAAA,
)
from .stolen.dnslib import CLASS as DC
from .stolen.dnslib import (
NSEC,
PTR,
QTYPE,
RR,
SRV,
TXT,
A,
DNSHeader,
DNSQuestion,
DNSRecord,
set_avahi_379,
)
DNS_VND = True
except ImportError:
DNS_VND = False
from dnslib import (
AAAA,
)
from dnslib import CLASS as DC
from dnslib import (
NSEC,
PTR,
QTYPE,
RR,
SRV,
TXT,
A,
Bimap,
DNSHeader,
DNSQuestion,
DNSRecord,
)
DC.forward[0x8001] = "F_IN"
DC.reverse["F_IN"] = 0x8001
if TYPE_CHECKING:
from .svchub import SvcHub
if True: # pylint: disable=using-constant-test
from typing import Any, Optional, Union
if os.getenv("PRTY_MODSPEC"):
from inspect import getsourcefile
print("PRTY_MODSPEC: dnslib:", getsourcefile(A))
MDNS4 = "224.0.0.251"
MDNS6 = "ff02::fb"
@ -73,8 +109,8 @@ class MDNS(MCast):
self.ngen = ngen
self.ttl = 300
if not self.args.zm_nwa_1:
set_avahi_379()
if not self.args.zm_nwa_1 and DNS_VND:
set_avahi_379() # type: ignore
zs = self.args.zm_fqdn or (self.args.name + ".local")
zs = zs.replace("--name", self.args.name).rstrip(".") + "."
@ -100,9 +136,14 @@ class MDNS(MCast):
self.log_func(self.logsrc, msg, c)
def build_svcs(self) -> tuple[dict[str, dict[str, Any]], set[str]]:
ar = self.args
zms = self.args.zms
http = {"port": 80 if 80 in self.args.p else self.args.p[0]}
https = {"port": 443 if 443 in self.args.p else self.args.p[0]}
zi = ar.zm_http
http = {"port": zi if zi != -1 else 80 if 80 in ar.p else ar.p[0]}
zi = ar.zm_https
https = {"port": zi if zi != -1 else 443 if 443 in ar.p else ar.p[0]}
webdav = http.copy()
webdavs = https.copy()
webdav["u"] = webdavs["u"] = "u" # KDE requires username
@ -127,16 +168,16 @@ class MDNS(MCast):
svcs: dict[str, dict[str, Any]] = {}
if "d" in zms:
if "d" in zms and http["port"]:
svcs["_webdav._tcp.local."] = webdav
if "D" in zms:
if "D" in zms and https["port"]:
svcs["_webdavs._tcp.local."] = webdavs
if "h" in zms:
if "h" in zms and http["port"]:
svcs["_http._tcp.local."] = http
if "H" in zms:
if "H" in zms and https["port"]:
svcs["_https._tcp.local."] = https
if "f" in zms.lower():

View file

@ -17,10 +17,10 @@ class Metrics(object):
self.hsrv = hsrv
def tx(self, cli: "HttpCli") -> bool:
if not cli.avol:
args = cli.args
if not cli.avol and cli.uname.lower() not in args.stats_u_set:
raise Pebkac(403, "'stats' not allowed for user " + cli.uname)
args = cli.args
if not args.stats:
raise Pebkac(403, "the stats feature is not enabled in server config")

View file

@ -168,16 +168,17 @@ def au_unpk(
znil = [x for x in znil if "cover" in x[0]] or znil
znil = [x for x in znil if CBZ_01.search(x[0])] or znil
t = "cbz: %d files, %d hits" % (nf, len(znil))
if not znil:
raise Exception("no images inside cbz")
using = sorted(znil)[0][1].filename
if znil:
t += ", using " + using
log(t)
if not znil:
raise Exception("no images inside cbz")
fi = zf.open(using)
elif pk == "epub":
fi = get_cover_from_epub(log, abspath)
assert fi # !rm
else:
raise Exception("unknown compression %s" % (pk,))
@ -199,9 +200,10 @@ def au_unpk(
except Exception as ex:
if ret:
t = "failed to decompress audio file %r: %r"
t = "failed to decompress file %r: %r"
log(t % (abspath, ex))
wunlink(log, ret, vn.flags if vn else VF_CAREFUL)
return ""
return abspath
@ -383,7 +385,7 @@ def get_cover_from_epub(log: "NamedLogger", abspath: str) -> Optional[IO[bytes]]
from .dxml import parse_xml
try:
from urlparse import urljoin # Python2
from urlparse import urljoin # type: ignore # Python2
except ImportError:
from urllib.parse import urljoin # Python3
@ -421,10 +423,17 @@ def get_cover_from_epub(log: "NamedLogger", abspath: str) -> Optional[IO[bytes]]
# This might be an EPUB2 file, try the legacy way of specifying covers
coverimage_path = _get_cover_from_epub2(log, package_root, package_ns)
if not coverimage_path:
raise Exception("no cover inside epub")
# This url is either absolute (in the .epub) or relative to the package document
adjusted_cover_path = urljoin(rootfile_path, coverimage_path)
return z.open(adjusted_cover_path)
try:
return z.open(adjusted_cover_path)
except KeyError:
t = "epub: cover specified in package document, but doesn't exist: %s"
log(t % (adjusted_cover_path,))
def _get_cover_from_epub2(
@ -432,9 +441,8 @@ def _get_cover_from_epub2(
) -> Optional[str]:
# <meta name="cover" content="id-to-cover-image"> in <metadata>, then
# <item> in <manifest>
cover_id = package_root.find("./metadata/meta[@name='cover']", package_ns).get(
"content"
)
xn = package_root.find("./metadata/meta[@name='cover']", package_ns)
cover_id = xn.get("content") if xn is not None else None
if not cover_id:
return None
@ -510,13 +518,12 @@ class MTag(object):
"album-artist",
"tpe2",
"aart",
"conductor",
"organization",
"band",
],
".tn": ["tracknumber", "trck", "trkn", "track"],
"genre": ["genre", "tcon", "\u00a9gen"],
"date": [
"tdate": [
"original-release-date",
"release-date",
"date",
@ -644,6 +651,9 @@ class MTag(object):
return self._get(abspath)
ap = au_unpk(self.log, self.args.au_unpk, abspath)
if not ap:
return {}
ret = self._get(ap)
if ap != abspath:
wunlink(self.log, ap, VF_CAREFUL)
@ -749,6 +759,9 @@ class MTag(object):
ap = abspath
ret: dict[str, Any] = {}
if not ap:
return ret
for tagname, parser in sorted(parsers.items(), key=lambda x: (x[1].pri, x[0])):
try:
cmd = [parser.bin, ap]

View file

@ -96,7 +96,10 @@ class MCast(object):
def create_servers(self) -> list[str]:
bound: list[str] = []
netdevs = self.hub.tcpsrv.netdevs
ips = [x[0] for x in self.hub.tcpsrv.bound]
blist = self.hub.tcpsrv.bound
if self.args.http_no_tcp:
blist = self.hub.tcpsrv.seen_eps
ips = [x[0] for x in blist]
if "::" in ips:
ips = [x for x in ips if x != "::"] + list(

112
copyparty/qrkode.py Normal file
View file

@ -0,0 +1,112 @@
# coding: utf-8
from __future__ import print_function, unicode_literals
import os
try:
if os.getenv("PRTY_SYS_ALL") or os.getenv("PRTY_SYS_QRCG"):
raise ImportError()
from .stolen.qrcodegen import QrCode
qrgen = QrCode.encode_binary
VENDORED = True
except ImportError:
VENDORED = False
from qrcodegen import QrCode
if os.getenv("PRTY_MODSPEC"):
from inspect import getsourcefile
print("PRTY_MODSPEC: qrcode:", getsourcefile(QrCode))
if True: # pylint: disable=using-constant-test
import typing
from typing import Any, Optional, Sequence, Union
if not VENDORED:
def _qrgen(data: Union[bytes, Sequence[int]]) -> "QrCode":
ret = None
V = QrCode.Ecc
for e in [V.HIGH, V.QUARTILE, V.MEDIUM, V.LOW]:
qr = QrCode.encode_binary(data, e)
qr.size = qr._size
qr.modules = qr._modules
if not ret or ret.size > qr.size:
ret = qr
return ret
qrgen = _qrgen
def qr2txt(qr: QrCode, zoom: int = 1, pad: int = 4) -> str:
tab = qr.modules
sz = qr.size
if sz % 2 and zoom == 1:
tab.append([False] * sz)
tab = [[False] * sz] * pad + tab + [[False] * sz] * pad
tab = [[False] * pad + x + [False] * pad for x in tab]
rows: list[str] = []
if zoom == 1:
for y in range(0, len(tab), 2):
row = ""
for x in range(len(tab[y])):
v = 2 if tab[y][x] else 0
v += 1 if tab[y + 1][x] else 0
row += " ▄▀█"[v]
rows.append(row)
else:
for tr in tab:
row = ""
for zb in tr:
row += ""[int(zb)] * 2
rows.append(row)
return "\n".join(rows)
def qr2png(
qr: QrCode,
zoom: int,
pad: int,
bg: Optional[tuple[int, int, int]],
fg: Optional[tuple[int, int, int]],
ap: str,
) -> None:
from PIL import Image
tab = qr.modules
sz = qr.size
psz = sz + pad * 2
if bg:
img = Image.new("RGB", (psz, psz), bg)
else:
img = Image.new("RGBA", (psz, psz), (0, 0, 0, 0))
fg = (fg[0], fg[1], fg[2], 255)
for y in range(sz):
for x in range(sz):
if tab[y][x]:
img.putpixel((x + pad, y + pad), fg)
if zoom != 1:
img = img.resize((sz * zoom, sz * zoom), Image.Resampling.NEAREST)
img.save(ap)
def qr2svg(qr: QrCode, border: int) -> str:
parts: list[str] = []
for y in range(qr.size):
sy = border + y
for x in range(qr.size):
if qr.modules[y][x]:
parts.append("M%d,%dh1v1h-1z" % (border + x, sy))
t = """\
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 {0} {0}" stroke="none">
<rect width="100%" height="100%" fill="#F7F7F7"/>
<path d="{1}" fill="#111111"/>
</svg>
"""
return t.format(qr.size + border * 2, " ".join(parts))

804
copyparty/sftpd.py Normal file
View file

@ -0,0 +1,804 @@
# coding: utf-8
from __future__ import print_function, unicode_literals
import errno
import hashlib
import logging
import os
import select
import socket
import time
from threading import ExceptHookArgs
import paramiko
import paramiko.common
import paramiko.sftp_attr
from paramiko.common import AUTH_FAILED, AUTH_SUCCESSFUL
from paramiko.sftp import (
SFTP_FAILURE,
SFTP_NO_SUCH_FILE,
SFTP_OK,
SFTP_OP_UNSUPPORTED,
SFTP_PERMISSION_DENIED,
)
from .__init__ import ANYWIN, TYPE_CHECKING
from .authsrv import LEELOO_DALLAS, VFS, AuthSrv
from .bos import bos
from .util import (
FN_EMB,
VF_CAREFUL,
Daemon,
ODict,
Pebkac,
ipnorm,
min_ex,
read_utf8,
relchk,
runhook,
sanitize_fn,
ub64enc,
undot,
vjoin,
wunlink,
)
if TYPE_CHECKING:
from .svchub import SvcHub
if True: # pylint: disable=using-constant-test
from typing import Any, BinaryIO, Optional, Union
SATTR = paramiko.sftp_attr.SFTPAttributes
class SSH_Srv(paramiko.ServerInterface):
def __init__(self, hub: "SvcHub", addr: Any):
self.hub = hub
self.args = args = hub.args
self.log_func = hub.log
self.uname = "*"
self.addr = addr
self.ip = addr[0]
if self.ip.startswith("::ffff:"):
self.ip = self.ip[7:]
zsl = []
if args.sftp_anon:
zsl.append("none")
if args.sftp_key2u:
zsl.append("publickey")
if args.sftp_pw or args.sftp_anon:
zsl.append("password")
self._auths = ",".join(zsl)
def log(self, msg: str, c: Union[int, str] = 0) -> None:
self.hub.log("sftp:%s" % (self.ip,), msg, c)
def get_allowed_auths(self, username: str) -> str:
return self._auths
def get_banner(self) -> tuple[Optional[str], Optional[str]]:
if self.args.sftpv:
self.log("get_banner")
t = self.args.sftp_banner
if not t:
return (None, None)
if t.startswith("@"):
t = read_utf8(self.log, t[1:], False)
if t and not t.endswith("\n"):
t += "\n"
return (t, "en-US")
def check_channel_request(self, kind: str, chanid: int) -> int:
if self.args.sftpv:
self.log("channel-request: %r, %r" % (kind, chanid))
if kind == "session":
return paramiko.common.OPEN_SUCCEEDED
return paramiko.common.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
def check_auth_none(self, username: str) -> int:
try:
return self._check_auth_none(username)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return AUTH_FAILED
def _check_auth_none(self, uname: str) -> int:
args = self.args
if uname != args.sftp_anon or not uname:
return AUTH_FAILED
ipn = ipnorm(self.ip)
bans = self.hub.bans
if ipn in bans:
rt = bans[ipn] - time.time()
if rt < 0:
self.log("client unbanned")
del bans[ipn]
else:
self.log("client is banned")
return AUTH_FAILED
self.uname = "*"
self.log("auth-none OK: *")
return AUTH_SUCCESSFUL
def check_auth_password(self, username: str, password: str) -> int:
try:
return self._check_auth_password(username, password)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return AUTH_FAILED
def _check_auth_password(self, uname: str, pw: str) -> int:
args = self.args
if args.sftpv:
logpw = pw
if args.log_badpwd == 0:
logpw = ""
elif args.log_badpwd == 2:
zb = hashlib.sha512(pw.encode("utf-8", "replace")).digest()
logpw = "%" + ub64enc(zb[:12]).decode("ascii")
self.log("auth-pw: %r, %r" % (uname, logpw))
ipn = ipnorm(self.ip)
bans = self.hub.bans
if ipn in bans:
rt = bans[ipn] - time.time()
if rt < 0:
self.log("client unbanned")
del bans[ipn]
else:
self.log("client is banned")
return AUTH_FAILED
anon = args.sftp_anon
if anon and uname == anon:
self.uname = "*"
self.log("auth-pw OK: *")
return AUTH_SUCCESSFUL
if not args.sftp_pw:
return AUTH_FAILED
if args.usernames:
alts = ["%s:%s" % (uname, pw)]
else:
alts = [pw, uname]
attempt = "%s:%s" % (uname, pw)
uname = ""
asrv = self.hub.asrv
for zs in alts:
zs = asrv.iacct.get(asrv.ah.hash(zs), "")
if zs:
uname = zs
break
if args.ipu and uname == "*":
uname = args.ipu_iu[args.ipu_nm.map(self.ip)]
if args.ipr and uname in args.ipr_u:
if not args.ipr_u[uname].map(self.ip):
logging.warning("username [%s] rejected by --ipr", uname)
return AUTH_FAILED
if not uname or not (asrv.vfs.aread.get(uname) or asrv.vfs.awrite.get(uname)):
g = self.hub.gpwd
if g.lim:
bonk, ip = g.bonk(self.ip, attempt)
if bonk:
logging.warning("client banned: invalid passwords")
bans[self.ip] = bonk
try:
# only possible if multiprocessing disabled
self.hub.broker.httpsrv.bans[ip] = bonk # type: ignore
self.hub.broker.httpsrv.nban += 1 # type: ignore
except:
pass
return AUTH_FAILED
self.uname = uname
self.log("auth-pw OK: %s" % (uname,))
return AUTH_SUCCESSFUL
def check_auth_publickey(self, username: str, key: paramiko.PKey) -> int:
try:
return self._check_auth_publickey(username, key)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return AUTH_FAILED
def _check_auth_publickey(self, uname: str, key: paramiko.PKey) -> int:
args = self.args
if args.sftpv:
zs = key.get_name() + "," + key.get_base64()[:32]
self.log("auth-key: %r, %r" % (uname, zs))
ipn = ipnorm(self.ip)
bans = self.hub.bans
if ipn in bans:
rt = bans[ipn] - time.time()
if rt < 0:
self.log("client unbanned")
del bans[ipn]
else:
self.log("client is banned")
return AUTH_FAILED
anon = args.sftp_anon
if anon and uname == anon:
self.uname = "*"
self.log("auth-key OK: *")
return AUTH_SUCCESSFUL
attempt = "%s %s" % (key.get_name(), key.get_base64())
ok = args.sftp_key2u.get(attempt) == uname
if ok and args.ipr and uname in args.ipr_u:
if not args.ipr_u[uname].map(self.ip):
logging.warning("username [%s] rejected by --ipr", uname)
return AUTH_FAILED
asrv = self.hub.asrv
if not ok or not (asrv.vfs.aread.get(uname) or asrv.vfs.awrite.get(uname)):
self.log("auth-key REJECTED: %s" % (uname,))
return AUTH_FAILED
self.uname = uname
self.log("auth-key OK: %s" % (uname,))
return AUTH_SUCCESSFUL
class SFTP_FH(paramiko.SFTPHandle):
def __init__(self, flags: int = 0) -> None:
self.filename = ""
self.readfile: Optional[BinaryIO] = None
self.writefile: Optional[BinaryIO] = None
super(SFTP_FH, self).__init__(flags)
def stat(self):
try:
f = self.readfile or self.writefile
return SATTR.from_stat(os.fstat(f.fileno()))
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def chattr(self, attr):
# python doesn't have equivalents to fchown or fchmod, so we have to
# use the stored filename
if not self.writefile:
return SFTP_PERMISSION_DENIED
try:
paramiko.SFTPServer.set_file_attr(self.filename, attr)
return SFTP_OK
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
class SFTP_Srv(paramiko.SFTPServerInterface):
def __init__(self, ssh: paramiko.ServerInterface, *a, **ka):
super(SFTP_Srv, self).__init__(ssh, *a, **ka)
self.ssh = ssh
self.ip: str = ssh.ip # type: ignore
self.hub: "SvcHub" = ssh.hub # type: ignore
self.uname: str = ssh.uname # type: ignore
self.args = self.hub.args
self.asrv: "AuthSrv" = self.hub.asrv
if self.uname == LEELOO_DALLAS:
raise Exception("send her back")
def log(self, msg: str, c: Union[int, str] = 0) -> None:
self.hub.log("sftp:%s" % (self.ip,), msg, c)
def v2a(
self,
vpath: str,
r: bool = False,
w: bool = False,
m: bool = False,
d: bool = False,
) -> tuple[str, VFS, str]:
vpath = vpath.replace(os.sep, "/").strip("/")
rd, fn = os.path.split(vpath)
if relchk(rd):
self.log("malicious vpath: %s", vpath)
raise Exception("Unsupported characters in [%s]" % (vpath,))
fn = sanitize_fn(fn or "")
vpath = vjoin(rd, fn)
vn, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
if (
w
and fn.lower() in FN_EMB
and self.uname not in vn.axs.uread
and "wo_up_readme" not in vn.flags
):
fn = "_wo_" + fn
vpath = vjoin(rd, fn)
vn, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
if not vn.realpath:
# return "", vn, rem
raise OSError(errno.ENOENT, "no filesystem mounted at [/%s]" % (vpath,))
if "xdev" in vn.flags or "xvol" in vn.flags:
ap = vn.canonical(rem)
avn = vn.chk_ap(ap)
t = "Permission denied in [{}]"
if not avn:
raise OSError(errno.EPERM, "permission denied in [/%s]" % (vpath,))
cr, cw, cm, cd, _, _, _, _, _ = avn.uaxs[self.uname]
if r and not cr or w and not cw or m and not cm or d and not cd:
raise OSError(errno.EPERM, "permission denied in [/%s]" % (vpath,))
if "bcasechk" in vn.flags and not vn.casechk(rem, True):
raise OSError(errno.ENOENT, "file does not exist case-sensitively")
return os.path.join(vn.realpath, rem), vn, rem
def list_folder(self, path: str) -> list[SATTR] | int:
try:
return self._list_folder(path)
except Pebkac as ex:
if ex.code == 404:
self.log("folder 404: %s" % (path,))
return SFTP_NO_SUCH_FILE
return SFTP_PERMISSION_DENIED
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _list_folder(self, path: str) -> list[SATTR] | int:
try:
ap, vn, rem = self.v2a(path, r=True)
except Pebkac:
try:
self.v2a(path, w=True)
return [] # display write-only folders as empty
except:
pass
if self.asrv.vfs.realpath or path.strip("/"):
return SFTP_PERMISSION_DENIED
# list of accessible volumes
ret = []
zi = int(time.time())
vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
for vn in self.asrv.vfs.all_vols.values():
if "/" in vn.vpath or not vn.vpath:
continue # only include toplevel-mounted vols
try:
self.hub.asrv.vfs.get(vn.vpath, self.uname, True, False)
ret.append(SATTR.from_stat(vst, filename=vn.vpath))
except:
pass
ret.sort(key=lambda x: x.filename)
return ret
_, vfs_ls, vfs_virt = vn.ls(
rem,
self.uname,
not self.args.no_scandir,
[[True, False], [False, True]],
throw=True,
)
ret = [SATTR.from_stat(x[1], filename=x[0]) for x in vfs_ls]
for zs, vn2 in vfs_virt.items():
if not vn2.realpath:
continue
st = bos.stat(vn2.realpath)
ret.append(SATTR.from_stat(st, filename=zs))
if self.uname not in vn.axs.udot:
ret = [x for x in ret if not x.filename.split("/")[-1].startswith(".")]
ret.sort(key=lambda x: x.filename)
return ret
def stat(self, path: str) -> SATTR | int:
try:
return self._stat(path)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def lstat(self, path: str) -> SATTR | int:
try:
return self._stat(path)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _stat(self, vp: str) -> SATTR | int:
try:
ap = self.v2a(vp, r=True)[0]
st = bos.stat(ap)
except:
if vp.strip("/") or self.asrv.vfs.realpath:
try:
self.v2a(vp, w=True)[0]
except:
return SFTP_PERMISSION_DENIED
zi = int(time.time())
st = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
return SATTR.from_stat(st)
def open(self, path: str, flags: int, attr: SATTR) -> paramiko.SFTPHandle | int:
try:
return self._open(path, flags, attr)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _open(self, vp: str, iflag: int, attr: SATTR) -> paramiko.SFTPHandle | int:
if ANYWIN:
iflag |= os.O_BINARY
if iflag & os.O_WRONLY:
rd = False
wr = True
if iflag & os.O_APPEND:
smode = "ab"
else:
smode = "wb"
elif iflag & os.O_RDWR:
rd = wr = True
if iflag & os.O_APPEND:
smode = "a+b"
else:
smode = "r+b"
else:
rd = True
wr = False
smode = "rb"
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, rd, wr)
ap = os.path.join(vn.realpath, rem)
vf = vn.flags
except Pebkac as ex:
t = "denied open file [%s], iflag=%s, attr=%s, read=%s, write=%s: %s"
self.log(t % (vp, iflag, attr, rd, wr, ex))
return SFTP_PERMISSION_DENIED
if wr:
try:
st = bos.stat(ap)
td = time.time() - st.st_mtime
need_unlink = True
except:
need_unlink = False
td = 0
xbu = vn.flags.get("xbu")
if xbu:
hr = runhook(
self.log,
None,
self.hub.up2k,
"xbu.sftp",
xbu,
ap,
vp,
"",
"",
"",
0,
0,
"7.3.8.7",
time.time(),
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xbu server config: %r" % (vp,)
self.log(t, 3)
return SFTP_PERMISSION_DENIED
if wr and need_unlink: # type: ignore # !rm
assert td # type: ignore # !rm
if td >= -1 and td <= self.args.ftp_wt:
# within permitted timeframe; allow overwrite or resume
do_it = True
elif self.args.no_del or self.args.ftp_no_ow:
# file too old, or overwrite not allowed; reject
do_it = False
else:
# allow overwrite if user has delete permission
do_it = self.uname in vn.axs.udel
if not do_it:
t = "file already exists and no permission to overwrite: %s"
self.log(t % (vp,))
return SFTP_PERMISSION_DENIED
# Don't unlink file for append mode
elif "a" not in smode:
wunlink(self.log, ap, VF_CAREFUL)
chmod = getattr(attr, "st_mode", None)
if chmod is None:
chmod = vf.get("chmod_f", 644)
try:
fd = os.open(ap, iflag, chmod)
except OSError as ex:
t = "failed to os.open [%s] -> [%s] with iflag [%s] and chmod [%s]"
self.log(t % (vp, ap, iflag, chmod), 3)
return paramiko.SFTPServer.convert_errno(ex.errno)
if iflag & os.O_CREAT:
paramiko.SFTPServer.set_file_attr(ap, attr)
try:
f = os.fdopen(fd, smode)
except OSError as ex:
t = "failed to os.fdpen [%s] -> [%s] with smode [%s]"
self.log(t % (vp, ap, smode), 3)
return paramiko.SFTPServer.convert_errno(ex.errno)
ret = SFTP_FH(iflag)
ret.filename = ap
ret.readfile = f if rd else None
ret.writefile = f if wr else None
return ret
def remove(self, path: str) -> int:
try:
return self._remove(path)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _remove(self, vp: str) -> int:
if self.args.no_del:
self.log("The delete feature is disabled in server config")
return SFTP_PERMISSION_DENIED
try:
self.hub.up2k.handle_rm(self.uname, self.ip, [vp], [], False, False)
return SFTP_OK
except Pebkac as ex:
t = "denied delete [%s]: %s"
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def rename(self, oldpath: str, newpath: str) -> int:
try:
return self._rename(oldpath, newpath)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _rename(self, svp: str, dvp: str) -> int:
if self.args.no_mv:
self.log("The rename/move feature is disabled in server config")
svp = svp.strip("/")
dvp = dvp.strip("/")
try:
self.hub.up2k.handle_mv("", self.uname, self.ip, svp, dvp)
return SFTP_OK
except Pebkac as ex:
t = "denied rename [%s] to [%s]: %s"
self.log(t % (svp, dvp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def mkdir(self, path: str, attr: SATTR) -> int:
try:
return self._mkdir(path, attr)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _mkdir(self, vp: str, attr: SATTR) -> int:
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True)
ap = os.path.join(vn.realpath, rem)
bos.makedirs(ap, vf=vn.flags) # filezilla expects this
if attr is not None:
paramiko.SFTPServer.set_file_attr(ap, attr)
return SFTP_OK
except Pebkac as ex:
t = "denied mkdir [%s]: %s"
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def rmdir(self, path: str) -> int:
try:
return self._rmdir(path)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _rmdir(self, vp: str) -> int:
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, False, will_del=True)
ap = os.path.join(vn.realpath, rem)
bos.rmdir(ap)
return SFTP_OK
except Pebkac as ex:
t = "denied rmdir [%s]: %s"
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def chattr(self, path: str, attr: SATTR) -> int:
try:
return self._chattr(path, attr)
except:
self.log("unhandled exception: %s" % (min_ex(),), 1)
return SFTP_FAILURE
def _chattr(self, vp: str, attr: SATTR) -> int:
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True, will_del=True)
ap = os.path.join(vn.realpath, rem)
paramiko.SFTPServer.set_file_attr(ap, attr)
return SFTP_OK
except Pebkac as ex:
t = "denied chattr [%s]: %s"
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
return paramiko.SFTPServer.convert_errno(ex.errno)
def symlink(self, target_path: str, path: str) -> int:
return SFTP_OP_UNSUPPORTED
def readlink(self, path: str) -> str | int:
return path
def canonicalize(self, path: str) -> str:
return "/%s" % (undot(path),)
class Sftpd(object):
def __init__(self, hub: "SvcHub") -> None:
self.hub = hub
self.args = args = hub.args
self.log_func = hub.log
self.srv: list[socket.socket] = []
self.bound: list[str] = []
self.sessions = {}
ips = args.i
if "::" in ips:
ips.append("0.0.0.0")
ips = [x for x in ips if not x.startswith(("unix:", "fd:"))]
if args.sftp4:
ips = [x for x in ips if ":" not in x]
if not ips:
self.log("cannot start sftp-server; no compatible IPs in -i", 1)
return
self.hostkeys = []
hostkeytypes = (
("ed25519", "Ed25519Key", {}), # best
("ecdsa", "ECDSAKey", {"bits": 384}),
("rsa", "RSAKey", {"bits": 4096}),
("dsa", "DSSKey", {}), # worst
)
for fname, aname, opts in hostkeytypes:
fpath = "%s/ssh_host_%s_key" % (args.sftp_hostk, fname.lower())
try:
pkey = getattr(paramiko, aname).from_private_key_file(fpath)
except Exception as ex:
try:
genfun = getattr(paramiko, aname).generate
except Exception as ex2:
if args.sftpv or fname not in ("dsa", "ed25519"):
# dsa dropped in 4.0
# ed25519 not supported yet
self.log("cannot generate %s hostkey: %r" % (aname, ex2), 3)
continue
self.log("generating hostkey [%s] due to %r" % (fpath, ex))
pkey = genfun(**opts)
pkey.write_private_key_file(fpath)
pkey = getattr(paramiko, aname).from_private_key_file(fpath)
self.hostkeys.append(pkey)
if args.sftpv:
self.log("loaded hostkey %r" % (pkey,))
ips = list(ODict.fromkeys(ips)) # dedup
for ip in ips:
self._bind(ip)
self.log("listening on %s port %s" % (self.srv, args.sftp))
def log(self, msg: str, c: Union[int, str] = 0) -> None:
self.hub.log("sftp", msg, c)
def _bind(self, ip: str) -> None:
port = self.args.sftp
try:
ipv = socket.AF_INET6 if ":" in ip else socket.AF_INET
srv = socket.socket(ipv, socket.SOCK_STREAM)
if not ANYWIN or self.args.reuseaddr:
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
srv.settimeout(0) # == srv.setblocking(False)
try:
srv.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
pass # will create another ipv4 socket instead
if getattr(self.args, "freebind", False):
srv.setsockopt(socket.SOL_IP, socket.IP_FREEBIND, 1)
srv.bind((ip, port))
srv.listen(10)
self.srv.append(srv)
self.bound.append(ip)
except Exception as ex:
if ip == "0.0.0.0" and "::" in self.bound:
return # dualstack
self.log("could not listen on (%s,%s): %r" % (ip, port, ex), 3)
def _accept(self, srv: socket.socket) -> None:
cli, addr = srv.accept()
# cli.settimeout(0) # == srv.setblocking(False)
self.log("%r is connecting" % (addr,))
zs = "sftp-%s" % (addr[0],)
# Daemon(self._accept2, zs, (cli, addr))
self._accept2(cli, addr)
def _accept2(self, cli, addr) -> None:
tra = paramiko.Transport(cli)
for hkey in self.hostkeys:
tra.add_server_key(hkey)
tra.set_subsystem_handler("sftp", paramiko.SFTPServer, SFTP_Srv)
psrv = SSH_Srv(self.hub, addr)
try:
tra.start_server(server=psrv)
except Exception as ex:
self.log("%r could not establish connection: %r" % (addr, ex), 3)
cli.close()
return
chan = tra.accept()
if chan is None:
self.log("%r did not open an sftp channel" % (addr,), 3)
cli.close()
return
self.sessions[addr] = (chan, tra, psrv)
# tra.join()
# self.log("%r disconnected" % (addr,))
def run(self):
lgr = logging.getLogger("paramiko.transport")
lgr.setLevel(logging.DEBUG if self.args.sftpvv else logging.INFO)
if self.args.no_poll:
fun = self._run_select
else:
fun = self._run_poll
Daemon(fun, "sftpd")
def _run_select(self):
while not self.hub.stopping:
rx, _, _ = select.select(self.srv, [], [], 180)
for sck in rx:
self._accept(sck)
def _run_poll(self):
fd2sck = {}
poll = select.poll()
for sck in self.srv:
fd = sck.fileno()
fd2sck[fd] = sck
poll.register(fd, select.POLLIN)
while not self.hub.stopping:
pr = poll.poll(180 * 1000)
rx = [fd2sck[x[0]] for x in pr if x[1] & select.POLLIN]
for sck in rx:
self._accept(sck)

View file

@ -246,24 +246,29 @@ class SMB(object):
ap = absreal(ap)
xbu = vfs.flags.get("xbu")
if xbu and not runhook(
self.nlog,
None,
self.hub.up2k,
"xbu.smb",
xbu,
ap,
vpath,
"",
"",
"",
0,
0,
"1.7.6.2",
time.time(),
"",
):
yeet("blocked by xbu server config: %r" % (vpath,))
if xbu:
hr = runhook(
self.nlog,
None,
self.hub.up2k,
"xbu.smb",
xbu,
ap,
vpath,
"",
"",
"",
0,
0,
"1.7.6.2",
time.time(),
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "blocked by xbu server config: %r" % (vpath,)
yeet(t)
ret = bos.open(ap, flags, *a, mode=chmod, **ka)
if wr:

View file

@ -4,7 +4,7 @@
# https://github.com/nayuki/QR-Code-generator/blob/daa3114/python/qrcodegen.py
# the original ^ is extremely well commented so refer to that for explanations
# hacks: binary-only, auto-ecc, render, py2-compat
# hacks: binary-only, auto-ecc, py2-compat
from __future__ import print_function, unicode_literals
@ -173,52 +173,6 @@ class QrCode(object):
self._apply_mask(msk) # Apply the final choice of mask
self._draw_format_bits(msk) # Overwrite old format bits
def render(self, zoom=1, pad=4) -> str:
tab = self.modules
sz = self.size
if sz % 2 and zoom == 1:
tab.append([False] * sz)
tab = [[False] * sz] * pad + tab + [[False] * sz] * pad
tab = [[False] * pad + x + [False] * pad for x in tab]
rows: list[str] = []
if zoom == 1:
for y in range(0, len(tab), 2):
row = ""
for x in range(len(tab[y])):
v = 2 if tab[y][x] else 0
v += 1 if tab[y + 1][x] else 0
row += " ▄▀█"[v]
rows.append(row)
else:
for tr in tab:
row = ""
for zb in tr:
row += ""[int(zb)] * 2
rows.append(row)
return "\n".join(rows)
def to_png(self, zoom, pad, bg, fg, ap) -> None:
from PIL import Image
tab = self.modules
sz = self.size
psz = sz + pad * 2
if bg:
img = Image.new("RGB", (psz, psz), bg)
else:
img = Image.new("RGBA", (psz, psz), (0, 0, 0, 0))
fg = (fg[0], fg[1], fg[2], 255)
for y in range(sz):
for x in range(sz):
if tab[y][x]:
img.putpixel((x + pad, y + pad), fg)
if zoom != 1:
img = img.resize((sz * zoom, sz * zoom), Image.Resampling.NEAREST)
img.save(ap)
def _draw_function_patterns(self) -> None:
# Draw horizontal and vertical timing patterns
for i in range(self.size):
@ -613,20 +567,3 @@ def _get_bit(x: int, i: int) -> bool:
class DataTooLongError(ValueError):
pass
def qr2svg(qr: QrCode, border: int) -> str:
parts: list[str] = []
for y in range(qr.size):
sy = border + y
for x in range(qr.size):
if qr.modules[y][x]:
parts.append("M%d,%dh1v1h-1z" % (border + x, sy))
t = """\
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 {0} {0}" stroke="none">
<rect width="100%" height="100%" fill="#F7F7F7"/>
<path d="{1}" fill="#111111"/>
</svg>
"""
return t.format(qr.size + border * 2, " ".join(parts))

View file

@ -27,9 +27,10 @@ if True: # pylint: disable=using-constant-test
from typing import Any, Optional, Union
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
from .authsrv import BAD_CFG, AuthSrv, n_du_who, n_ver_who
from .authsrv import BAD_CFG, AuthSrv, derive_args, n_du_who, n_ver_who
from .bos import bos
from .cert import ensure_cert
from .fsutil import ramdisk_chk
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
from .pwhash import HAVE_ARGON2
from .tcpsrv import TcpSrv
@ -66,6 +67,7 @@ from .util import (
build_netmap,
expat_ver,
gzip,
html_escape,
load_ipr,
load_ipu,
lock_file,
@ -77,6 +79,7 @@ from .util import (
start_stackmon,
termsize,
ub64enc,
umktrans,
)
if HAVE_SQLITE3:
@ -156,7 +159,7 @@ class SvcHub(object):
args.unpost = 0
args.no_del = True
args.no_mv = True
args.hardlink = True
args.reflink = True
args.dav_auth = True
args.vague_403 = True
args.nih = True
@ -217,6 +220,10 @@ class SvcHub(object):
self.log("root", t.format(args.j), c=3)
args.no_fpool = True
args.p_nodav = [int(x.strip()) for x in args.p_nodav.split(",") if x]
if args.dav_port and args.dav_port not in args.p:
args.p.append(args.dav_port)
for name, arg in (
("iobuf", "iobuf"),
("s-rd-sz", "s_rd_sz"),
@ -246,8 +253,8 @@ class SvcHub(object):
t = "WARNING: --th-ram-max is very small (%.2f GiB); will not be able to %s"
self.log("root", t % (args.th_ram_max, zs), 3)
if args.chpw and args.have_idp_hdrs:
t = "ERROR: user-changeable passwords is incompatible with IdP/identity-providers; you must disable either --chpw or --idp-h-usr"
if args.chpw and args.have_idp_hdrs and "pw" not in args.auth_ord.split(","):
t = "ERROR: user-changeable passwords is not compatible with your current configuration. Choose one of these options to fix it:\n option1: disable --chpw\n option2: remove all use of IdP features; --idp-*\n option3: change --auth-ord to something like pw,idp,ipu"
self.log("root", t, 1)
raise Exception(t)
@ -289,6 +296,9 @@ class SvcHub(object):
ch = "abcdefghijklmnopqrstuvwx"[int(args.theme / 2)]
args.theme = "{0}{1} {0} {1}".format(ch, bri)
if args.no_stack:
args.stack_who = "no"
if args.nid:
args.du_who = "no"
args.du_iwho = n_du_who(args.du_who)
@ -310,6 +320,7 @@ class SvcHub(object):
# initiate all services to manage
self.asrv = AuthSrv(self.args, self.log, dargs=self.dargs)
ramdisk_chk(self.asrv)
if args.cgen:
self.asrv.cgen()
@ -389,7 +400,10 @@ class SvcHub(object):
t = "invalid mp3 transcoding quality [%s] specified; only supports [0] to disable, a CBR value such as [192k], or a CQ/CRF value such as [v2]"
raise Exception(t % (args.q_mp3,))
else:
args.au_unpk = {}
zss = set(args.th_r_ffa.split(",") + args.th_r_ffv.split(","))
args.au_unpk = {
k: v for k, v in args.au_unpk.items() if v.split(".")[0] not in zss
}
args.th_poke = min(args.th_poke, args.th_maxage, args.ac_maxage)
@ -399,6 +413,11 @@ class SvcHub(object):
if not args.http_only:
zms += "D"
if args.sftp:
from .sftpd import Sftpd
self.sftpd: Optional[Sftpd] = None
if args.ftp or args.ftps:
from .ftpd import Ftpd
@ -410,7 +429,7 @@ class SvcHub(object):
self.tftpd: Optional[Tftpd] = None
if args.ftp or args.ftps or args.tftp:
if args.sftp or args.ftp or args.ftps or args.tftp:
Daemon(self.start_ftpd, "start_tftpd")
if args.smb:
@ -737,12 +756,28 @@ class SvcHub(object):
def start_ftpd(self) -> None:
time.sleep(30)
if hasattr(self, "sftpd") and not self.sftpd:
self.restart_sftpd()
if hasattr(self, "ftpd") and not self.ftpd:
self.restart_ftpd()
if hasattr(self, "tftpd") and not self.tftpd:
self.restart_tftpd()
def restart_sftpd(self) -> None:
if not hasattr(self, "sftpd"):
return
from .sftpd import Sftpd
if self.sftpd:
return # todo
self.sftpd = Sftpd(self)
self.sftpd.run()
self.log("root", "started SFTPd")
def restart_ftpd(self) -> None:
if not hasattr(self, "ftpd"):
return
@ -852,6 +887,10 @@ class SvcHub(object):
if w8:
time.sleep(w8)
self.log("qr-code", qr)
if self.args.qr_stdout:
self.pr(self.tcpsrv.qr)
if self.args.qr_stderr:
self.pr(self.tcpsrv.qr, file=sys.stderr)
w8 = self.args.qr_every
msg = "%s\033[%dA" % (qr, len(qr.split("\n")))
while w8:
@ -875,9 +914,9 @@ class SvcHub(object):
return
ar = self.args
for _ in range(10 if ar.ftp or ar.ftps else 0):
for _ in range(10 if ar.sftp or ar.ftp or ar.ftps else 0):
time.sleep(0.03)
if self.ftpd:
if self.ftpd if ar.ftp or ar.ftps else ar.sftp:
break
if self.tcpsrv.qr:
@ -885,8 +924,13 @@ class SvcHub(object):
self.sticky_qr()
if self.args.qr_wait or self.args.qr_every or self.args.qr_winch:
Daemon(self._qr_thr, "qr")
elif not self.args.qr_pin:
self.log("qr-code", self.tcpsrv.qr)
else:
if not self.args.qr_pin:
self.log("qr-code", self.tcpsrv.qr)
if self.args.qr_stdout:
self.pr(self.tcpsrv.qr)
if self.args.qr_stderr:
self.pr(self.tcpsrv.qr, file=sys.stderr)
else:
self.log("root", "workers OK\n")
@ -1063,13 +1107,13 @@ class SvcHub(object):
vs = os.path.expandvars(os.path.expanduser(vs))
setattr(al, k, vs)
for k in "idp_adm".split(" "):
for k in "idp_adm stats_u".split(" "):
vs = getattr(al, k)
vsa = [x.strip() for x in vs.split(",")]
vsa = [x.lower() for x in vsa if x]
setattr(al, k + "_set", set(vsa))
zs = "dav_ua1 sus_urls nonsus_urls ua_nodoc ua_nozip"
zs = "dav_ua1 sus_urls nonsus_urls ua_nodav ua_nodoc ua_nozip"
for k in zs.split(" "):
vs = getattr(al, k)
if not vs or vs == "no":
@ -1084,6 +1128,12 @@ class SvcHub(object):
else:
setattr(al, k, re.compile("^" + vs + "$"))
if al.banmsg.startswith("@"):
with open(al.banmsg[1:], "rb") as f:
al.banmsg_b = f.read()
else:
al.banmsg_b = al.banmsg.encode("utf-8") + b"\n"
if not al.sus_urls:
al.ban_url = "no"
elif al.ban_url == "no":
@ -1107,8 +1157,25 @@ class SvcHub(object):
except:
raise Exception("invalid --idp-hm-usr [%s]" % (zs0,))
al.ftp_ipa_nm = build_netmap(al.ftp_ipa or al.ipa, True)
al.tftp_ipa_nm = build_netmap(al.tftp_ipa or al.ipa, True)
zs1 = ""
zs2 = ""
zs = al.idp_chsub
while zs:
if zs[:1] != "|":
raise Exception("invalid --idp-chsub; expected another | but got " + zs)
zs1 += zs[1:2]
zs2 += zs[2:3]
zs = zs[3:]
al.idp_chsub_tr = umktrans(zs1, zs2)
al.sftp_ipa_nm = build_netmap(al.sftp_ipa or al.ipa or al.ipar, True)
al.ftp_ipa_nm = build_netmap(al.ftp_ipa or al.ipa or al.ipar, True)
al.tftp_ipa_nm = build_netmap(al.tftp_ipa or al.ipa or al.ipar, True)
al.sftp_key2u = {
"%s %s" % (x[1], x[2]): x[0]
for x in [x.split(" ") for x in al.sftp_key or []]
}
mte = ODict.fromkeys(DEF_MTE.split(","), True)
al.mte = odfusion(mte, al.mte)
@ -1157,6 +1224,13 @@ class SvcHub(object):
if len(al.tcolor) == 3: # fc5 => ffcc55
al.tcolor = "".join([x * 2 for x in al.tcolor])
if self.args.name_url:
zs = html_escape(self.args.name_url, True, True)
zs = '<a href="%s">%s</a>' % (zs, self.args.name)
else:
zs = self.args.name
self.args.name_html = zs
zs = al.u2sz
zsl = [x.strip() for x in zs.split(",")]
if len(zsl) not in (1, 3):
@ -1175,6 +1249,7 @@ class SvcHub(object):
zi2 = zi
al.u2sz = ",".join(zsl)
derive_args(al)
return True
def _ipa2re(self, txt) -> Optional[re.Pattern]:
@ -1350,6 +1425,7 @@ class SvcHub(object):
with self.reload_mutex:
self.log("root", "reloading config")
self.asrv.reload(9 if up2k else 4)
ramdisk_chk(self.asrv)
if up2k:
self.up2k.reload(rescan_all_vols)
t += "; volumes are now reinitializing"
@ -1525,6 +1601,9 @@ class SvcHub(object):
with self.log_mutex:
dt = datetime.now(self.tz)
if dt.day != self.cday or dt.month != self.cmon:
if self.args.log_date:
zs = dt.strftime(self.args.log_date)
self.log_efmt = "%s %s" % (zs, self.log_efmt.split(" ")[-1])
zs = "{}\n" if self.no_ansi else "\033[36m{}\033[0m\n"
zs = zs.format(dt.strftime("%Y-%m-%d"))
print(zs, end="")

View file

@ -8,7 +8,7 @@ import time
from .authsrv import AuthSrv
from .bos import bos
from .sutil import StreamArc, errdesc
from .util import min_ex, sanitize_fn, spack, sunpack, yieldfile, zlib
from .util import VPTL_WIN, min_ex, sanitize_to, spack, sunpack, yieldfile, zlib
if True: # pylint: disable=using-constant-test
from typing import Any, Generator, Optional
@ -104,7 +104,7 @@ def gen_hdr(
ret += spack(b"<LL", vsz, vsz)
# windows support (the "?" replace below too)
fn = sanitize_fn(fn, "/")
fn = sanitize_to(fn, VPTL_WIN)
bfn = fn.encode("utf-8" if utf8 else "cp437", "replace").replace(b"?", b"_")
# add ntfs (0x24) and/or unix (0x10) extrafields for utc, add z64 if requested

View file

@ -9,7 +9,7 @@ import time
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
from .cert import gencert
from .stolen.qrcodegen import QrCode, qr2svg
from .qrkode import QrCode, qr2png, qr2svg, qr2txt, qrgen
from .util import (
E_ACCESS,
E_ADDR_IN_USE,
@ -21,6 +21,7 @@ from .util import (
VF_CAREFUL,
Netdev,
atomic_move,
get_adapters,
min_ex,
sunpack,
termsize,
@ -59,6 +60,7 @@ class TcpSrv(object):
self.stopping = False
self.srv: list[socket.socket] = []
self.bound: list[tuple[str, int]] = []
self.seen_eps: list[tuple[str, int]] = [] # also skipped by uds-only
self.netdevs: dict[str, Netdev] = {}
self.netlist = ""
self.nsrv = 0
@ -299,6 +301,9 @@ class TcpSrv(object):
try:
if tcp:
if self.args.http_no_tcp:
self.seen_eps.append((ip, port))
return
srv.bind((ip, port))
else:
if ANYWIN or self.args.rm_sck:
@ -409,6 +414,7 @@ class TcpSrv(object):
self.srv = srvs
self.bound = bound
self.seen_eps = list(set(self.seen_eps + bound))
self.nsrv = len(srvs)
self._distribute_netdevs()
@ -416,6 +422,7 @@ class TcpSrv(object):
self.hub.broker.say("httpsrv.set_netdevs", self.netdevs)
self.hub.start_zeroconf()
gencert(self.log, self.args, self.netdevs)
self.hub.restart_sftpd()
self.hub.restart_ftpd()
self.hub.restart_tftpd()
@ -451,8 +458,6 @@ class TcpSrv(object):
self._distribute_netdevs()
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 not x.startswith(("unix:", "fd:"))]
nics = get_adapters(True)
@ -625,7 +630,7 @@ class TcpSrv(object):
pad = self.args.qrp
zoom = self.args.qrz
qrc = QrCode.encode_binary(btxt)
qrc = qrgen(btxt)
for zs in self.args.qr_file or []:
self._qr2file(qrc, zs)
@ -638,7 +643,7 @@ class TcpSrv(object):
except:
zoom = 1
qr = qrc.render(zoom, pad)
qr = qr2txt(qrc, zoom, pad)
if self.args.no_ansi:
return "{}\n{}".format(txt, qr)
@ -679,12 +684,12 @@ class TcpSrv(object):
if zoom not in (1, 2):
raise Exception("invalid zoom for qr.txt; must be 1 or 2")
with open(ap, "wb") as f:
f.write(qrc.render(zoom, pad).encode("utf-8"))
f.write(qr2txt(qrc, zoom, pad).encode("utf-8"))
elif ap.endswith(".svg"):
with open(ap, "wb") as f:
f.write(qr2svg(qrc, pad).encode("utf-8"))
else:
qrc.to_png(zoom, pad, self._h2i(bg), self._h2i(fg), ap)
qr2png(qrc, zoom, pad, self._h2i(bg), self._h2i(fg), ap)
def _h2i(self, hs):
try:

View file

@ -363,24 +363,29 @@ class Tftpd(object):
yeet("blocked write; folder not world-deletable: /%s" % (vpath,))
xbu = vfs.flags.get("xbu")
if xbu and not runhook(
self.nlog,
None,
self.hub.up2k,
"xbu.tftpd",
xbu,
ap,
vpath,
"",
"",
"",
0,
0,
"8.3.8.7",
time.time(),
"",
):
yeet("blocked by xbu server config: %r" % (vpath,))
if xbu:
hr = runhook(
self.nlog,
None,
self.hub.up2k,
"xbu.tftpd",
xbu,
ap,
vpath,
"",
"",
"",
0,
0,
"8.3.8.7",
time.time(),
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xbu server config: %r" % (vpath,)
yeet(t)
if not self.args.tftp_nols and bos.path.isdir(ap):
return self._ls(vpath, "", 0, True)

View file

@ -14,7 +14,7 @@ import time
from queue import Queue
from .__init__ import ANYWIN, PY2, TYPE_CHECKING
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
from .authsrv import VFS
from .bos import bos
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, ffprobe
@ -56,6 +56,56 @@ EXTS_SPEC_SAFE = set("aif aiff flac mp3 opus wav".split())
PTN_TS = re.compile("^-?[0-9a-f]{8,10}$")
# for n in {1..100}; do rm -rf /home/ed/Pictures/wp/.hist/th/ ; python3 -m copyparty -qv /home/ed/Pictures/wp/::r --th-no-webp --th-qv $n --th-dec pil >/dev/null 2>&1 & p=$!; printf '\033[A\033[J%3d ' $n; while true; do sleep 0.1; curl -s 127.1:3923 >/dev/null && break; done; curl -s '127.1:3923/?tar=j' >/dev/null ; cat /home/ed/Pictures/wp/.hist/th/1n/bs/1nBsjDetfie1iDq3y2D4YzF5/*.* | wc -c; kill $p; wait >/dev/null 2>&1; done
# filesize-equivalent, not quality (ff looks much shittier)
FF_JPG_Q = {
0: b"30", # 0
1: b"30", # 5
2: b"30", # 10
3: b"30", # 15
4: b"28", # 20
5: b"21", # 25
6: b"17", # 30
7: b"15", # 35
8: b"13", # 40
9: b"12", # 45
10: b"11", # 50
11: b"10", # 55
12: b"9", # 60
13: b"8", # 65
14: b"7", # 70
15: b"6", # 75
16: b"5", # 80
17: b"4", # 85
18: b"3", # 90
19: b"2", # 95
20: b"2", # 100
}
# FF_JPG_Q = {xn: ("%d" % (xn,)).encode("ascii") for xn in range(2, 33)}
VIPS_JPG_Q = {
0: 4, # 0
1: 7, # 5
2: 12, # 10
3: 17, # 15
4: 22, # 20
5: 27, # 25
6: 32, # 30
7: 37, # 35
8: 42, # 40
9: 47, # 45
10: 52, # 50
11: 56, # 55
12: 61, # 60
13: 66, # 65
14: 71, # 70
15: 75, # 75
16: 80, # 80
17: 85, # 85
18: 89, # 90 (vips explodes past this point)
19: 91, # 95
20: 97, # 100
}
try:
if os.environ.get("PRTY_NO_PIL"):
@ -270,6 +320,9 @@ class ThumbSrv(object):
def shutdown(self) -> None:
self.stopping = True
Daemon(self._fire_sentinels, "thumbstopper")
def _fire_sentinels(self):
for _ in range(self.nthr):
self.q.put(None)
@ -305,6 +358,7 @@ class ThumbSrv(object):
if not bos.path.exists(inf_path):
with open(inf_path, "wb") as f:
f.write(afsenc(os.path.dirname(abspath)))
self.writevolcfg(histpath)
self.busy[tpath] = [cond]
do_conv = True
@ -348,6 +402,47 @@ class ThumbSrv(object):
"ffa": self.fmt_ffa,
}
def volcfgi(self, vn: VFS) -> str:
ret = []
zs = "th_dec th_no_webp th_no_jpg"
for zs in zs.split(" "):
ret.append("%s(%s)\n" % (zs, getattr(self.args, zs)))
zs = "th_qv thsize th_spec_p convt"
for zs in zs.split(" "):
ret.append("%s(%s)\n" % (zs, vn.flags.get(zs)))
return "".join(ret)
def volcfga(self, vn: VFS) -> str:
ret = []
zs = "q_opus q_mp3"
for zs in zs.split(" "):
ret.append("%s(%s)\n" % (zs, getattr(self.args, zs)))
zs = "aconvt"
for zs in zs.split(" "):
ret.append("%s(%s)\n" % (zs, vn.flags.get(zs)))
return "".join(ret)
def writevolcfg(self, histpath: str) -> None:
try:
bos.stat(os.path.join(histpath, "th", "cfg.txt"))
bos.stat(os.path.join(histpath, "ac", "cfg.txt"))
return
except:
pass
cfgi = cfga = ""
for vn in self.asrv.vfs.all_vols.values():
if vn.histpath == histpath:
cfgi = self.volcfgi(vn)
cfga = self.volcfga(vn)
break
t = "writing thumbnailer-config %d,%d to %s"
self.log(t % (len(cfgi), len(cfga), histpath))
chmod = bos.MKD_700 if self.args.free_umask else bos.MKD_755
for cfg, cat in ((cfgi, "th"), (cfga, "ac")):
bos.makedirs(os.path.join(histpath, cat), vf=chmod)
with open(os.path.join(histpath, cat, "cfg.txt"), "wb") as f:
f.write(cfg.encode("utf-8"))
def wait4ram(self, need: float, ttpath: str) -> None:
ram = self.args.th_ram_max
if need > ram * 0.99:
@ -381,7 +476,7 @@ class ThumbSrv(object):
else:
ap_unpk = abspath
if not bos.path.exists(tpath):
if ap_unpk and not bos.path.exists(tpath):
tex = tpath.rsplit(".", 1)[-1]
want_mp3 = tex == "mp3"
want_opus = tex in ("opus", "owa", "caf")
@ -424,12 +519,14 @@ class ThumbSrv(object):
except:
pass
conv_ok = False
for fun in funs:
try:
if not png_ok and tpath.endswith(".png"):
raise Exception("png only allowed for waveforms")
fun(ap_unpk, ttpath, fmt, vn)
conv_ok = True
break
except Exception as ex:
msg = "%s could not create thumbnail of %r\n%s"
@ -451,16 +548,20 @@ class ThumbSrv(object):
except:
pass
if abspath != ap_unpk:
if abspath != ap_unpk and ap_unpk:
wunlink(self.log, ap_unpk, vn.flags)
try:
atomic_move(self.log, ttpath, tpath, vn.flags)
except Exception as ex:
if not os.path.exists(tpath):
if conv_ok and not os.path.exists(tpath):
t = "failed to move [%s] to [%s]: %r"
self.log(t % (ttpath, tpath, ex), 3)
pass
elif not conv_ok:
try:
open(tpath, "ab").close()
except:
pass
untemp = []
with self.mutex:
@ -520,7 +621,7 @@ class ThumbSrv(object):
im.thumbnail(self.getres(vn, fmt))
fmts = ["RGB", "L"]
args = {"quality": 40}
args = {"quality": vn.flags["th_qv"]}
if tpath.endswith(".webp"):
# quality 80 = pillow-default
@ -564,7 +665,12 @@ class ThumbSrv(object):
raise
assert img # type: ignore # !rm
img.write_to_file(tpath, Q=40)
args = {}
qv = vn.flags["th_qv"]
if tpath.endswith("jpg"):
qv = VIPS_JPG_Q[qv // 5]
args["optimize_coding"] = True
img.write_to_file(tpath, Q=qv, strip=True, **args)
def conv_raw(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
self.wait4ram(0.2, tpath)
@ -598,7 +704,12 @@ class ThumbSrv(object):
raise
assert img # type: ignore # !rm
img.write_to_file(tpath, Q=40)
args = {}
qv = vn.flags["th_qv"]
if tpath.endswith("jpg"):
qv = VIPS_JPG_Q[qv // 5]
args["optimize_coding"] = True
img.write_to_file(tpath, Q=qv, strip=True, **args)
elif HAVE_PIL:
if thumb.format == rawpy.ThumbFormat.BITMAP:
im = Image.fromarray(thumb.data, "RGB")
@ -662,12 +773,12 @@ class ThumbSrv(object):
if tpath.endswith(".jpg"):
cmd += [
b"-q:v",
b"6", # default=??
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
]
else:
cmd += [
b"-q:v",
b"50", # default=75
unicode(vn.flags["th_qv"]).encode("ascii"), # default=75
b"-compression_level:v",
b"6", # default=4, 0=fast, 6=max
]
@ -682,7 +793,7 @@ class ThumbSrv(object):
return
c: Union[str, int] = "90"
t = "FFmpeg failed (probably a corrupt video file):\n"
t = "FFmpeg failed (probably a corrupt file):\n"
if (
(not self.args.th_ff_jpg or time.time() - int(self.args.th_ff_jpg) < 60)
and cmd[-1].lower().endswith(b".webp")
@ -713,7 +824,7 @@ class ThumbSrv(object):
if len(lines) > 50:
lines = lines[:25] + ["[...]"] + lines[-25:]
txt = "\n".join(["ff: " + str(x) for x in lines])
txt = "\n".join(["ff: " + unicode(x) for x in lines])
if len(txt) > 5000:
txt = txt[:2500] + "...\nff: [...]\nff: ..." + txt[-2500:]
@ -871,12 +982,12 @@ class ThumbSrv(object):
if tpath.endswith(".jpg"):
cmd += [
b"-q:v",
b"6", # default=??
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
]
else:
cmd += [
b"-q:v",
b"50", # default=75
unicode(vn.flags["th_qv"]).encode("ascii"), # default=75
b"-compression_level:v",
b"6", # default=4, 0=fast, 6=max
]
@ -1134,7 +1245,7 @@ class ThumbSrv(object):
ret = []
for k, vs in raw_tags.items():
for v in vs:
if len(str(v)) >= 1024:
if len(unicode(v)) >= 1024:
bv = k.encode("utf-8", "replace")
ret += [b"-metadata", bv + b"="]
break
@ -1172,6 +1283,28 @@ class ThumbSrv(object):
time.sleep(interval)
def clean(self, histpath: str) -> int:
cfgi = cfga = ""
for vn in self.asrv.vfs.all_vols.values():
if vn.histpath == histpath:
cfgi = self.volcfgi(vn)
cfga = self.volcfga(vn)
break
for cfg, cat in ((cfgi, "th"), (cfga, "ac")):
if not cfg:
continue
try:
with open(os.path.join(histpath, cat, "cfg.txt"), "rb") as f:
oldcfg = f.read().decode("utf-8")
except:
oldcfg = ""
if cfg == oldcfg:
continue
zs = os.path.join(histpath, cat)
if not os.path.exists(zs):
continue
self.log("thumbnailer-config changed; deleting %s" % (zs,), 3)
shutil.rmtree(zs)
ret = 0
for cat in ["th", "ac"]:
top = os.path.join(histpath, cat)
@ -1230,7 +1363,7 @@ class ThumbSrv(object):
if len(b64) != 24 or len(ts) != 8 or ext not in exts:
raise Exception()
except:
if f != "dir.txt":
if f != "dir.txt" and f != "cfg.txt":
self.log("foreign file in thumbs dir: [{}]".format(fp), 1)
continue

View file

@ -53,6 +53,11 @@ class U2idx(object):
self.log("your python does not have sqlite3; searching will be disabled")
return
if self.args.srch_icase:
self._open_db = self._open_db_icase
else:
self._open_db = self._open_db_std
assert sqlite3 # type: ignore # !rm
self.active_id = ""
@ -69,6 +74,16 @@ class U2idx(object):
def log(self, msg: str, c: Union[int, str] = 0) -> None:
self.log_func("u2idx", msg, c)
def _open_db_std(self, *args, **kwargs):
assert sqlite3 # type: ignore # !rm
kwargs["check_same_thread"] = False
return sqlite3.connect(*args, **kwargs)
def _open_db_icase(self, *args, **kwargs):
db = self._open_db_std(*args, **kwargs)
db.create_function("casefold", 1, lambda x: x.casefold() if x else x)
return db
def shutdown(self) -> None:
if not HAVE_SQLITE3:
return
@ -148,8 +163,7 @@ class U2idx(object):
uri = ""
try:
uri = "{}?mode=ro&nolock=1".format(Path(db_path).as_uri())
db = sqlite3.connect(uri, timeout=2, uri=True, check_same_thread=False)
cur = db.cursor()
cur = self._open_db(uri, timeout=2, uri=True).cursor()
cur.execute('pragma table_info("up")').fetchone()
self.log("ro: %r" % (db_path,))
except:
@ -160,7 +174,7 @@ class U2idx(object):
if not cur:
# on windows, this steals the write-lock from up2k.deferred_init --
# seen on win 10.0.17763.2686, py 3.10.4, sqlite 3.37.2
cur = sqlite3.connect(db_path, timeout=2, check_same_thread=False).cursor()
cur = self._open_db(db_path, timeout=2).cursor()
self.log("opened %r" % (db_path,))
self.cur[ptop] = cur
@ -173,6 +187,8 @@ class U2idx(object):
if not HAVE_SQLITE3:
return [], [], False
icase = self.args.srch_icase
q = ""
v: Union[str, int] = ""
va: list[Union[str, int]] = []
@ -180,6 +196,7 @@ class U2idx(object):
is_key = True
is_size = False
is_date = False
is_wark = False
field_end = "" # closing parenthesis or whatever
kw_key = ["(", ")", "and ", "or ", "not "]
kw_val = ["==", "=", "!=", ">", ">=", "<", "<=", "like "]
@ -198,6 +215,8 @@ class U2idx(object):
is_key = kw in kw_key
uq = uq[len(kw) :]
ok = True
if is_wark:
kw = "= "
q += kw
break
@ -232,9 +251,17 @@ class U2idx(object):
elif v == "path":
v = "trim(?||up.rd,'/')"
va.append("\nrd")
if icase:
v = "casefold(%s)" % (v,)
elif v == "name":
v = "up.fn"
if icase:
v = "casefold(%s)" % (v,)
elif v == "w":
v = "substr(up.w,1,16)"
is_wark = True
elif v == "tags" or ptn_mt.match(v):
have_mt = True
@ -247,7 +274,7 @@ class U2idx(object):
v = "exists(select 1 from mt where mt.w = mtw and " + vq
else:
raise Pebkac(400, "invalid key [{}]".format(v))
raise Pebkac(400, "invalid key %r" % (v,))
q += v + " "
continue
@ -276,6 +303,14 @@ class U2idx(object):
is_size = False
v = int(float(v) * 1024 * 1024)
elif is_wark:
is_wark = False
v = v.strip("*")
if len(v) > 16:
v = v[:16]
if len(v) < 16:
raise Pebkac(400, "w/filehash must be 16+ chars")
else:
if v.startswith("*"):
head = "'%'||"
@ -285,6 +320,12 @@ class U2idx(object):
tail = "||'%'"
v = v[:-1]
if icase and "casefold(" in q:
try:
v = unicode(v).casefold()
except:
v = unicode(v).lower()
q += " {}?{} ".format(head, tail)
va.append(v)
is_key = True
@ -319,7 +360,7 @@ class U2idx(object):
uname: str,
vols: list[VFS],
uq: str,
uv: list[Union[str, int]],
uv: Union[list[str], list[Union[str, int]]],
have_mt: bool,
sort: bool,
lim: int,

View file

@ -10,6 +10,7 @@ import re
import shutil
import stat
import subprocess as sp
import sys
import tempfile
import threading
import time
@ -18,13 +19,16 @@ from copy import deepcopy
from queue import Queue
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, WINDOWS, E
from .__init__ import ANYWIN, MACOS, PY2, TYPE_CHECKING, WINDOWS, E
from .authsrv import LEELOO_DALLAS, SEESLOG, VFS, AuthSrv
from .bos import bos
from .cfg import vf_bmap, vf_cmap, vf_vmap
from .fsutil import Fstab
from .mtag import MParser, MTag
from .util import (
E_FS_CRIT,
E_FS_MEH,
HAVE_FICLONE,
HAVE_SQLITE3,
SYMTIME,
VF_CAREFUL,
@ -60,6 +64,7 @@ from .util import (
sfsenc,
spack,
statdir,
trystat_shutil_copy2,
ub64enc,
unhumanize,
vjoin,
@ -85,13 +90,17 @@ if True: # pylint: disable=using-constant-test
if TYPE_CHECKING:
from .svchub import SvcHub
USE_FICLONE = HAVE_FICLONE and sys.version_info < (3, 14)
if USE_FICLONE:
import fcntl
zsg = "avif,avifs,bmp,gif,heic,heics,heif,heifs,ico,j2p,j2k,jp2,jpeg,jpg,jpx,png,tga,tif,tiff,webp"
ICV_EXTS = set(zsg.split(","))
zsg = "3gp,asf,av1,avc,avi,flv,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,vob,webm,wmv"
VCV_EXTS = set(zsg.split(","))
zsg = "aif,aiff,alac,ape,flac,m4a,mp3,oga,ogg,opus,tak,tta,wav,wma,wv"
zsg = "aif,aiff,alac,ape,flac,m4a,mp3,oga,ogg,opus,tak,tta,wav,wma,wv,cbz,epub"
ACV_EXTS = set(zsg.split(","))
zsg = "nohash noidx xdev xvol"
@ -212,7 +221,7 @@ class Up2k(object):
t = "could not initialize sqlite3, will use in-memory registry only"
self.log(t, 3)
self.fstab = Fstab(self.log_func, self.args)
self.fstab = Fstab(self.log_func, self.args, True)
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
if self.args.hash_mt < 2:
@ -1139,7 +1148,7 @@ class Up2k(object):
ft = "\033[0;32m{}{:.0}"
ff = "\033[0;35m{}{:.0}"
fv = "\033[0;36m{}:\033[90m{}"
zs = "du_iwho ext_th_d html_head put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
zs = "bcasechk du_iwho emb_lgs emb_mds ext_th_d html_head html_head_d html_head_s ls_q_m put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
fx = set(zs.split())
fd = vf_bmap()
fd.update(vf_cmap())
@ -1498,6 +1507,7 @@ class Up2k(object):
th_cvd = self.args.th_coversd
th_cvds = self.args.th_coversd_set
scan_pr_s = self.args.scan_pr_s
assert self.pp and self.mem_cur # !rm
self.pp.msg = "a%d %s" % (self.pp.n, cdir)
@ -1710,7 +1720,7 @@ class Up2k(object):
if nohash or not sz:
wark = up2k_wark_from_metadata(self.salt, sz, lmod, rd, fn)
else:
if sz > 1024 * 1024:
if sz > 1024 * 1024 * scan_pr_s:
self.log("file: %r" % (abspath,))
try:
@ -1718,7 +1728,7 @@ class Up2k(object):
abspath, "a{}, ".format(self.pp.n)
)
except Exception as ex:
self.log("hash: %r @ %r" % (ex, abspath))
self._ex_hash(ex, abspath)
continue
if not hashes:
@ -1979,7 +1989,7 @@ class Up2k(object):
try:
hashes, _ = self._hashlist_from_file(abspath, pf)
except Exception as ex:
self.log("hash: %r @ %r" % (ex, abspath))
self._ex_hash(ex, abspath)
continue
if not hashes:
@ -2768,7 +2778,7 @@ class Up2k(object):
cur.close()
db.close()
shutil.copy2(fsenc(db_path), fsenc(bak))
trystat_shutil_copy2(self.log, fsenc(db_path), fsenc(bak))
return self._orz(db_path)
def _read_ver(self, cur: "sqlite3.Cursor") -> Optional[int]:
@ -3005,7 +3015,7 @@ class Up2k(object):
# check if filesystem supports sparse files;
# refuse out-of-order / multithreaded uploading if sprs False
sprs = self.fstab.get(pdir) != "ng"
sprs = self.fstab.get(pdir)[0] != "ng"
if True:
jcur = self.cur.get(ptop)
@ -3294,10 +3304,13 @@ class Up2k(object):
job["size"],
job["addr"],
job["at"],
"",
None,
)
if not hr:
t = "upload blocked by xbu server config: %r" % (dst,)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xbu server config: %r"
t = t % (vp,)
self.log(t, 1)
raise Pebkac(403, t)
if hr.get("reloc"):
@ -3310,7 +3323,7 @@ class Up2k(object):
job["ptop"] = vfs.realpath
job["vtop"] = vfs.vpath
job["prel"] = rem
job["name"] = sanitize_fn(job["name"], "")
job["name"] = sanitize_fn(job["name"])
ud2 = (vfs.vpath, job["prel"], job["name"])
if ud1 != ud2:
# print(json.dumps(job, sort_keys=True, indent=4))
@ -3455,7 +3468,15 @@ class Up2k(object):
fp = djoin(fdir, fname)
ow = job.get("replace") and bos.path.exists(fp)
if ow and "mt" in str(job["replace"]).lower():
if ow:
replace_arg = str(job["replace"]).lower()
if ow and "skip" in replace_arg: # type: ignore
self.log("skipping upload, filename already exists: %r" % fp)
err = "upload rejected, a file with that name already exists"
raise Pebkac(409, err)
if ow and "mt" in replace_arg: # type: ignore
mts = bos.stat(fp).st_mtime
mtc = job["lmod"]
if mtc < mts:
@ -3523,11 +3544,26 @@ class Up2k(object):
linked = False
try:
if "reflink" in flags:
raise Exception("reflink")
if rm and bos.path.exists(dst):
wunlink(self.log, dst, flags)
if not is_mv and not flags.get("dedup"):
raise Exception("dedup is disabled in config")
if "reflink" in flags:
if not USE_FICLONE:
raise Exception("reflink") # python 3.14 or newer; no need
try:
with open(fsenc(src), "rb") as fi, open(fsenc(dst), "wb") as fo:
fcntl.ioctl(fo.fileno(), fcntl.FICLONE, fi.fileno())
except:
if bos.path.exists(dst):
wunlink(self.log, dst, flags)
raise
if lmod:
bos.utime_c(self.log, dst, int(lmod), False)
return
lsrc = src
ldst = dst
fs1 = bos.stat(os.path.dirname(src)).st_dev
@ -3554,9 +3590,6 @@ class Up2k(object):
lsrc = lsrc.replace("/", "\\")
ldst = ldst.replace("/", "\\")
if rm and bos.path.exists(dst):
wunlink(self.log, dst, flags)
try:
if "hardlink" in flags:
os.link(fsenc(absreal(src)), fsenc(dst))
@ -3591,7 +3624,7 @@ class Up2k(object):
t = "BUG: no valid sources to link from! orig(%r) fsrc(%r) link(%r)"
self.log(t, 1)
raise Exception(t % (src, fsrc, dst))
shutil.copy2(fsenc(csrc), fsenc(dst))
trystat_shutil_copy2(self.log, fsenc(csrc), fsenc(dst))
if lmod and (not linked or SYMTIME):
bos.utime_c(self.log, dst, int(lmod), False)
@ -3677,14 +3710,15 @@ class Up2k(object):
t = t.format(job["name"], nchunks[0][0], coffsets[0][0], cur_sz)
raise Pebkac(400, t)
job["busy"][chash] = 1
for chash in chashes:
job["busy"][chash] = 1
job["poke"] = time.time()
return chashes, chunksize, coffsets, path, job["lmod"], job["size"], job["sprs"]
def fast_confirm_chunks(
self, ptop: str, wark: str, chashes: list[str]
self, ptop: str, wark: str, chashes: list[str], locked: list[str]
) -> tuple[int, str]:
if not self.mutex.acquire(False):
return -1, ""
@ -3692,7 +3726,7 @@ class Up2k(object):
self.mutex.release()
return -1, ""
try:
return self._confirm_chunks(ptop, wark, chashes, chashes)
return self._confirm_chunks(ptop, wark, chashes, locked, False)
finally:
self.reg_mutex.release()
self.mutex.release()
@ -3701,10 +3735,10 @@ class Up2k(object):
self, ptop: str, wark: str, written: list[str], locked: list[str]
) -> tuple[int, str]:
with self.mutex, self.reg_mutex:
return self._confirm_chunks(ptop, wark, written, locked)
return self._confirm_chunks(ptop, wark, written, locked, True)
def _confirm_chunks(
self, ptop: str, wark: str, written: list[str], locked: list[str]
self, ptop: str, wark: str, written: list[str], locked: list[str], final: bool
) -> tuple[int, str]:
if True:
self.db_act = self.vol_act[ptop] = time.time()
@ -3716,14 +3750,16 @@ class Up2k(object):
except Exception as ex:
return -2, "confirm_chunk, wark(%r)" % (ex,) # type: ignore
for chash in locked:
for chash in locked if final else written:
job["busy"].pop(chash, None)
try:
for chash in written:
job["need"].remove(chash)
except Exception as ex:
# dead tcp connections can get here by timeout (OK)
for zs in locked:
if job["busy"].pop(zs, None):
self.log("panic-unlock wark(%s) chunk(%s)" % (wark, zs), 1)
return -2, "confirm_chunk, chash(%s) %r" % (chash, ex) # type: ignore
ret = len(job["need"])
@ -3972,10 +4008,13 @@ class Up2k(object):
sz,
ip,
at or time.time(),
"",
None,
)
if not hr:
t = "upload blocked by xau server config"
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xau server config: %r"
t = t % (djoin(vtop, rd, fn),)
self.log(t, 1)
wunlink(self.log, dst, vflags)
self.registry[ptop].pop(wark, None)
@ -4145,6 +4184,9 @@ class Up2k(object):
except:
raise Pebkac(400, "file not found on disk (already deleted?)")
if "bcasechk" in vn.flags and not vn.casechk(rem, False):
raise Pebkac(400, "file does not exist case-sensitively")
scandir = not self.args.no_scandir
if is_dir:
# note: deletion inside shares would require a rewrite here;
@ -4187,7 +4229,7 @@ class Up2k(object):
_ = dbv.get(volpath, uname, *permsets[0])
if xbd:
if not runhook(
hr = runhook(
self.log,
None,
self,
@ -4202,10 +4244,13 @@ class Up2k(object):
st.st_size,
ip,
time.time(),
"",
):
t = "delete blocked by xbd server config: %r"
self.log(t % (abspath,), 1)
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "delete blocked by xbd server config: %r" % (abspath,)
self.log(t, 1)
continue
n_files += 1
@ -4242,7 +4287,7 @@ class Up2k(object):
st.st_size,
ip,
time.time(),
"",
None,
)
if is_dir:
@ -4269,6 +4314,9 @@ class Up2k(object):
self.db_act = self.vol_act[svn_dbv.realpath] = time.time()
st = bos.stat(sabs)
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
raise Pebkac(400, "file does not exist case-sensitively")
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
with self.mutex:
try:
@ -4352,7 +4400,7 @@ class Up2k(object):
xbc = svn.flags.get("xbc")
xac = dvn.flags.get("xac")
if xbc:
if not runhook(
hr = runhook(
self.log,
None,
self,
@ -4367,9 +4415,12 @@ class Up2k(object):
fsize,
ip,
time.time(),
"",
):
t = "copy blocked by xbr server config: %r" % (svp,)
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "copy blocked by xbr server config: %r" % (svp,)
self.log(t, 1)
raise Pebkac(405, t)
@ -4427,7 +4478,7 @@ class Up2k(object):
b1, b2 = fsenc(sabs), fsenc(dabs)
is_link = os.path.islink(b1) # due to _relink
try:
shutil.copy2(b1, b2)
trystat_shutil_copy2(self.log, b1, b2)
except:
try:
wunlink(self.log, dabs, dvn.flags)
@ -4468,7 +4519,7 @@ class Up2k(object):
fsize,
ip,
time.time(),
"",
None,
)
return "k"
@ -4487,6 +4538,9 @@ class Up2k(object):
raise Pebkac(400, "mv: cannot move a mountpoint")
st = bos.lstat(sabs)
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
raise Pebkac(400, "file does not exist case-sensitively")
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
with self.mutex:
try:
@ -4601,7 +4655,7 @@ class Up2k(object):
xbr = svn.flags.get("xbr")
xar = dvn.flags.get("xar")
if xbr:
if not runhook(
hr = runhook(
self.log,
None,
self,
@ -4616,9 +4670,12 @@ class Up2k(object):
fsize,
ip,
time.time(),
"",
):
t = "move blocked by xbr server config: %r" % (svp,)
None,
)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "move blocked by xbr server config: %r" % (svp,)
self.log(t, 1)
raise Pebkac(405, t)
@ -4656,7 +4713,7 @@ class Up2k(object):
fsize,
ip,
time.time(),
"",
None,
)
return "k"
@ -4668,6 +4725,12 @@ class Up2k(object):
if w:
assert c1 # !rm
if c2 and c2 != c1:
if "nodupem" in dvn.flags:
q = "select w from up where substr(w,1,16) = ?"
for (w2,) in c2.execute(q, (w[:16],)):
if w == w2:
t = "file exists in target volume, and dupes are forbidden in config"
raise Pebkac(400, t)
self._copy_tags(c1, c2, w)
xlink = bool(svn.flags.get("xlink"))
@ -4733,7 +4796,7 @@ class Up2k(object):
b1, b2 = fsenc(sabs), fsenc(dabs)
is_link = os.path.islink(b1) # due to _relink
try:
shutil.copy2(b1, b2)
trystat_shutil_copy2(self.log, b1, b2)
except:
try:
wunlink(self.log, dabs, dvn.flags)
@ -4776,7 +4839,7 @@ class Up2k(object):
fsize,
ip,
time.time(),
"",
None,
)
return "k"
@ -5016,7 +5079,7 @@ class Up2k(object):
for k in cj["hash"]:
if not self.r_hash.match(k):
raise Pebkac(
400, "at least one hash is not according to spec: {}".format(k)
400, "at least one hash is not according to spec: %r" % (k,)
)
# try to use client-provided timestamp, don't care if it fails somehow
@ -5073,6 +5136,16 @@ class Up2k(object):
return ret, st
def _ex_hash(self, ex: Exception, ap: str) -> None:
eno = getattr(ex, "errno", 0)
if eno in E_FS_MEH:
return self.log("hashing failed; %r @ %r" % (ex, ap))
if eno not in E_FS_CRIT:
return self.log("hashing failed; %r @ %r\n%s" % (ex, ap, min_ex()), 3)
t = "hashing failed; %r @ %r\n%s\nWARNING: This MAY indicate a serious issue with your harddisk or filesystem! Please investigate %sOS-logs\n"
t2 = "" if ANYWIN or MACOS else "dmesg and "
return self.log(t % (ex, ap, min_ex(), t2), 1)
def _new_upload(self, job: dict[str, Any], vfs: VFS, depth: int) -> dict[str, str]:
pdir = djoin(job["ptop"], job["prel"])
if not job["size"]:
@ -5104,10 +5177,12 @@ class Up2k(object):
job["size"],
job["addr"],
job["t0"],
"",
None,
)
if not hr:
t = "upload blocked by xbu server config: %r" % (vp_chk,)
t = hr.get("rejectmsg") or ""
if t or hr.get("rc") != 0:
if not t:
t = "upload blocked by xbu server config: %r" % (vp_chk,)
self.log(t, 1)
raise Pebkac(403, t)
if hr.get("reloc"):
@ -5119,7 +5194,7 @@ class Up2k(object):
job["ptop"] = vfs.realpath
job["vtop"] = vfs.vpath
job["prel"] = rem
job["name"] = sanitize_fn(job["name"], "")
job["name"] = sanitize_fn(job["name"])
ud2 = (vfs.vpath, job["prel"], job["name"])
if ud1 != ud2:
self.log("xbu reloc2:%d..." % (depth,), 6)
@ -5169,7 +5244,7 @@ class Up2k(object):
sprs = False
if not ANYWIN and sprs and sz > 1024 * 1024:
fs = self.fstab.get(pdir)
fs, mnt = self.fstab.get(pdir)
if fs == "ok":
pass
elif "nosparse" in vf:
@ -5255,17 +5330,21 @@ class Up2k(object):
self.log("\n".join([t] + vis))
for job in rm:
del reg[job["wark"]]
rsv_cleared = False
try:
# remove the filename reservation
path = djoin(job["ptop"], job["prel"], job["name"])
if bos.path.getsize(path) == 0:
bos.unlink(path)
rsv_cleared = True
except:
pass
try:
if len(job["hash"]) == len(job["need"]):
# PARTIAL is empty, delete that too
if len(job["hash"]) == len(job["need"]) or (
rsv_cleared and "rm_partial" in self.flags[job["ptop"]]
):
# PARTIAL is empty (hash==need) or --rm-partial, so delete that too
path = djoin(job["ptop"], job["prel"], job["tnam"])
bos.unlink(path)
except:

View file

@ -55,7 +55,6 @@ from .__init__ import (
unicode,
)
from .__version__ import S_BUILD_DT, S_VERSION
from .stolen import surrogateescape
try:
from datetime import datetime, timezone
@ -81,6 +80,9 @@ except:
if PY2:
range = xrange # type: ignore
from .stolen import surrogateescape
surrogateescape.register_surrogateescape()
if sys.version_info >= (3, 7) or (
@ -111,6 +113,8 @@ E_ADDR_NOT_AVAIL = _ens("EADDRNOTAVAIL WSAEADDRNOTAVAIL")
E_ADDR_IN_USE = _ens("EADDRINUSE WSAEADDRINUSE")
E_ACCESS = _ens("EACCES WSAEACCES")
E_UNREACH = _ens("EHOSTUNREACH WSAEHOSTUNREACH ENETUNREACH WSAENETUNREACH")
E_FS_MEH = _ens("EPERM EACCES ENOENT ENOTCAPABLE")
E_FS_CRIT = _ens("EIO EFAULT EUCLEAN ENOTBLK")
IP6ALL = "0:0:0:0:0:0:0:0"
IP6_LL = ("fe8", "fe9", "fea", "feb")
@ -125,8 +129,10 @@ try:
import fcntl
HAVE_FCNTL = True
HAVE_FICLONE = hasattr(fcntl, "FICLONE")
except:
HAVE_FCNTL = False
HAVE_FICLONE = False
try:
import ctypes
@ -134,6 +140,25 @@ try:
except:
pass
try:
if os.environ.get("PRTY_NO_IFADDR"):
raise Exception()
try:
if os.getenv("PRTY_SYS_ALL") or os.getenv("PRTY_SYS_IFADDR"):
raise ImportError()
from .stolen.ifaddr import get_adapters
except ImportError:
from ifaddr import get_adapters
HAVE_IFADDR = True
except:
HAVE_IFADDR = False
def get_adapters(include_unconfigured=False):
return []
try:
if os.environ.get("PRTY_NO_SQLITE"):
raise Exception()
@ -171,6 +196,11 @@ try:
except:
pass
if os.getenv("PRTY_MODSPEC"):
from inspect import getsourcefile
print("PRTY_MODSPEC: ifaddr:", getsourcefile(get_adapters))
if True: # pylint: disable=using-constant-test
import types
from collections.abc import Callable, Iterable
@ -264,10 +294,26 @@ RE_MEMTOTAL = re.compile("^MemTotal:.* kB")
RE_MEMAVAIL = re.compile("^MemAvailable:.* kB")
if PY2:
def umktrans(s1, s2):
return {ord(c1): ord(c2) for c1, c2 in zip(s1, s2)}
else:
umktrans = str.maketrans
FNTL_WIN = umktrans('<>:|?*"\\/', "")
VPTL_WIN = umktrans('<>:|?*"\\', "")
APTL_WIN = umktrans('<>:|?*"/', "")
FNTL_MAC = VPTL_MAC = APTL_MAC = umktrans(":", "")
FNTL_OS = FNTL_WIN if ANYWIN else FNTL_MAC if MACOS else None
VPTL_OS = VPTL_WIN if ANYWIN else VPTL_MAC if MACOS else None
APTL_OS = APTL_WIN if ANYWIN else APTL_MAC if MACOS else None
BOS_SEP = ("%s" % (os.sep,)).encode("ascii")
surrogateescape.register_surrogateescape()
if WINDOWS and PY2:
FS_ENCODING = "utf-8"
else:
@ -329,6 +375,8 @@ IMPLICATIONS = [
["hardlink_only", "hardlink"],
["hardlink", "dedup"],
["tftpvv", "tftpv"],
["nodupem", "nodupe"],
["no_dupe_m", "no_dupe"],
["smbw", "smb"],
["smb1", "smb"],
["smbvvv", "smbvv"],
@ -376,6 +424,13 @@ DAV_ALLPROP_L = [
DAV_ALLPROPS = set(DAV_ALLPROP_L)
FAVICON_MIMES = {
"gif": "image/gif",
"png": "image/png",
"svg": "image/svg+xml",
}
MIMES = {
"opus": "audio/ogg; codecs=opus",
"owa": "audio/webm; codecs=opus",
@ -430,11 +485,11 @@ EXTS["vnd.mozilla.apng"] = "png"
MAGIC_MAP = {"jpeg": "jpg"}
DEF_EXP = "self.ip self.ua self.uname self.host cfg.name cfg.logout vf.scan vf.thsize hdr.cf_ipcountry srv.itime srv.htime"
DEF_EXP = "self.ip self.ua self.uname self.host cfg.name cfg.logout vf.scan vf.thsize hdr.cf-ipcountry srv.itime srv.htime"
DEF_MTE = ".files,circle,album,.tn,artist,title,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash"
DEF_MTE = ".files,circle,album,.tn,artist,title,tdate,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash"
DEF_MTH = ".vq,.aq,vc,ac,fmt,res,.fps"
DEF_MTH = "tdate,.vq,.aq,vc,ac,fmt,res,.fps"
REKOBO_KEY = {
@ -546,6 +601,8 @@ def py_desc() -> str:
ofs = py_ver.find(".final.")
if ofs > 0:
py_ver = py_ver[:ofs]
if "free-threading" in sys.version:
py_ver += "t"
host_os = platform.system()
compiler = platform.python_compiler().split("http")[0]
@ -597,22 +654,41 @@ except:
JINJA_VER = "(None)"
try:
if os.environ.get("PRTY_NO_PYFTPD"):
raise Exception()
from pyftpdlib.__init__ import __ver__ as PYFTPD_VER
except:
PYFTPD_VER = "(None)"
try:
if os.environ.get("PRTY_NO_PARTFTPY"):
raise Exception()
from partftpy.__init__ import __version__ as PARTFTPY_VER
except:
PARTFTPY_VER = "(None)"
try:
if os.environ.get("PRTY_NO_PARAMIKO"):
raise Exception()
from paramiko import __version__ as MIKO_VER
except:
MIKO_VER = "(None)"
PY_DESC = py_desc()
VERSIONS = (
"copyparty v{} ({})\n{}\n sqlite {} | jinja {} | pyftpd {} | tftp {}".format(
S_VERSION, S_BUILD_DT, PY_DESC, SQLITE_VER, JINJA_VER, PYFTPD_VER, PARTFTPY_VER
)
VERSIONS = "copyparty v{} ({})\n{}\n sqlite {} | jinja {} | pyftpd {} | tftp {} | miko {}".format(
S_VERSION,
S_BUILD_DT,
PY_DESC,
SQLITE_VER,
JINJA_VER,
PYFTPD_VER,
PARTFTPY_VER,
MIKO_VER,
)
@ -644,7 +720,7 @@ except Exception as ex:
ub64dec = base64.urlsafe_b64decode # type: ignore
b64enc = base64.b64encode # type: ignore
b64dec = base64.b64decode # type: ignore
if not PY36:
if PY36:
print("using fallback base64 codec due to %r" % (ex,))
@ -656,6 +732,9 @@ def read_utf8(log: Optional["NamedLogger"], ap: Union[str, bytes], strict: bool)
with open(ap, "rb") as f:
buf = f.read()
if buf.startswith(b"\xef\xbb\xbf"):
buf = buf[3:]
try:
return buf.decode("utf-8", "strict")
except UnicodeDecodeError as ex:
@ -1121,16 +1200,18 @@ class ProgressPrinter(threading.Thread):
sigblock()
tp = 0
msg = None
no_stdout = self.args.q
slp_pr = self.args.scan_pr_r
slp_ps = min(slp_pr, self.args.scan_st_r)
no_stdout = self.args.q or slp_pr == slp_ps
fmt = " {}\033[K\r" if VT100 else " {} $\r"
while not self.end:
time.sleep(0.1)
time.sleep(slp_ps)
if msg == self.msg or self.end:
continue
msg = self.msg
now = time.time()
if msg and now - tp > 10:
if msg and now - tp >= slp_pr:
tp = now
self.log("progress: %r" % (msg,), 6)
@ -1188,21 +1269,21 @@ class MTHash(object):
for nch in range(nchunks):
self.work_q.put(nch)
ex = ""
ex: Optional[Exception] = None
for nch in range(nchunks):
qe = self.done_q.get()
try:
nch, dig, ofs, csz = qe
chunks[nch] = (dig, ofs, csz)
except:
ex = ex or str(qe)
ex = ex or qe # type: ignore
if pp:
mb = (fsz - nch * chunksz) // (1024 * 1024)
pp.msg = prefix + str(mb) + suffix
if ex:
raise Exception(ex)
raise ex
ret = []
for n in range(nchunks):
@ -1219,7 +1300,7 @@ class MTHash(object):
try:
v = self.hash_at(ofs)
except Exception as ex:
v = str(ex) # type: ignore
v = ex # type: ignore
self.done_q.put(v)
@ -1457,20 +1538,24 @@ def trace(*args: Any, **kwargs: Any) -> None:
nuprint(msg)
def alltrace() -> str:
def alltrace(verbose: bool = True) -> str:
threads: dict[str, types.FrameType] = {}
names = dict([(t.ident, t.name) for t in threading.enumerate()])
for tid, stack in sys._current_frames().items():
name = "%s (%x)" % (names.get(tid), tid)
if verbose:
name = "%s (%x)" % (names.get(tid), tid)
else:
name = str(names.get(tid))
threads[name] = stack
rret: list[str] = []
bret: list[str] = []
np = -3 if verbose else -2
for name, stack in sorted(threads.items()):
ret = ["\n\n# %s" % (name,)]
pad = None
for fn, lno, name, line in traceback.extract_stack(stack):
fn = os.sep.join(fn.split(os.sep)[-3:])
fn = os.sep.join(fn.split(os.sep)[np:])
ret.append('File: "%s", line %d, in %s' % (fn, lno, name))
if line:
ret.append(" " + str(line.strip()))
@ -1577,10 +1662,12 @@ def vol_san(vols: list["VFS"], txt: bytes) -> bytes:
bvp = vol.vpath.encode("utf-8")
bvph = b"$hist(/" + bvp + b")"
txt = txt.replace(bap, bvp)
txt = txt.replace(bhp, bvph)
txt = txt.replace(bap.replace(b"\\", b"\\\\"), bvp)
txt = txt.replace(bhp.replace(b"\\", b"\\\\"), bvph)
if bap:
txt = txt.replace(bap, bvp)
txt = txt.replace(bap.replace(b"\\", b"\\\\"), bvp)
if bhp:
txt = txt.replace(bhp, bvph)
txt = txt.replace(bhp.replace(b"\\", b"\\\\"), bvph)
if vol.histpath != vol.dbpath:
bdp = vol.dbpath.encode("utf-8")
@ -1759,12 +1846,12 @@ class MultipartParser(object):
continue
if m.group(1).lower() != "form-data":
raise Pebkac(400, "not form-data: {}".format(ln))
raise Pebkac(400, "not form-data: %r" % (ln,))
try:
field = self.re_cdisp_field.match(ln).group(1) # type: ignore
except:
raise Pebkac(400, "missing field name: {}".format(ln))
raise Pebkac(400, "missing field name: %r" % (ln,))
try:
fn = self.re_cdisp_file.match(ln).group(1) # type: ignore
@ -1936,7 +2023,7 @@ def get_boundary(headers: dict[str, str]) -> str:
ct = headers["content-type"]
m = re.match(ptn, ct, re.IGNORECASE)
if not m:
raise Pebkac(400, "invalid content-type for a multipart post: {}".format(ct))
raise Pebkac(400, "invalid content-type for a multipart post: %r" % (ct,))
return m.group(2)
@ -2108,6 +2195,7 @@ def humansize(sz: float, terse: bool = False) -> str:
sz /= 1024.0
assert unit # type: ignore # !rm
if terse:
return "%s%s" % (str(sz)[:4].rstrip("."), unit[:1])
else:
@ -2176,38 +2264,30 @@ def undot(path: str) -> str:
return "/".join(ret)
def sanitize_fn(fn: str, ok: str) -> str:
if "/" not in ok:
fn = fn.replace("\\", "/").split("/")[-1]
def sanitize_fn(fn: str) -> str:
fn = fn.replace("\\", "/").split("/")[-1]
if APTL_OS:
fn = sanitize_to(fn, APTL_OS)
return fn.strip()
def sanitize_to(fn: str, tl: dict[int, int]) -> str:
fn = fn.translate(tl)
if ANYWIN:
remap = [
["<", ""],
[">", ""],
[":", ""],
['"', ""],
["/", ""],
["\\", ""],
["|", ""],
["?", ""],
["*", ""],
]
for a, b in [x for x in remap if x[0] not in ok]:
fn = fn.replace(a, b)
bad = ["con", "prn", "aux", "nul"]
for n in range(1, 10):
bad += ("com%s lpt%s" % (n, n)).split(" ")
if fn.lower().split(".")[0] in bad:
fn = "_" + fn
return fn.strip()
return fn
def sanitize_vpath(vp: str, ok: str) -> str:
def sanitize_vpath(vp: str) -> str:
if not APTL_OS:
return vp
parts = vp.replace(os.sep, "/").split("/")
ret = [sanitize_fn(x, ok) for x in parts]
ret = [sanitize_to(x, APTL_OS) for x in parts]
return "/".join(ret)
@ -2260,14 +2340,14 @@ def odfusion(
ret = base.copy()
if oth.startswith("+"):
for k in words1:
ret[k] = True
ret[k] = True # type: ignore
elif oth[:1] in ("-", "/"):
for k in words1:
ret.pop(k, None)
ret.pop(k, None) # type: ignore
else:
ret = ODict.fromkeys(words0, True)
return ret
return ret # type: ignore
def ipnorm(ip: str) -> str:
@ -2512,12 +2592,12 @@ def pathmod(
def _w8dec2(txt: bytes) -> str:
"""decodes filesystem-bytes to wtf8"""
return surrogateescape.decodefilename(txt)
return surrogateescape.decodefilename(txt) # type: ignore
def _w8enc2(txt: str) -> bytes:
"""encodes wtf8 to filesystem-bytes"""
return surrogateescape.encodefilename(txt)
return surrogateescape.encodefilename(txt) # type: ignore
def _w8dec3(txt: bytes) -> str:
@ -2639,6 +2719,24 @@ def set_fperms(f: Union[typing.BinaryIO, typing.IO[Any]], vf: dict[str, Any]) ->
os.fchown(fno, vf["uid"], vf["gid"])
def trystat_shutil_copy2(log: "NamedLogger", src: bytes, dst: bytes) -> bytes:
try:
return shutil.copy2(src, dst)
except:
# ignore failed mtime on linux+ntfs; for example:
# shutil.py:437 <copy2>: copystat(src, dst, follow_symlinks=follow_symlinks)
# shutil.py:376 <copystat>: lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
# [PermissionError] [Errno 1] Operation not permitted, '/windows/_videos'
_, _, tb = sys.exc_info()
for _, _, fun, _ in traceback.extract_tb(tb):
if fun == "copystat":
if log:
t = "warning: failed to retain some file attributes (timestamp and/or permissions) during copy from %r to %r:\n%s"
log(t % (src, dst, min_ex()), 3)
return dst # close enough
raise
def _fs_mvrm(
log: "NamedLogger", src: str, dst: str, atomic: bool, flags: dict[str, Any]
) -> bool:
@ -2677,7 +2775,7 @@ def _fs_mvrm(
t = "something appeared at dst; aborting rename %r ==> %r"
log(t % (src, dst), 1)
return False
osfun(*args)
osfun(*args) # type: ignore
if attempt:
now = time.time()
t = "%sd in %.2f sec, attempt %d: %r"
@ -2727,7 +2825,7 @@ def atomic_move(log: "NamedLogger", src: str, dst: str, flags: dict[str, Any]) -
os.unlink(bdst)
except:
pass
shutil.move(bsrc, bdst)
shutil.move(bsrc, bdst) # type: ignore
def wunlink(log: "NamedLogger", abspath: str, flags: dict[str, Any]) -> bool:
@ -2770,6 +2868,8 @@ def get_df(abspath: str, prune: bool) -> tuple[int, int, str]:
if not ANYWIN and not MACOS:
def siocoutq(sck: socket.socket) -> int:
assert fcntl # type: ignore # !rm
assert termios # type: ignore # !rm
# SIOCOUTQ^sockios.h == TIOCOUTQ^ioctl.h
try:
zb = fcntl.ioctl(sck.fileno(), termios.TIOCOUTQ, b"AAAA")
@ -2889,8 +2989,6 @@ def read_socket_chunked(
def list_ips() -> list[str]:
from .stolen.ifaddr import get_adapters
ret: set[str] = set()
for nic in get_adapters():
for ipo in nic.ips:
@ -3133,7 +3231,7 @@ def sendfile_kern(
try:
req = min(0x2000000, upper - ofs) # 32 MiB
if use_poll:
poll.poll(10000)
poll.poll(10000) # type: ignore
else:
select.select([], [out_fd], [], 10)
n = os.sendfile(out_fd, in_fd, ofs, req)
@ -3423,7 +3521,9 @@ NICEB = NICES.encode("utf-8")
def runcmd(
argv: Union[list[bytes], list[str]], timeout: Optional[float] = None, **ka: Any
argv: Union[list[bytes], list[str], list["LiteralString"]],
timeout: Optional[float] = None,
**ka: Any
) -> tuple[int, str, str]:
isbytes = isinstance(argv[0], (bytes, bytearray))
oom = ka.pop("oom", 0) # 0..1000
@ -3442,19 +3542,19 @@ def runcmd(
if ANYWIN:
if isbytes:
if argv[0] in CMD_EXEB:
argv[0] += b".exe"
argv[0] += b".exe" # type: ignore
else:
if argv[0] in CMD_EXES:
argv[0] += ".exe"
argv[0] += ".exe" # type: ignore
if ka.pop("nice", None):
if WINDOWS:
ka["creationflags"] = 0x4000
elif NICEB:
if isbytes:
argv = [NICEB] + argv
argv = [NICEB] + argv # type: ignore
else:
argv = [NICES] + argv
argv = [NICES] + argv # type: ignore
p = sp.Popen(argv, stdout=cout, stderr=cerr, **ka)
@ -3466,10 +3566,10 @@ def runcmd(
pass
if not timeout or PY2:
bout, berr = p.communicate(sin)
bout, berr = p.communicate(sin) # type: ignore
else:
try:
bout, berr = p.communicate(sin, timeout=timeout)
bout, berr = p.communicate(sin, timeout=timeout) # type: ignore
except sp.TimeoutExpired:
if kill == "n":
return -18, "", "" # SIGCONT; leave it be
@ -3479,7 +3579,7 @@ def runcmd(
killtree(p.pid)
try:
bout, berr = p.communicate(timeout=1)
bout, berr = p.communicate(timeout=1) # type: ignore
except:
bout = b""
berr = b""
@ -3565,11 +3665,13 @@ def retchk(
def _parsehook(
log: Optional["NamedLogger"], cmd: str
) -> tuple[str, bool, bool, bool, float, dict[str, Any], list[str]]:
) -> tuple[str, bool, bool, bool, bool, bool, float, dict[str, Any], list[str]]:
areq = ""
chk = False
fork = False
jtxt = False
imp = False
sin = False
wait = 0.0
tout = 0.0
kill = "t"
@ -3583,6 +3685,10 @@ def _parsehook(
fork = True
elif arg == "j":
jtxt = True
elif arg == "I":
imp = True
elif arg == "s":
sin = True
elif arg.startswith("w"):
wait = float(arg[1:])
elif arg.startswith("t"):
@ -3627,7 +3733,7 @@ def _parsehook(
argv[0] = os.path.expandvars(os.path.expanduser(argv[0]))
return areq, chk, fork, jtxt, wait, sp_ka, argv
return areq, chk, imp, fork, sin, jtxt, wait, sp_ka, argv
def runihook(
@ -3637,7 +3743,7 @@ def runihook(
vol: "VFS",
ups: list[tuple[str, int, int, str, str, str, int, str]],
) -> bool:
_, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
_, chk, _, fork, _, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
bcmd = [sfsenc(x) for x in acmd]
if acmd[0].endswith(".py"):
bcmd = [sfsenc(pybin)] + bcmd
@ -3813,10 +3919,10 @@ def _runhook(
sz: int,
ip: str,
at: float,
txt: str,
txt: Optional[list[str]],
) -> dict[str, Any]:
ret = {"rc": 0}
areq, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
areq, chk, imp, fork, sin, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
if areq:
for ch in areq:
if ch not in perms:
@ -3824,7 +3930,7 @@ def _runhook(
if log:
log(t % (uname, cmd, areq, perms))
return ret # fallthrough to next hook
if jtxt:
if imp or jtxt:
ja = {
"ap": ap,
"vp": vp,
@ -3836,19 +3942,35 @@ def _runhook(
"user": uname,
"perms": perms,
"src": src,
"txt": txt,
}
if txt:
ja["txt"] = txt[0]
ja["body"] = txt[1]
if imp:
ja["log"] = log
mod = loadpy(acmd[0], False)
return mod.main(ja)
arg = json.dumps(ja)
else:
arg = txt or ap
arg = txt[0] if txt else ap
if acmd[0].startswith("zmq:"):
zi, zs = _zmq_hook(log, verbose, src, acmd[0][4:].lower(), arg, wait, sp_ka)
if zi:
raise Exception("zmq says %d" % (zi,))
return {"rc": 0, "stdout": zs}
try:
ret = json.loads(zs)
if "rc" not in ret:
ret["rc"] = 0
return ret
except:
return {"rc": 0, "stdout": zs}
if sin:
sp_ka["sin"] = (arg + "\n").encode("utf-8", "replace")
else:
acmd += [arg]
acmd += [arg]
if acmd[0].endswith(".py"):
acmd = [pybin] + acmd
@ -3861,20 +3983,23 @@ def _runhook(
rc, v, err = runcmd(bcmd, **sp_ka) # type: ignore
if chk and rc:
ret["rc"] = rc
retchk(rc, bcmd, err, log, 5)
zi = 0 if rc == 100 else rc
retchk(zi, bcmd, err, log, 5)
else:
try:
ret = json.loads(v)
except:
ret = {}
pass
try:
if "stdout" not in ret:
ret["stdout"] = v
if "stderr" not in ret:
ret["stderr"] = err
if "rc" not in ret:
ret["rc"] = rc
except:
ret = {"rc": rc, "stdout": v}
ret = {"rc": rc, "stdout": v, "stderr": err}
if wait:
wait -= time.time() - t0
@ -3899,13 +4024,14 @@ def runhook(
sz: int,
ip: str,
at: float,
txt: str,
txt: Optional[list[str]],
) -> dict[str, Any]:
assert broker or up2k # !rm
args = (broker or up2k).args
args = (broker or up2k).args # type: ignore
verbose = args.hook_v
vp = vp.replace("\\", "/")
ret = {"rc": 0}
stop = False
for cmd in cmds:
try:
hr = _runhook(
@ -3913,28 +4039,30 @@ def runhook(
)
if verbose and log:
log("hook(%s) %r => \033[32m%s" % (src, cmd, hr), 6)
if not hr:
return {}
for k, v in hr.items():
if k in ("idx", "del") and v:
if broker:
broker.say("up2k.hook_fx", k, v, vp)
else:
assert up2k # !rm
up2k.fx_backlog.append((k, v, vp))
elif k == "reloc" and v:
# idk, just take the last one ig
ret["reloc"] = v
elif k == "rc" and v:
stop = True
ret[k] = 0 if v == 100 else v
elif k in ret:
if k == "rc" and v:
ret[k] = v
elif k == "stdout" and v and not ret[k]:
if k == "stdout" and v and not ret[k]:
ret[k] = v
else:
ret[k] = v
except Exception as ex:
(log or print)("hook: {}".format(ex))
(log or print)("hook: %r, %s" % (ex, ex))
if ",c," in "," + cmd:
return {}
return {"rc": 1}
break
if stop:
break
return ret
@ -4075,10 +4203,17 @@ def wrap(txt: str, maxlen: int, maxlen2: int) -> list[str]:
def termsize() -> tuple[int, int]:
# from hashwalk
try:
w, h = os.get_terminal_size()
return w, h
except:
pass
env = os.environ
def ioctl_GWINSZ(fd: int) -> Optional[tuple[int, int]]:
assert fcntl # type: ignore # !rm
assert termios # type: ignore # !rm
try:
cr = sunpack(b"hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, b"AAAA"))
return cr[::-1]

View file

@ -2,11 +2,14 @@
# which should help on really slow connections
# but then why are you using copyparty in the first place
pk: $(addsuffix .gz, $(wildcard *.js *.css))
un: $(addsuffix .un, $(wildcard *.gz))
pk: $(addsuffix .gz, $(wildcard tl/*.js *.js *.css) \
a/webdav-cfg.txt )
un: $(addsuffix .un, $(wildcard tl/*.gz *.gz a/*.gz))
%.gz: %
pigz -11 -J 34 -I 573 $<
pigz -c11 -J 34 -I 573 <$< >$@
touch -r $< $@
rm $<
%.un: %
pigz -d $<

View file

@ -1,3 +1,5 @@
"use strict";
/*!
* baguetteBox.js
* @author feimosi
@ -5,6 +7,8 @@
* @url https://github.com/feimosi/baguetteBox.js
*/
var J_BBX = 1;
window.baguetteBox = (function () {
'use strict';
@ -22,8 +26,9 @@ window.baguetteBox = (function () {
afterHide: null,
duringHide: null,
onChange: null,
readDirRtl: false,
},
overlay, slider, btnPrev, btnNext, btnHelp, btnAnim, btnRotL, btnRotR, btnSel, btnFull, btnVmode, btnClose,
overlay, slider, btnPrev, btnNext, btnHelp, btnAnim, btnRotL, btnRotR, btnSel, btnFull, btnZoom, btnVmode, btnReadDir, btnClose,
currentGallery = [],
currentIndex = 0,
isOverlayVisible = false,
@ -33,6 +38,8 @@ window.baguetteBox = (function () {
scrollTimer = 0,
re_i = /^[^?]+\.(a?png|avif|bmp|gif|heif|jpe?g|jfif|svg|webp)(\?|$)/i,
re_v = /^[^?]+\.(webm|mkv|mp4|m4v|mov)(\?|$)/i,
re_cbz = /^[^?]+\.(cbz)(\?|$)/i,
cbz_pics = ["png", "jpg", "jpeg", "gif", "bmp", "tga", "tif", "tiff", "webp", "avif"],
anims = ['slideIn', 'fadeIn', 'none'],
data = {}, // all galleries
imagesElements = [],
@ -57,6 +64,15 @@ window.baguetteBox = (function () {
hideOverlay();
};
var vtouch = function (e) {
var v = vid(),
bv = v.getBoundingClientRect(),
tp = e.changedTouches[0];
if (bv.bottom - tp.clientY < 90)
touchFlag = true;
};
var touchstartHandler = function (e) {
touch.count = e.touches.length;
if (touch.count > 1)
@ -73,10 +89,10 @@ window.baguetteBox = (function () {
var touchEvent = e.touches[0] || e.changedTouches[0];
if (touchEvent.pageX - touch.startX > 40) {
touchFlag = true;
showPreviousImage();
showLeftImage();
} else if (touchEvent.pageX - touch.startX < -40) {
touchFlag = true;
showNextImage();
showRightImage();
} else if (touch.startY - touchEvent.pageY > 100) {
hideOverlay();
}
@ -114,9 +130,9 @@ window.baguetteBox = (function () {
scrollTimer = Date.now();
if (d > 0)
showNextImage();
showNextImageIgnoreReadDir();
else
showPreviousImage();
showPreviousImageIgnoreReadDir();
};
var trapFocusInsideOverlay = function (e) {
@ -146,6 +162,8 @@ window.baguetteBox = (function () {
tagsNodeList = [galleryElement];
else
tagsNodeList = galleryElement.getElementsByTagName('a');
if (have_zls)
bindCbzClickListeners(tagsNodeList, userOptions);
tagsNodeList = [].filter.call(tagsNodeList, function (element) {
if (element.className.indexOf(userOptions && userOptions.ignoreClass) === -1)
@ -166,7 +184,7 @@ window.baguetteBox = (function () {
};
var imageItem = {
eventHandler: imageElementClickHandler,
imageElement: imageElement
imageElement: imageElement,
};
bind(imageElement, 'click', imageElementClickHandler);
gallery.push(imageItem);
@ -177,6 +195,86 @@ window.baguetteBox = (function () {
return [selectorData.galleries, options];
}
function bindCbzClickListeners(tagsNodeList, userOptions) {
var cbzNodes = [].filter.call(tagsNodeList, function (element) {
return re_cbz.test(element.href);
});
if (!tagsNodeList.length) {
return;
}
[].forEach.call(cbzNodes, function (cbzElement, index) {
var gallery = [];
var eventHandler = function (e) {
if (ctrl(e) || e && e.shiftKey)
return true;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
fillCbzGallery(gallery, cbzElement, eventHandler).then(function () {
prepareOverlay(gallery, userOptions);
showOverlay(0);
}
).catch(function (reason) {
console.error("cbz-ded", reason);
var t;
try {
t = uricom_dec(cbzElement.href.split('/').pop());
} catch (ex) { }
var msg = "Could not browse " + (t ? t : 'archive');
try {
msg += "\n\n" + reason.message;
} catch (ex) { }
toast.err(20, msg, 'cbz-ded');
});
}
bind(cbzElement, "click", eventHandler);
})
}
function fillCbzGallery(gallery, cbzElement, eventHandler) {
if (gallery.length !== 0) {
return Promise.resolve();
}
var href = cbzElement.href;
var zlsHref = href + (href.indexOf("?") === -1 ? "?" : "&") + "zls";
return fetch(zlsHref)
.then(function (response) {
if (response.ok) {
return response.json();
} else {
throw new Error("Archive is invalid");
}
})
.then(function (fileList) {
var imagesList = fileList.map(function (file) {
return file["fn"];
}).filter(function (file) {
return file.indexOf(".") !== -1
&& cbz_pics.indexOf(file.split(".").pop()) !== -1;
}).sort();
if (imagesList.length === 0) {
throw new Error("Archive does not contain any images");
}
imagesList.forEach(function (imageName, index) {
var imageHref = href
+ (href.indexOf("?") === -1 ? "?" : "&")
+ "zget="
+ encodeURIComponent(imageName);
var galleryItem = {
href: imageHref,
imageElement: cbzElement,
eventHandler: eventHandler,
};
gallery.push(galleryItem);
});
});
}
function clearCachedData() {
for (var selector in data)
if (data.hasOwnProperty(selector))
@ -212,10 +310,12 @@ window.baguetteBox = (function () {
'<div id="bbox-btns">' +
'<button id="bbox-help" type="button">?</button>' +
'<button id="bbox-anim" type="button" tt="a">-</button>' +
'<button id="bbox-readdir" type="button" tt="a">ltr</button>' +
'<button id="bbox-rotl" type="button">↶</button>' +
'<button id="bbox-rotr" type="button">↷</button>' +
'<button id="bbox-tsel" type="button">sel</button>' +
'<button id="bbox-full" type="button">⛶</button>' +
'<button id="bbox-full" type="button" tt="full-screen">⛶</button>' +
'<button id="bbzoom" type="button" tt="zoom/stretch">z</button>' +
'<button id="bbox-vmode" type="button" tt="a"></button>' +
'<button id="bbox-close" type="button" aria-label="Close">X</button>' +
'</div></div>'
@ -229,12 +329,17 @@ window.baguetteBox = (function () {
btnNext = ebi('bbox-next');
btnHelp = ebi('bbox-help');
btnAnim = ebi('bbox-anim');
btnReadDir = ebi('bbox-readdir');
btnRotL = ebi('bbox-rotl');
btnRotR = ebi('bbox-rotr');
btnSel = ebi('bbox-tsel');
btnFull = ebi('bbox-full');
btnZoom = ebi('bbzoom');
btnVmode = ebi('bbox-vmode');
btnClose = ebi('bbox-close');
bcfg_bind(options, 'bbzoom', 'bbzoom', false, setzoom);
setzoom();
}
function halp() {
@ -250,10 +355,11 @@ window.baguetteBox = (function () {
['end', 'last file'],
['R', 'rotate (shift=ccw)'],
['F', 'toggle fullscreen'],
['Z', 'toggle zoom/stretch'],
['S', 'toggle file selection'],
['space, P, K', 'video: play / pause'],
['U', 'video: seek 10sec back'],
['P', 'video: seek 10sec ahead'],
['O', 'video: seek 10sec ahead'],
['0..9', 'video: seek 0%..90%'],
['M', 'video: toggle mute'],
['V', 'video: toggle loop'],
@ -301,9 +407,9 @@ window.baguetteBox = (function () {
else if (e.shiftKey && kl != "r")
return;
else if (k == "ArrowLeft" || k == "Left" || kl == "j")
showPreviousImage();
showLeftImage();
else if (k == "ArrowRight" || k == "Right" || kl == "l")
showNextImage();
showRightImage();
else if (k == "Escape" || k == "Esc")
hideOverlay();
else if (k == "Home")
@ -332,6 +438,8 @@ window.baguetteBox = (function () {
}
else if (kl == "f")
tglfull();
else if (kl == "z")
btnZoom.click();
else if (kl == "s")
tglsel();
else if (kl == "r")
@ -353,6 +461,21 @@ window.baguetteBox = (function () {
tt.show.call(this);
}
function toggleReadDir() {
var o = options,
next = options.readDirRtl ? "ltr" : "rtl";
swrite('greaddir', next);
slider.className = "no-transition";
options = {};
setOptions(o);
updateOffset(true);
window.getComputedStyle(slider).opacity; // force a restyle
slider.className = "";
if (tt.en)
tt.show.call(this);
}
function setVmode() {
var v = vid();
ebi('bbox-vmode').style.display = v ? '' : 'none';
@ -424,6 +547,12 @@ window.baguetteBox = (function () {
}
}
function setzoom() {
var sel = clgot(btnZoom, 'on')
clmod(ebi('bbox-overlay'), 'fill', sel);
btnState(btnZoom, sel);
}
function tglsel() {
var o = findfile()[3];
clmod(o.closest('tr'), 'sel', 't');
@ -451,10 +580,14 @@ window.baguetteBox = (function () {
'rgba(153,34,85,0.7)' : '';
img.style.borderRadius = sel ? '1em' : '';
btnSel.style.color = sel ? '#fff' : '';
btnSel.style.background = sel ? '#d48' : '';
btnSel.style.textShadow = sel ? '1px 1px 0 #b38' : '';
btnSel.style.boxShadow = sel ? '.15em .15em 0 #502' : '';
btnState(btnSel, sel);
}
function btnState(btn, sel) {
btn.style.color = sel ? '#fff' : '';
btn.style.background = sel ? '#d48' : '';
btn.style.textShadow = sel ? '1px 1px 0 #b38' : '';
btn.style.boxShadow = sel ? '.15em .15em 0 #502' : '';
}
function keyUpHandler(e) {
@ -492,12 +625,13 @@ window.baguetteBox = (function () {
bind(document, 'fullscreenchange', onFSC);
bind(overlay, 'click', overlayClickHandler);
bind(overlay, 'wheel', overlayWheelHandler);
bind(btnPrev, 'click', showPreviousImage);
bind(btnNext, 'click', showNextImage);
bind(btnPrev, 'click', showLeftImage);
bind(btnNext, 'click', showRightImage);
bind(btnClose, 'click', hideOverlay);
bind(btnVmode, 'click', tglVmode);
bind(btnHelp, 'click', halp);
bind(btnAnim, 'click', anim);
bind(btnReadDir, 'click', toggleReadDir);
bind(btnRotL, 'click', rotl);
bind(btnRotR, 'click', rotr);
bind(btnSel, 'click', tglsel);
@ -515,12 +649,13 @@ window.baguetteBox = (function () {
unbind(document, 'fullscreenchange', onFSC);
unbind(overlay, 'click', overlayClickHandler);
unbind(overlay, 'wheel', overlayWheelHandler);
unbind(btnPrev, 'click', showPreviousImage);
unbind(btnNext, 'click', showNextImage);
unbind(btnPrev, 'click', showLeftImage);
unbind(btnNext, 'click', showRightImage);
unbind(btnClose, 'click', hideOverlay);
unbind(btnVmode, 'click', tglVmode);
unbind(btnHelp, 'click', halp);
unbind(btnAnim, 'click', anim);
unbind(btnReadDir, 'click', toggleReadDir);
unbind(btnRotL, 'click', rotl);
unbind(btnRotR, 'click', rotr);
unbind(btnSel, 'click', tglsel);
@ -571,6 +706,23 @@ window.baguetteBox = (function () {
btnAnim.textContent = ['⇄', '⮺', '⚡'][anims.indexOf(an)];
btnAnim.setAttribute('tt', 'animation: ' + an);
options.readDirRtl = sread('greaddir') === "rtl";
var msg;
if (options.readDirRtl) {
btnReadDir.innerText = "rtl";
msg = "browse from right to left";
slider.style.display = "flex";
slider.style.flexDirection = "row-reverse";
} else {
btnReadDir.innerText = "ltr";
msg = "browse from left to right";
slider.style.flexDirection = "";
slider.style.display = "block";
}
btnReadDir.setAttribute("tt", msg);
btnReadDir.setAttribute("aria-label", msg);
slider.style.transition = (options.animation === 'fadeIn' ? 'opacity .3s ease' :
options.animation === 'slideIn' ? '' : 'none');
@ -612,7 +764,7 @@ window.baguetteBox = (function () {
overlay.style.display = 'block';
// Fade in overlay
setTimeout(function () {
overlay.className = 'visible';
clmod(overlay, 'visible', 1);
if (options.bodyClass && document.body.classList)
document.body.classList.add(options.bodyClass);
@ -621,7 +773,7 @@ window.baguetteBox = (function () {
}, 50);
if (options.onChange && !url_ts)
options.onChange(currentIndex, imagesElements.length);
options.onChange.call(currentGallery, currentIndex, imagesElements.length);
url_ts = null;
documentLastFocus = document.activeElement;
@ -658,7 +810,7 @@ window.baguetteBox = (function () {
unbindEvents();
// Fade out and hide the overlay
overlay.className = '';
clmod(overlay, 'visible');
setTimeout(function () {
overlay.style.display = 'none';
if (options.bodyClass && document.body.classList)
@ -683,6 +835,7 @@ window.baguetteBox = (function () {
if (v == keep)
continue;
unbind(v, 'touchstart', vtouch, nonPassiveEvent);
unbind(v, 'error', lerr);
v.src = '';
v.load();
@ -749,11 +902,11 @@ window.baguetteBox = (function () {
imageContainer.removeChild(imageContainer.firstChild);
var imageElement = galleryItem.imageElement,
imageSrc = imageElement.href,
imageSrc = galleryItem.href || imageElement.href,
is_vid = re_v.test(imageSrc),
thumbnailElement = imageElement.querySelector('img, video'),
imageCaption = typeof options.captions === 'function' ?
options.captions.call(currentGallery, imageElement) :
options.captions.call(currentGallery, imageElement, index) :
imageElement.getAttribute('data-caption') || imageElement.title;
imageSrc = addq(imageSrc, 'cache');
@ -812,15 +965,27 @@ window.baguetteBox = (function () {
un_pp = 0;
return playpause(); // browser undid space hotkey
}
show_buttons(this.paused ? 1 : 0);
show_buttons(this.paused ? 0 : 1);
}
function showNextImage(e) {
function showRightImage(e) {
ev(e);
var dir = options.readDirRtl ? -1 : 1;
return show(currentIndex + dir);
}
function showLeftImage(e) {
ev(e);
var dir = options.readDirRtl ? 1 : -1;
return show(currentIndex + dir);
}
function showNextImageIgnoreReadDir(e) {
ev(e);
return show(currentIndex + 1);
}
function showPreviousImage(e) {
function showPreviousImageIgnoreReadDir(e) {
ev(e);
return show(currentIndex - 1);
}
@ -848,12 +1013,14 @@ window.baguetteBox = (function () {
}
if (index < 0)
return bounceAnimation('left');
return bounceAnimation(options.readDirRtl ? 'right' : 'left');
if (index >= imagesElements.length)
return bounceAnimation('right');
return bounceAnimation(options.readDirRtl ? 'left' : 'right');
var orot;
try {
orot = vidimg().getAttribute('rot');
vid().pause();
}
catch (ex) { }
@ -871,6 +1038,9 @@ window.baguetteBox = (function () {
else if (toast.tag == 'bb-ded')
toast.hide();
if (orot && im.getAttribute('rot') === null)
rotn(orot / 90, 1);
if (options.animation == 'none')
unvid(vid());
else
@ -881,13 +1051,13 @@ window.baguetteBox = (function () {
unfig(index);
if (options.onChange)
options.onChange(currentIndex, imagesElements.length);
options.onChange.call(currentGallery, currentIndex, imagesElements.length);
return true;
}
var prev_cw = 0, prev_ch = 0, unrot_timer = null;
function rotn(n) {
function rotn(n, asap) {
var el = vidimg(),
orot = parseInt(el.getAttribute('rot') || 0),
frot = orot + (n || 0) * 90;
@ -902,6 +1072,8 @@ window.baguetteBox = (function () {
if (!n && prev_cw === cw && prev_ch === ch)
return; // reflow noop
clmod(el, 'asap', asap);
prev_cw = cw;
prev_ch = ch;
var rot = frot,
@ -911,8 +1083,13 @@ window.baguetteBox = (function () {
dl = el.closest('div').querySelector('figcaption a'),
vw = cw,
vh = ch - dl.offsetHeight + magic,
pmag = Math.min(1, Math.min(vw / ih, vh / iw)),
wmag = Math.min(1, Math.min(vw / iw, vh / ih));
pmag = Math.min(vw / ih, vh / iw),
wmag = Math.min(vw / iw, vh / ih);
if (!options.bbzoom) {
pmag = Math.min(1, pmag);
wmag = Math.min(1, wmag);
}
while (rot < 0) rot += 360;
while (rot >= 360) rot -= 360;
@ -956,7 +1133,7 @@ window.baguetteBox = (function () {
return;
clmod(el, 'nt', 1);
el.removeAttribute('rot');
el.setAttribute('rot', 0);
el.removeAttribute("style");
rot = el.offsetHeight;
clmod(el, 'nt');
@ -1005,7 +1182,7 @@ window.baguetteBox = (function () {
function vidEnd() {
if (this == vid() && vnext)
showNextImage();
showNextImageIgnoreReadDir();
}
function setloop(side) {
@ -1066,11 +1243,12 @@ window.baguetteBox = (function () {
return false;
}
function updateOffset() {
var offset = -currentIndex * 100 + '%',
function updateOffset(noTransition) {
var dir = options.readDirRtl ? 1 : -1,
offset = dir * currentIndex * 100 + '%',
xform = slider.style.perspective !== undefined;
if (options.animation === 'fadeIn') {
if (options.animation === 'fadeIn' && !noTransition) {
slider.style.opacity = 0;
setTimeout(function () {
xform ?
@ -1098,6 +1276,7 @@ window.baguetteBox = (function () {
setloop();
}
}
bind(v, 'touchstart', vtouch, nonPassiveEvent);
}
selbg();
mp_ctl();
@ -1116,10 +1295,10 @@ window.baguetteBox = (function () {
fx = x / (rc.right - rc.left);
if (fx < 0.3)
return showPreviousImage();
return showLeftImage();
if (fx > 0.7)
return showNextImage();
return showRightImage();
show_buttons('t');
@ -1175,8 +1354,8 @@ window.baguetteBox = (function () {
return {
run: run,
show: show,
showNext: showNextImage,
showPrevious: showPreviousImage,
showNext: showRightImage,
showPrevious: showLeftImage,
relseek: relseek,
urltime: urltime,
playpause: playpause,
@ -1184,3 +1363,5 @@ window.baguetteBox = (function () {
destroy: destroyPlugin
};
})();
J_BBX = 2;

View file

@ -84,6 +84,13 @@
--sort-1: #fb0;
--sort-2: #d09;
--sz-b: #aaa;
--sz-k: #4ff;
--sz-m: var(--tab-alt);
--sz-g: var(--a);
--sz-t: var(--sz-g);
--sz-p: var(--sz-t);
--srv-1: #aaa;
--srv-2: #a73;
--srv-3: #f4c;
@ -187,6 +194,9 @@ html.y {
--sort-1: #059;
--sort-2: #f5d;
--sz-b: #777;
--sz-k: #380;
--srv-1: #555;
--srv-2: #c83;
--srv-3: #c0a;
@ -344,6 +354,9 @@ html.cz {
--btn-1-bb: .2em solid #e90;
--btn-1-bs: 0 .1em .8em rgba(255,205,0,0.9);
--sz-b: #ddd;
--sz-k: #c9f;
--srv-3: #fff;
--u2-tab-b1: var(--bg-d3);
@ -740,6 +753,15 @@ html.y #files tr.fade a {
#files tbody tr td:last-child {
white-space: nowrap;
}
#files span.fsz_B { color: var(--sz-b); }
#files span.fsz_K { color: var(--sz-k); }
#files span.fsz_M { color: var(--sz-m); }
#files span.fsz_G { color: var(--sz-g); }
#files span.fsz_T { color: var(--sz-t); }
#files span.fsz_P { color: var(--sz-p); }
html.y #files span.fsz_G,
html.y #files span.fsz_T,
html.y #files span.fsz_P { font-weight: bold }
#files thead th[style] {
width: auto !important;
}
@ -865,6 +887,9 @@ html.y #path a:hover {
#srv_info2 span {
color: var(--srv-1);
}
#srv_info2 a {
padding: 0;
}
#srv_info2 {
display: none;
}
@ -1011,6 +1036,7 @@ html.dz #flogout {
box-shadow: 0 .1em 1.2em var(--g-play-sh);
}
#files tbody tr.sel td,
#files tbody tr.sel span,
#ggrid>a.sel,
#ggrid>a[tt].sel {
color: var(--g-sel-fg);
@ -1155,6 +1181,9 @@ html.y #widget.open {
border: 1px solid var(--bg-u5);
border-width: 0 .1em 0 0;
}
#wzip1 {
margin-right: .2em;
}
#wfm.act+#wzip1+#wzip,
#wfm.act+#wzip1+#wzip+#wnp {
margin-left: .2em;
@ -1911,6 +1940,8 @@ html.y #tree.nowrap .ntree a+a:hover {
#rui td input[type="text"] {
width: 100%;
}
#rui #rn_n_d,
#rui #rn_n_s,
#shui td.exs input[type="text"] {
width: 3em;
}
@ -2115,6 +2146,7 @@ html.noscroll .sbar::-webkit-scrollbar {
width: 100%;
height: 100%;
text-align: center;
flex: none;
}
.full-image figure {
display: inline;
@ -2134,6 +2166,16 @@ html.noscroll .sbar::-webkit-scrollbar {
vertical-align: middle;
transition: transform .23s, left .23s, top .23s, width .23s, height .23s;
}
.full-image img.asap,
.full-image video.asap {
transition: none;
}
#bbox-overlay.fill .full-image img,
#bbox-overlay.fill .full-image video {
width: 100%;
height: 100%;
object-fit: contain;
}
html.bb_fsc .full-image img,
html.bb_fsc .full-image video {
max-height: 100%;
@ -2309,6 +2351,9 @@ html.y #bbox-overlay figcaption a {
0%, 100% {transform: scale(0)}
50% {transform: scale(1)}
}
.no-transition {
transition: none !important;
}
@ -3106,9 +3151,6 @@ html.bz .ghead {
html.b #files td {
padding: .5em .7em;
}
html.b #ggrid>a {
margin: .8em;
}
html.b .btn {
top: -.1em;
}
@ -3253,8 +3295,8 @@ html.d #treepar {
}
html.b #ggrid {
padding: 0 2em 2em 0;
gap: .5em 3em;
padding: 0 0 2em 0;
gap: 1em 1.5em;
}
#ggrid > a {
@ -3496,7 +3538,6 @@ html.ez {
html.e {
text-shadow: none;
}
html.e #files,
html.e #u2conf input[type="checkbox"]:hover + label,
html.e .tgl.btn.on:hover,
@ -3596,6 +3637,10 @@ html.e #srv_info {
display: flex;
align-items: center;
}
html.e #acc_info span.warn,
html.e #acc_info a {
color: var(--white);
}
html.e #flogout:before {
padding-left: 0.2em;
padding-right: 0.4em;
@ -4080,3 +4125,47 @@ html.e #doc {
html.e #detree {
padding: 0px;
}
#rcm {
position: absolute;
display: none;
background: #fff;
background: var(--bg);
border: 1px solid var(--bg-u3);
outline: none;
border-radius: .3rem;
box-shadow: 0 0 .3rem var(--bg-d3);
z-index: 3;
}
#rcm > * {
display: block;
}
#rcm > a {
padding: .2rem .3rem;
}
#rcm > .hide {
display: none;
}
#rcm > a:hover {
background: var(--bg-d2);
}
#rcm > .sep {
margin: 0 .2rem;
border-bottom: 1px solid var(--a-gray);
}
#tempname {
color: var(--fg);
background: var(--txt-bg);
border: none;
box-shadow: 0 0 2px var(--txt-sh);
border-bottom: 1px solid #999;
border-color: var(--a);
border-radius: .2em;
padding: .2em .3em;
}

View file

@ -9,7 +9,7 @@
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
{%- if css %}
<link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}">
{%- endif %}
@ -51,8 +51,9 @@
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="{{ url_suf }}">
<input type="hidden" name="act" value="new_md" />
📝<input type="text" name="name" class="i" placeholder="weekend-plans">
<input type="submit" value="new markdown doc">
<input type="submit" value="new file">
</form>
<span id="new_mdi"></span>
</div>
<div id="op_msg" class="opview opbox {% if not ls0 %}act{% endif %}">
@ -128,17 +129,17 @@
<div id="widget"></div>
<div id="rcm" tabindex="0"></div>
<script>
var SR = "{{ r }}",
CGV1 = {{ cgv1 }},
CGV = {{ cgv|tojson }},
TS = "{{ ts }}",
dtheme = "{{ dtheme }}",
srvinf = "{{ srv_info }}",
lang = "{{ lang }}",
dfavico = "{{ favico }}",
have_tags_idx = {{ have_tags_idx }},
sb_lg = "{{ sb_lg }}",
logues = {{ logues|tojson if sb_lg else "[]" }},
ls0 = {{ ls0|tojson }};
@ -146,13 +147,22 @@
document.documentElement.className = (STG && STG.cpp_thm) || dtheme;
</script>
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
{%- if lang != "eng" %}
<script src="{{ r }}/.cpr/tl/{{ lang }}.js?_={{ ts }}"></script>
{%- endif %}
<script src="{{ r }}/.cpr/baguettebox.js?_={{ ts }}"></script>
<script src="{{ r }}/.cpr/browser.js?_={{ ts }}"></script>
<script src="{{ r }}/.cpr/up2k.js?_={{ ts }}"></script>
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_BBX","baguettebox");
jsldp("J_BRW","browser");
jsldp("J_U2K","up2k");
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
</head>
<body>
@ -50,6 +50,10 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
</script>
</body>
</html>

View file

@ -9,7 +9,7 @@
{%- if edit %}
<link rel="stylesheet" href="{{ r }}/.cpr/md2.css?_={{ ts }}">
{%- endif %}
{{- html_head }}
{{ html_head }}
</head>
<body>
<div id="mn"></div>
@ -22,7 +22,8 @@
<a id="nsbs" href="#" tt="switch between editor and preview$NHotkey: ctrl-e">editor</a>
<div id="toolsbox">
<a id="tools" href="#">tools</a>
<a id="fmt_table" href="#">prettify table (ctrl-k)</a>
<a id="fmt_table" href="#">beautify table (ctrl-k)</a>
<a id="fmt_json" href="#">beautify json (ctrl-j)</a>
<a id="iter_uni" href="#">non-ascii: iterate (ctrl-u)</a>
<a id="mark_uni" href="#">non-ascii: markup</a>
<a id="cfg_uni" href="#">non-ascii: whitelist</a>
@ -160,8 +161,17 @@ try { l.light = drk? 0:1; } catch (ex) { }
{%- if edit %}
<script src="{{ r }}/.cpr/md2.js?_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_MD","md");
{%- if edit %}
jsldp("J_MD2","md2");
{%- endif %}
</script>
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
</body></html>
</body>
</html>

View file

@ -1,5 +1,6 @@
"use strict";
var J_MD = 1;
var dom_toc = ebi('toc'),
dom_wrap = ebi('mw'),
dom_hbar = ebi('mh'),
@ -239,6 +240,12 @@ function convert_markdown(md_text, dest_dom) {
var href = nodes[a].getAttribute('href');
var txt = nodes[a].innerHTML;
if (/\.[Mm][Dd]$/.test(href)) {
var o = new URL(href, location.href).origin;
if (!o || o == location.origin)
nodes[a].href = href + '?v';
}
if (!txt)
nodes[a].textContent = href;
else if (href !== txt && !nodes[a].className)
@ -518,3 +525,5 @@ if (sread('hidenav') == 1)
if (window.tt && tt.init)
tt.init();
J_MD = 2;

View file

@ -9,10 +9,13 @@
width: calc(100% - 56em);
}
#mw {
left: max(0em, calc(100% - 55em));
overflow-y: auto;
position: fixed;
bottom: 0;
left: 0;
}
@media (min-width: 55em) {
#mw {left:calc(100% - 55em)}
}

View file

@ -1,6 +1,7 @@
"use strict";
var J_MD2 = 1;
var sloc0 = '' + location,
dbg_kbd = /[?&]dbgkbd\b/.exec(sloc0);
@ -334,7 +335,7 @@ window.onbeforeunload = function (e) {
// save handler
function save(e) {
if (e) e.preventDefault();
ev(e);
var save_btn = ebi("save"),
save_cls = save_btn.className + '';
@ -698,9 +699,42 @@ function reLastIndexOf(txt, ptn, end) {
}
// json formatter
function fmt_json(e) {
ev(e);
try {
fmt_json2();
}
catch (ex) {
return toast.err(7, 'json-format (CTRL-J) failed\n\n(hint: select the json you want to beautify/minify first)\n\n' + ex);
}
}
function fmt_json2() {
var txt = dom_src.value,
o0 = txt.lastIndexOf('\n', dom_src.selectionStart - 1),
o1 = txt.indexOf('\n', dom_src.selectionEnd);
o0 = o0 + 1 ? o0 + 1 : 0;
if (o1 < 0) o1 = txt.length;
for (var a = 0; a < 9; a++) {
if (has(['\r', '\n', ' '], txt.charAt(o0))) ++o0;
if (has(['\r', '\n', ' '], txt.charAt(o1))) --o1;
}
var jt0 = txt.slice(o0, ++o1),
jo = JSON.parse(jt0),
jt = JSON.stringify(jo, null, jt0.indexOf('\n') + 1 ? 0 : 2);
setsel({
"pre": txt.slice(0, o0),
"sel": jt,
"post": txt.slice(o1),
"car": o0,
"cdr": o0,
});
}
// table formatter
function fmt_table(e) {
if (e) e.preventDefault();
ev(e);
try {
fmt_table2();
}
@ -857,7 +891,7 @@ function fmt_table2() {
// show unicode
function mark_uni(e) {
if (e) e.preventDefault();
ev(e);
dom_tbox.className = '';
var txt = dom_src.value,
@ -873,7 +907,7 @@ function mark_uni(e) {
// iterate unicode
function iter_uni(e) {
if (e) e.preventDefault();
ev(e);
var txt = dom_src.value,
ofs = dom_src.selectionDirection == "forward" ? dom_src.selectionEnd : dom_src.selectionStart,
@ -895,7 +929,7 @@ function iter_uni(e) {
// configure whitelist
function cfg_uni(e) {
if (e) e.preventDefault();
ev(e);
modal.prompt("unicode whitelist", esc_uni_whitelist, function (reply) {
esc_uni_whitelist = reply;
@ -923,7 +957,9 @@ var set_lno = (function () {
if (i === pi)
return;
var v = 'L' + dom_src.value.slice(0, i).split('\n').length;
var lns = dom_src.value.slice(0, i).split('\n'),
v = lns.length + ' : ' + lns.pop().length;
if (v != pv)
lno.innerHTML = v;
@ -995,6 +1031,10 @@ var set_lno = (function () {
action_stack.redo();
return false;
}
if (kl == "j") {
fmt_json(e.shiftKey);
return false;
}
if (kl == "k") {
fmt_table();
return false;
@ -1038,14 +1078,14 @@ var set_lno = (function () {
ebi('tools').onclick = function (e) {
if (e) e.preventDefault();
ev(e);
var is_open = dom_tbox.className != 'open';
dom_tbox.className = is_open ? 'open' : '';
};
ebi('help').onclick = function (e) {
if (e) e.preventDefault();
ev(e);
dom_tbox.className = '';
var dom = ebi('helpbox');
@ -1065,6 +1105,7 @@ ebi('help').onclick = function (e) {
ebi('fmt_table').onclick = fmt_table;
ebi('fmt_json').onclick = fmt_json;
ebi('mark_uni').onclick = mark_uni;
ebi('iter_uni').onclick = iter_uni;
ebi('cfg_uni').onclick = cfg_uni;
@ -1190,3 +1231,5 @@ action_stack = (function () {
_ref: ref
}
})();
J_MD2 = 2;

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="{{ r }}/.cpr/mde.css?_={{ ts }}">
<link rel="stylesheet" href="{{ r }}/.cpr/deps/mini-fa.css?_={{ ts }}">
<link rel="stylesheet" href="{{ r }}/.cpr/deps/easymde.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
</head>
<body>
<div id="mw">
@ -57,5 +57,10 @@ try { l.light = drk? 0:1; } catch (ex) { }
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_MDE","mde");
</script>
</body></html>

View file

@ -1,5 +1,6 @@
"use strict";
var J_MDE = 1;
var dom_wrap = ebi('mw');
var dom_nav = ebi('mn');
var dom_doc = ebi('m');
@ -199,3 +200,5 @@ function save_chk() {
toast.ok(2, 'save OK' + (this.ntry ? '\nattempt ' + this.ntry : ''));
}
J_MDE = 2;

View file

@ -1,36 +0,0 @@
:root {
--font-main: sans-serif;
--font-serif: serif;
--font-mono: 'scp';
}
html,body,tr,th,td,#files,a {
color: inherit;
background: none;
font-weight: inherit;
font-size: inherit;
padding: 0;
border: none;
}
html {
color: #ccc;
background: #333;
font-family: sans-serif;
font-family: var(--font-main), sans-serif;
text-shadow: 1px 1px 0px #000;
touch-action: manipulation;
}
html, body {
margin: 0;
padding: 0;
}
#box {
padding: .5em 1em;
background: #2c2c2c;
}
pre {
font-family: monospace, monospace;
font-family: var(--font-mono), monospace, monospace;
}
a {
color: #fc5;
}

View file

@ -7,8 +7,13 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=0.8">
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/msg.css?_={{ ts }}">
{{- html_head }}
<style>:root{--font-main:sans-serif;--font-mono:monospace}
html,body,a{margin:0;padding:0;border:none;color:#ccc;background:none;font-family:sans-serif;font-family:var(--font-main),sans-serif}
pre{font-family:monospace,monospace;font-family:var(--font-mono),monospace}
html{touch-action:manipulation;background:#333}
#box{padding:.5em 1em;background:#2c2c2c}
a{color:#fc5}</style>
{{ html_head }}
</head>
<body>
@ -43,7 +48,7 @@
<script>
setTimeout(function() {
location.replace("{{ redir }}");
}, 1000);
}, 800);
</script>
{%- endif %}
{%- if js %}

31
copyparty/web/opds.xml Normal file
View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
{%- for d in dirs %}
<entry>
<title>{{ d.name }}</title>
<link rel="subsection"
href="{{ d.href | e }}"
type="application/atom+xml;profile=opds-catalog"/>
<updated>{{ d.iso8601 }}</updated>
</entry>
{%- endfor %}
{%- for f in files %}
<entry>
<title>{{ f.name }}</title>
<updated>{{ f.iso8601 }}</updated>
<link rel="http://opds-spec.org/acquisition"
href="{{ f.href | e }}"
type="{{ f.mime }}"/>
{%- if f.jpeg_thumb_href != None %}
<link rel="http://opds-spec.org/image/thumbnail"
href="{{ f.jpeg_thumb_href | e }}"
type="image/jpeg"/>
{%- endif %}
{%- if f.jpeg_thumb_href_hires != None %}
<link rel="http://opds-spec.org/image"
href="{{ f.jpeg_thumb_href_hires | e }}"
type="image/jpeg"/>
{%- endif %}
</entry>
{%- endfor %}
</feed>

View file

@ -10,7 +10,7 @@
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/rups.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
</head>
<body>
@ -39,6 +39,11 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_RUP","rups");
</script>
</body>
</html>

View file

@ -1,3 +1,7 @@
"use strict";
var J_RUP = 1;
function render() {
var html = ['<table id="tab"><thead><tr><th>size</th><th>who</th><th>ip</th><th>when</th><th>age</th><th>dir</th><th>file</th></tr></thead><tbody>'];
var ups = V.ups, now = V.now;
@ -67,3 +71,5 @@ ebi('filter').onkeydown = function (e) {
if (('' + e.key).endsWith('Enter'))
ask();
};
J_RUP = 2;

View file

@ -58,6 +58,7 @@ th {
#wrap th {
padding: .3em .6em;
text-align: left;
vertical-align: top;
white-space: nowrap;
}
#wrap td+td+td+td+td+td+td+td {
@ -71,7 +72,10 @@ th {
#wrap td:last-child {
border-radius: 0 .5em .5em 0;
}
#wrap.terse td div {
height: 2.3em;
overflow-y: hidden;
}
html.z {

View file

@ -10,12 +10,13 @@
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
</head>
<body>
<div id="wrap">
<div id="wrap" class="terse">
<a href="{{ r }}/?shares">refresh</a>
<a id="xpnd" href="#">files</a>
<a href="{{ r }}/?h">control-panel</a>
<span>axs = perms (read,write,move,delet)</span>
@ -46,7 +47,7 @@
<td>{{ "yes" if pw else "--" }}</td>
<td><a href="{{ r }}/{{ vp|e }}">/{{ vp|e }}</a></td>
<td>{{ pr }}</td>
<td>{{ st }}</td>
<td><div>{{ st }}</div></td>
<td>{{ un|e }}</td>
<td>{{ t0 }}</td>
<td>{{ t1 }}</td>
@ -78,6 +79,11 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_SHR","shares");
</script>
</body>
</html>

View file

@ -1,3 +1,7 @@
"use strict";
var J_SHR = 1;
var t = QSA('a[k]');
for (var a = 0; a < t.length; a++)
t[a].onclick = rm;
@ -28,6 +32,11 @@ function cb() {
location = '?shares';
}
ebi('xpnd').onclick = function (e) {
ev(e);
clmod(ebi('wrap'), 'terse', 't');
};
function qr(e) {
ev(e);
var href = this.href,
@ -76,3 +85,5 @@ function showqr(href) {
for (var a = 0; a < aa; a++)
btns[a].onclick = bump;
})();
J_SHR = 2;

View file

@ -118,6 +118,26 @@ table {
.btns>a:first-child {
margin-left: 0;
}
.agr br {
display: none;
}
#lo,
.agr a,
.agr form {
margin: 0 .5em 0 0;
line-height: 4em;
}
.agr form,
.agr input {
display: inline;
padding: 0;
margin: 0;
}
#lo,
.agr input {
line-height: 1em;
font-weight: normal;
}
#msg {
margin: 3em 0;
}

View file

@ -9,7 +9,7 @@
<meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }}
{{ html_head }}
</head>
<body>
@ -42,7 +42,7 @@
<thead><tr><th>%</th><th>speed</th><th>eta</th><th>idle</th><th>dir</th><th>file</th></tr></thead>
<tbody>
{%- for u in ups %}
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td><a href="{{ u[4] }}">{{ u[5]|e }}</a></td><td>{{ u[6]|e }}</td></tr>
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td><a href="{{ r }}{{ u[4] }}">{{ u[5]|e }}</a></td><td>{{ u[6]|e }}</td></tr>
{%- endfor %}
</tbody>
</table>
@ -54,7 +54,7 @@
<thead><tr><th>%</th><th>sent</th><th>speed</th><th>eta</th><th>idle</th><th></th><th>dir</th><th>file</th></tr></thead>
<tbody>
{%- for u in dls %}
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td>{{ u[4] }}</td><td>{{ u[5] }}</td><td><a href="{{ u[6] }}">{{ u[7]|e }}</a></td><td>{{ u[8] }}</td></tr>
<tr><td>{{ u[0] }}</td><td>{{ u[1] }}</td><td>{{ u[2] }}</td><td>{{ u[3] }}</td><td>{{ u[4] }}</td><td>{{ u[5] }}</td><td><a href="{{ r }}{{ u[6] }}">{{ u[7]|e }}</a></td><td>{{ u[8] }}</td></tr>
{%- endfor %}
</tbody>
</table>
@ -117,10 +117,15 @@
{%- if ahttps %}
<a id="w" href="{{ ahttps }}">switch to https</a>
{%- endif %}
<div id="lm"></div>
</form>
</div>
{%- else %}
{%- if this.uname == '*' %}
<h1 id="l">login for more:</h1>
{%- else %}
<h1 id="l">change account:</h1>
{%- endif %}
<div>
{%- if this.args.idp_login %}
<ul><li>
@ -145,25 +150,38 @@
{%- if ahttps %}
<a id="w" href="{{ ahttps }}">switch to https</a>
{%- endif %}
<div id="lm"></div>
</form>
{%- endif %}
</div>
{%- endif %}
<h1 id="cc">other stuff:</h1>
<ul>
<div class="agr">
{%- if ahttps %}
<li><a id="wb" href="{{ ahttps }}">switch to https</a></li>
<a id="wb" href="{{ ahttps }}">switch to https</a><br />
{%- endif %}
{%- if this.uname in this.args.idp_adm_set %}
<li><a id="ag" href="{{ r }}/?idp">view idp cache</a></li>
{%- endif %}
<a id="af" href="{{ r }}/?ru">show recent uploads</a><br />
{%- if this.uname != '*' and this.args.shr %}
<li><a id="y" href="{{ r }}/?shares">edit shares</a></li>
<a id="y" href="{{ r }}/?shares">edit shares</a><br />
{%- endif %}
{%- if this.uname in this.args.idp_adm_set %}
<a id="ag" href="{{ r }}/?idp">view idp cache</a><br />
{%- endif %}
<a id="k" href="{{ r }}/?reset" class="r" onclick="localStorage.clear();return true">reset client settings</a><br />
{%- if this.uname != '*' and not in_shr %}
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="act" value="logout" />
<input type="submit" id="lo" value="logout “{{ this.uname|e }}” everywhere" />
</form>
{%- endif %}
</div>
<ul>
{%- if k304 or k304vis %}
{%- if k304 %}
<li><a id="h" href="{{ r }}/?cc&setck=k304=n">disable k304</a> (currently enabled)
@ -181,16 +199,6 @@
{%- endif %}
<blockquote id="ad">enabling no304 will disable all caching; try this if k304 wasn't enough. This will waste a huge amount of network traffic!</blockquote></li>
{%- endif %}
<li><a id="af" href="{{ r }}/?ru">show recent uploads</a></li>
<li><a id="k" href="{{ r }}/?reset" class="r" onclick="localStorage.clear();return true">reset client settings</a></li>
{%- if this.uname != '*' and not in_shr %}
<li><form method="post" enctype="multipart/form-data">
<input type="hidden" name="act" value="logout" />
<input type="submit" id="lo" value="logout “{{ this.uname|e }}” everywhere" />
</form></li>
{%- endif %}
</ul>
</div>
@ -209,10 +217,18 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
</script>
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
{%- if lang != "eng" %}
<script src="{{ r }}/.cpr/tl/{{ lang }}.js?_={{ ts }}"></script>
{%- endif %}
<script src="{{ r }}/.cpr/splash.js?_={{ ts }}"></script>
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_SPL","splash");
</script>
</body>
</html>

View file

@ -1,54 +1,9 @@
// please add translations in alphabetic order, but keep "nor" and "eng" first
// (lines ending with //m are machine translations)
var Ls = {
"nor": {
"a1": "oppdater",
"b1": "halloien &nbsp; <small>(du er ikke logget inn)</small>",
"c1": "logg ut",
"d1": "tilstand",
"d2": "vis tilstanden til alle tråder",
"e1": "last innst.",
"e2": "leser inn konfigurasjonsfiler på nytt$N(kontoer, volumer, volumbrytere)$Nog kartlegger alle e2ds-volumer$N$Nmerk: endringer i globale parametere$Nkrever en full restart for å ta gjenge",
"f1": "du kan betrakte:",
"g1": "du kan laste opp til:",
"cc1": "brytere og sånt:",
"h1": "skru av k304",
"i1": "skru på k304",
"j1": "k304 bryter tilkoplingen for hver HTTP 304. Dette hjelper mot visse mellomtjenere som kan sette seg fast / plutselig slutter å laste sider, men det reduserer også ytelsen betydelig",
"k1": "nullstill innstillinger",
"l1": "logg inn:",
"ls3": "logg inn",
"lu4": "brukernavn",
"lp4": "passord",
"lo3": "logg ut “{0}” overalt",
"lo2": "avslutter økten på alle nettlesere",
"m1": "velkommen tilbake,",
"n1": "404: filen finnes ikke &nbsp;┐( ´ -`)┌",
"o1": 'eller kanskje du ikke har tilgang? prøv et passord eller <a href="' + SR + '/?h">gå hjem</a>',
"p1": "403: tilgang nektet &nbsp;~┻━┻",
"q1": 'prøv et passord eller <a href="' + SR + '/?h">gå hjem</a>',
"r1": "gå hjem",
".s1": "kartlegg",
"t1": "handling",
"u2": "tid siden noen sist skrev til serveren$N( opplastning / navneendring / ... )$N$N17d = 17 dager$N1h23 = 1 time 23 minutter$N4m56 = 4 minuter 56 sekunder",
"v1": "koble til",
"v2": "bruk denne serveren som en lokal harddisk",
"w1": "bytt til https",
"x1": "bytt passord",
"y1": "dine delinger",
"z1": "lås opp område:",
"ta1": "du må skrive et nytt passord først",
"ta2": "gjenta for å bekrefte nytt passord:",
"ta3": "fant en skrivefeil; vennligst prøv igjen",
"aa1": "innkommende:",
"ab1": "skru av no304",
"ac1": "skru på no304",
"ad1": "no304 stopper all bruk av cache. Hvis ikke k304 var nok, prøv denne. Vil mangedoble dataforbruk!",
"ae1": "utgående:",
"af1": "vis nylig opplastede filer",
"ag1": "vis kjente IdP-brukere",
},
"eng": {
"use strict";
var J_SPL = 1;
Ls.eng = {
"splash": {
"d2": "shows the state of all active threads",
"e2": "reload config files (accounts/volumes/volflags),$Nand rescan all e2ds volumes$N$Nnote: any changes to global settings$Nrequire a full restart to take effect",
"lo2": "ends the session on all browsers",
@ -57,762 +12,19 @@ var Ls = {
"ta1": "fill in your new password first",
"ta2": "repeat to confirm new password:",
"ta3": "found a typo; please try again",
},
"chi": {
"a1": "更新",
"b1": "你好 &nbsp; <small>(你尚未登录)</small>",
"c1": "登出",
"d1": "状态",
"d2": "显示所有活动线程的状态",
"e1": "重新加载配置",
"e2": "重新加载配置文件(账户/卷/卷标),$N并重新扫描所有 e2ds 卷$N$N注意任何全局设置的更改$N都需要完全重启才能生效",
"f1": "你可以查看:",
"g1": "你可以上传到:",
"cc1": "开关等",
"h1": "关闭 k304",
"i1": "开启 k304",
"j1": "k304 会在每个 HTTP 304 时断开连接。这有助于避免某些代理服务器卡住或突然停止加载页面,但也会显著降低性能。",
"k1": "重置设置",
"l1": "登录:",
"ls3": "登录", //m
"lu4": "用户名", //m
"lp4": "密码", //m
"lo3": "在所有地方注销 {0}", //m
"lo2": "这将结束在所有浏览器中的会话", //m
"m1": "欢迎回来,",
"n1": "404: 文件不存在 &nbsp;┐( ´ -`)┌",
"o1": '或者你可能没有权限?尝试输入密码或 <a href="' + SR + '/?h">回家</a>',
"p1": "403: 访问被拒绝 &nbsp;~┻━┻",
"q1": '尝试输入密码或 <a href="' + SR + '/?h">回家</a>',
"r1": "回家",
".s1": "映射",
"t1": "操作",
"u2": "自上次服务器写入的时间$N( 上传 / 重命名 / ... )$N$N17d = 17 天$N1h23 = 1 小时 23 分钟$N4m56 = 4 分钟 56 秒",
"v1": "连接",
"v2": "将此服务器用作本地硬盘",
"w1": "切换到 https",
"x1": "更改密码",
"y1": "你的分享",
"z1": "解锁区域",
"ta1": "请先输入新密码",
"ta2": "重复以确认新密码:",
"ta3": "发现拼写错误;请重试",
"aa1": "正在接收的文件:", //m
"ab1": "关闭 k304",
"ac1": "开启 k304",
"ad1": "启用 no304 将禁用所有缓存;如果 k304 不够,可以尝试此选项。这将消耗大量的网络流量!", //m
"ae1": "正在下载:", //m
"af1": "显示最近上传的文件", //m
"ag1": "查看已知 IdP 用户", //m
},
"cze": {
"a1": "obnovit",
"b1": "ahoj cizinče &nbsp; <small>(nejsi přihlášen)</small>",
"c1": "odhlásit se",
"d1": "vypsat zásobníku",
"d2": "zobrazit stav všech aktivních vláken",
"e1": "znovu načíst konfiguraci",
"e2": "znovu načíst konfigurační soubory (accounts/volumes/volflags),$Na prohledat všechny e2ds úložiště$N$Npoznámka: všechny změny globálních nastavení$Nvyžadují úplné restartování, aby se projevily",
"f1": "můžeš procházet:",
"g1": "můžeš nahrávat do:",
"cc1": "další věci:",
"h1": "zakázat k304",
"i1": "povolit k304",
"j1": "povolení k304 odpojí vašeho klienta při každém HTTP 304, což může zabránit některým chybovým proxy serverům, aby se zasekly (náhle nenačítaly stránky), <em>ale</em> také to obecně zpomalí věci",
"k1": "resetovat nastavení klienta",
"l1": "přihlaste se pro více:",
"ls3": "přihlásit se", //m
"lu4": "uživatelské jméno", //m
"lp4": "heslo", //m
"lo3": "odhlásit “{0}” všude", //m
"lo2": "tímto ukončíte relaci ve všech prohlížečích", //m
"m1": "vítej zpět,",
"n1": "404 nenalezeno &nbsp;┐( ´ -`)┌",
"o1": 'nebo možná nemáš přístup -- zkus heslo nebo <a href="' + SR + '/?h">jdi domů</a>',
"p1": "403 zakázáno &nbsp;~┻━┻",
"q1": 'použij heslo nebo <a href="' + SR + '/?h">jdi domů</a>',
"r1": "jdi domů",
".s1": "znovu prohledat",
"t1": "akce",
"u2": "čas od posledního zápisu na server$N( upload / rename / ... )$N$N17d = 17 dní$N1h23 = 1 hodina 23 minut$N4m56 = 4 minuty 56 sekund",
"v1": "připojit",
"v2": "použít tento server jako místní HDD",
"w1": "přepnout na https",
"x1": "změnit heslo",
"y1": "upravit sdílení",
"z1": "odblokovat toto sdílení:",
"ta1": "nejprve vyplňte své nové heslo",
"ta2": "zopakujte pro potvrzení nového hesla:",
"ta3": "nalezen překlep; zkuste to prosím znovu",
"aa1": "příchozí soubory:",
"ab1": "deaktivovat no304",
"ac1": "povolit no304",
"ad1": "povolení no304 deaktivuje veškeré mezipaměti; zkuste to, pokud k304 nestačilo. To ovšem zapříčíní obrovské množství síťového provozu!",
"ae1": "aktivní stahování:",
"af1": "zobrazit nedávné nahrávání",
},
"deu": {
"a1": "Neu laden",
"b1": "Tach, wie geht's? &nbsp; <small>(Du bist nicht angemeldet)</small>",
"c1": "Abmelden",
"d1": "Zustand",
"d2": "Zeigt den Zustand aller aktiven Threads",
"e1": "Config neu laden",
"e2": "Konfigurationsdatei neu laden (Accounts/Volumes/VolFlags)$Nund scannt alle e2ds-Volumes$N$NBeachte: Jegliche Änderung an globalen Einstellungen$Nbenötigt einen Neustart zum Anwenden",
"f1": "Du kannst lesen:",
"g1": "Du kannst hochladen nach:",
"cc1": "Andere Dinge:",
"h1": "k304 deaktivieren",
"i1": "k304 aktivieren",
"j1": "k304 trennt die Clientverbindung bei jedem HTTP 304, was Bugs mit problematischen Proxies vorbeugen kann (z.B. nicht ladenden Seiten), macht Dinge aber generell langsamer",
"k1": "Client-Einstellungen zurücksetzen",
"l1": "Melde dich an für mehr:",
"ls3": "Anmelden", //m
"lu4": "Benutzername", //m
"lp4": "Passwort", //m
"lo3": "“{0}” überall abmelden", //m
"lo2": "Dies beendet die Sitzung in allen Browsern", //m
"m1": "Willkommen zurück,",
"n1": "404 Nicht gefunden &nbsp;┐( ´ -`)┌",
"o1": 'or maybe you don\'t have access -- try a password or <a href="' + SR + '/?h">go home</a>',
"p1": "403 Verboten &nbsp;~┻━┻",
"q1": 'Benutze ein Passwort oder <a href="' + SR + '/?h">gehe zur Homepage</a>',
"r1": "Gehe zur Homepage",
".s1": "Neu scannen",
"t1": "Aktion",
"u2": "time since the last server write$N( upload / rename / ... )$N$N17d = 17 days$N1h23 = 1 hour 23 minutes$N4m56 = 4 minutes 56 seconds",
"v1": "Verbinden",
"v2": "Benutze diesen Server als lokale Festplatte",
"w1": "Zu HTTPS wechseln",
"x1": "Passwort ändern",
"y1": "Shares bearbeiten",
"z1": "Share entsperren:",
"ta1": "Trage zuerst dein Passwort ein",
"ta2": "Wiederhole dein Passwort zur Bestätigung:",
"ta3": "Da stimmt etwas nicht; probier's nochmal",
"aa1": "Eingehende Dateien:",
"ab1": "no304 deaktivieren",
"ac1": "no304 aktivieren",
"ad1": "Das Aktivieren von no304 deaktiviert jegliche Form von Caching; probier dies, wenn k304 nicht genug war. Dies verschwendet eine grosse Menge Netzwerk-Traffic!",
"ae1": "Aktive Downloads:",
"af1": "Zeige neue Uploads",
},
"fin": {
"a1": "päivitä",
"b1": "hei sie muukalainen &nbsp; <small>(et ole kirjautunut sisään)</small>",
"c1": "kirjaudu ulos",
"d1": "tulosta pinojälki",
"d2": "näytä kaikkien aktiivisten säikeiden tila",
"e1": "päivitä konffit",
"e2": "lataa konfiguraatiotiedostot uudelleen (käyttäjätilit/asemat/asemaflagit),$Nja skannaa kaikki e2ds asemat uudelleen$N$Nhuom: kaikki global-asetuksiin$Ntehdyt muutokset vaativat täyden$Nuudelleenkäynnistyksen",
"f1": "voit selata näitä:",
"g1": "voit ladata näihin:",
"cc1": "muuta:",
"h1": "poista k304 käytöstä",
"i1": "ota k304 käyttöön",
"j1": "k304 katkaisee yhteytesi jokaisella HTTP 304:llä, mikä voi estää joitain bugisia välityspalvelimia jumittumasta/lopettamasta sivujen lataamista, <em>mutta</em> se myös vähentää suorituskykyä",
"k1": "nollaa asetukset",
"l1": "kirjaudu sisään:",
"ls3": "kirjaudu sisään", //m
"lu4": "käyttäjätunnus", //m
"lp4": "salasana", //m
"lo3": "kirjaa “{0}” ulos kaikkialta", //m
"lo2": "tämä lopettaa istunnon kaikissa selaimissa", //m
"m1": "tervetuloa takaisin,",
"n1": "404: ei löytynyt mitään &nbsp;┐( ´ -`)┌",
"o1": 'tai ehkä sinulla ei vain ole käyttöoikeuksia? kokeile salasanaa tai <a href="' + SR + '/?h">mene kotiin</a>',
"p1": "403: pääsy kielletty &nbsp;~┻━┻",
"q1": 'kokeile salasanaa tai <a href="' + SR + '/?h">mene kotiin</a>',
"r1": "mene kotiin",
".s1": "uudelleenkartoita",
"t1": "toiminto",
"u2": "aika viimeisestä palvelimen kirjoituksesta$N( lataus / uudelleennimeäminen / tms. )$N$N17d = 17 päivää$N1h23 = 1 tunti 23 minuuttia$N4m56 = 4 minuuttia 56 sekuntia",
"v1": "yhdistä",
"v2": "käytä tätä palvelinta paikallisena kiintolevynä",
"w1": "vaihda https:ään",
"x1": "vaihda salasana",
"y1": "muokkaa jakoja",
"z1": "avaa tämä jako:",
"ta1": "täytä ensin uusi salasana",
"ta2": "toista vahvistaaksesi uuden salasanan:",
"ta3": "löytyi kirjoitusvirhe; yritä uudelleen",
"aa1": "saapuvat:",
"ab1": "poista no304 käytöstä",
"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",
"ag1": "näytä tunnetut IdP-käyttäjät",
},
"fra": {
"a1": "rafraîchir",
"b1": "salut étranger &nbsp; <small>(vous n'êtes pas connecté.)</small>",
"c1": "déconnexion",
"d1": "vidange de la pile",
"d2": "affiche l'état de tous les threads actifs",
"e1": "recharger la configuration",
"e2": "recharger le fichier de configuration (comptes/volumes/indicateurs de volume),$Net rescanner tous les volumes e2ds$N$Nnote : n'importe quel changement aux paramètres globaux$Nnécessite un redémarrage complet pour prendre effet",
"f1": "vous pouvez naviguer :",
"g1": "vous pouvez télécharger sur :",
"cc1": "autres choses :",
"h1": "désactiver k304",
"i1": "activer k304",
"j1": "activer k304 va déconnecter votre client sur chaque HTTP 304, ce qui peut éviter à certains proxies défectueux de rester bloqués (les pages ne se chargent soudainement plus), <em>mais</em> cela ralentira également les choses en général",
"k1": "réinitialiser les paramètres du client",
"l1": "connectez-vous pour en savoir plus :",
"ls3": "se connecter", //m
"lu4": "nom d'utilisateur", //m
"lp4": "mot de passe", //m
"lo3": "déconnecter “{0}” partout", //m
"lo2": "cela mettra fin à la session sur tous les navigateurs", //m
"m1": "heureux de vous revoir,",
"n1": "404 introuvable &nbsp;┐( ´ -`)┌",
"o1": 'ou peut-être que vous n\'y avez pas accès -- essayer un mot de passe ou <a href="' + SR + '/?h">aller à la page d\'accueil</a>',
"p1": "403 interdit &nbsp;~┻━┻",
"q1": 'utiliser un mot de passe ou <a href="' + SR + '/?h">aller à la page d\'accueil</a>',
"r1": "aller à la page d\'accueil",
".s1": "rescanner",
"t1": "action",
"u2": "temps écoulé depuis la dernière écriture sur le serveur$N(téléchargement/renommage/...)$N$N17j = 17 jours$N1h23 = 1 heure 23 minutes$N4m56 = 4 minutes 56 secondes",
"v1": "connecter",
"v2": "utilisez ce serveur en tant que disque dur local",
"w1": "passer à https",
"x1": "changer mot de passe",
"y1": "modifier les partages",
"z1": "déverrouiller ce partage :",
"ta1": "entrez d'abord votre nouveau mot de passe",
"ta2": "répétez pour confirmer le nouveau mot de passe :",
"ta3": "une faute de frappe a été détectée ; veuillez réessayer.",
"aa1": "fichiers entrants :",
"ab1": "désactiver no304",
"ac1": "activer no304",
"ad1": "l'activation de no304 désactivera toute mise en cache ; essayez ceci si k304 n'était pas suffisant. Cela va générer un trafic réseau considérable !",
"ae1": "téléchargements actifs :",
"af1": "afficher les derniers téléchargements",
},
"grc": {
"a1": "ανανέωση",
"b1": "γεια σου ξένε! &nbsp; <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": "συνδέσου για περισσότερα:",
"ls3": "σύνδεση", //m
"lu4": "όνομα χρήστη", //m
"lp4": "κωδικός πρόσβασης", //m
"lo3": "αποσύνδεση του “{0}” από παντού", //m
"lo2": "αυτό θα τερματίσει τη συνεδρία σε όλους τους περιηγητές", //m
"m1": "καλώς ήρθες,",
"n1": "404 δεν βρέθηκε &nbsp;┐( ´ -`)┌",
"o1": '´η μήπως δεν έχεις πρόσβαση -- δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>',
"p1": "403 απαγορευμένο &nbsp;~┻━┻",
"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 &nbsp; <small>(non sei connesso)</small>",
"c1": "disconnetti",
"d1": "stato",
"d2": "mostra lo stato di tutti i thread attivi",
"e1": "ricarica configurazione",
"e2": "ricarica i file di configurazione (account/volumi/flag dei volumi),\n e riesegue la scansione di tutti i volumi e2ds.\n\nNota: qualsiasi modifica alle impostazioni globali richiede un riavvio completo per avere effetto",
"f1": "puoi visualizzare:",
"g1": "puoi caricare su:",
"cc1": "altro:",
"h1": "disattiva k304",
"i1": "attiva k304",
"j1": "k304 interrompe la connessione per ogni HTTP 304. Questo aiuta contro alcuni proxy difettosi che possono bloccarsi o smettere improvvisamente di caricare pagine, ma riduce notevolmente le prestazioni",
"k1": "resetta impostazioni",
"l1": "accedi:",
"ls3": "accedi", //m
"lu4": "nome utente", //m
"lp4": "password", //m
"lo3": "disconnetti “{0}” ovunque", //m
"lo2": "questo terminerà la sessione su tutti i browser", //m
"m1": "bentornato,",
"n1": "404: file non trovato &nbsp;┐( ´ -`)┌",
"o1": "oppure forse non hai accesso? prova una password o <a href=\"SR/?h\">torna alla home</a>",
"p1": "403: accesso negato &nbsp;~┻━┻",
"q1": "prova una password o <a href=\"SR/?h\">torna alla home</a>",
"r1": "torna alla home",
".s1": "mappa",
"t1": "azione",
"u2": "tempo dall'ultima scrittura sul server\n (caricamento / rinomina / ...)\n\n17d = 17 giorni\n1h23 = 1 ora 23 minuti\n4m56 = 4 minuti 56 secondi",
"v1": "connetti",
"v2": "usa questo server come un disco locale",
"w1": "passa a https",
"x1": "cambia password",
"y1": "le tue condivisioni",
"z1": "sblocca area:",
"ta1": "devi prima inserire una nuova password",
"ta2": "ripeti per confermare la nuova password:",
"ta3": "errore di digitazione; riprova",
"aa1": "in arrivo:",
"ab1": "disattiva no304",
"ac1": "attiva no304",
"ad1": "no304 disabilita completamente la cache. Se k304 non è sufficiente, prova questa opzione. Aumenterà notevolmente il consumo di dati!",
"ae1": "in uscita:",
"af1": "mostra i file caricati di recente",
"ag1": "mostra utenti IdP conosciuti"
},
"kor": {
"a1": "새로고침",
"b1": "어이 친구! 처음 보는 얼굴인데? &nbsp; <small>(로그인되어 있지 않습니다)</small>",
"c1": "로그아웃",
"d1": "스택 덤프하기",
"d2": "모든 활성 스레드의 상태를 표시합니다",
"e1": "설정 다시 불러오기",
"e2": "설정 파일(계정/볼륨/볼륨 플래그)을 다시 불러오고,$N모든 e2ds 볼륨을 다시 스캔합니다$N$N참고: 전역 설정에 대한 변경 사항은$N적용하려면 전체 재시작이 필요합니다",
"f1": "탐색 가능한 곳:",
"g1": "업로드 가능한 곳:",
"cc1": "기타 항목:",
"h1": "k304 비활성화",
"i1": "k304 활성화",
"j1": "k304를 활성화하면 모든 HTTP 304 응답 시 클라이언트 연결이 끊어집니다. 이는 일부 프록시가 멈추는 현상(갑자기 페이지가 로드되지 않음)을 방지할 수 있지만, <em>대신 전반적인 속도는 느려집니다.</em>",
"k1": "클라이언트 설정 초기화",
"l1": "로그인하기:",
"ls3": "로그인", //m
"lu4": "사용자 이름", //m
"lp4": "비밀번호", //m
"lo3": "{0}을(를) 모든 곳에서 로그아웃", //m
"lo2": "이 작업은 모든 브라우저에서 세션을 종료합니다", //m
"m1": "또 오셨네요,",
"n1": "404 찾을 수 없음 &nbsp;┐( ´ -`)┌",
"o1": "또는 접근 권한이 없을 수 있습니다. 비밀번호를 입력하거나 <a href=\"' + SR + '/?h\">홈으로 이동</a>하세요",
"p1": "403 접근 금지 &nbsp;~┻━┻",
"q1": "비밀번호를 입력하거나 <a href=\"' + SR + '/?h\">홈으로 이동</a>하세요",
"r1": "홈으로 이동",
".s1": "다시 스캔",
"t1": "작업",
"u2": "서버에 마지막으로 쓰기 작업을 한 후 경과된 시간$N(업로드 / 이름 변경 / 등등...)$N$N17d = 17일$N1h23 = 1시간 23분$N4m56 = 4분 56초",
"v1": "연결",
"v2": "이 서버를 로컬 하드디스크처럼 사용하기",
"w1": "HTTPS로 전환",
"x1": "비밀번호 변경",
"y1": "공유 설정",
"z1": "이 공유 잠금해제:",
"ta1": "새 비밀번호를 먼저 입력하세요",
"ta2": "새 비밀번호 확인을 위해 다시 입력하세요:",
"ta3": "오타가 있습니다. 다시 시도해주세요",
"aa1": "수신 중인 파일:",
"ab1": "no304 비활성화",
"ac1": "no304 활성화",
"ad1": "no304를 활성화하면 모든 캐싱이 비활성화됩니다. k304로 충분하지 않은 경우 시도해보세요. 네트워크 트래픽이 대량으로 낭비됩니다!",
"ae1": "활성 다운로드:",
"af1": "최근 업로드 보기",
"ag1": "IdP 캐시 보기"
},
"nld": {
"a1": "Update",
"b1": "Hallo, hoe gaat het met jou? &nbsp; <small>(Je bent niet ingelogd)</small>",
"c1": "Uitloggen",
"d1": "Voorwaarde",
"d2": "Toont de status van alle actieve threads",
"e1": "Configuratie opnieuw laden.",
"e2": "Leest configuratiebestanden opnieuw in$N(accounts, volumes, volumeschakelaars)$Nen brengt alle e2ds-volumes in kaart$N$Nopmerking: veranderingen in globale parameters$Nvereist een volledige herstart van de server",
"f1": "Je kan het volgende lezen:",
"g1": "Je kan naar het volgende uploaden:",
"cc1": "Schakelaars en dergelijke:",
"h1": "k304 uitschakelen",
"i1": "k304 inschakelen",
"j1": "k304 verbreekt de verbinding voor elke HTTP 304. Dit helpt tegen bepaalde proxy servers die kunnen vastlopen/plotseling stoppen met het laden van pagina's, maar het vermindert ook de prestaties aanzienlijk",
"k1": "Instellingen resetten",
"l1": "Inloggen:",
"ls3": "inloggen", //m
"lu4": "gebruikersnaam", //m
"lp4": "wachtwoord", //m
"lo3": "“{0}” overal afmelden", //m
"lo2": "dit zal de sessie in alle browsers beëindigen", //m
"m1": "Welkom terug,",
"n1": "404: bestand bestaat niet &nbsp;┐( ´ -`)┌",
"o1": 'of misschien heb je geen toegang? probeer een wachtwoord of <a href="' + SR + '/?h">ga naar startscherm</a>',
"p1": "403: toegang geweigerd &nbsp;~┻━┻",
"q1": 'Probeer een wachtwoord of <a href="' + SR + '/?h">ga naar startscherm</a>',
"r1": "Ga naar startscherm",
".s1": "Kaart",
"t1": "Actie",
"u2": "Tijd sinds iemand voor het laatst naar de server schreef$N( upload / naamswijziging / ... )$N$N17d = 17 dagen$N1h23 = 1 uur 23 minuten$N4m56 = 4 minuten 56 secondes",
"v1": "Verbinden",
"v2": "Gebruik deze server als een lokale harde schijf",
"w1": "Overschakelen naar https",
"x1": "Wachtwoord wijzigen",
"y1": "Jou gedeelde items",
"z1": "Ontgrendel gebied:",
"ta1": "Je moet eerst een nieuw wachtwoord invoeren",
"ta2": "Herhaal om nieuw wachtwoord te bevestigen:",
"ta3": "Typefout gevonden; probeer het opnieuw",
"aa1": "Inkomend:",
"ab1": "Schakel nr. 304 uit",
"ac1": "Schakel nr. 304 in",
"ad1": "Nr. 304 stopt al het cachegebruik. Als k304 niet voldoende was, probeer dan deze. Vermenigvuldigt het dataverbruik.!",
"ae1": "Uitgaand:",
"af1": "Recent geüploade bestanden weergeven",
"ag1": "Bekende IdP-gebruikers weergeven",
},
"nno": {
"a1": "oppdatér",
"b1": "heisann &nbsp; <small>(du er ikkje logga inn)</small>",
"c1": "logg ut",
"d1": "tilstand",
"d2": "vis tilstanden åt alle trådar",
"e1": "last innst.",
"e2": "les inn konfigurasjonsfiler på nytt$N(kontoer, volum, volumbrytarar)$Nog kartlegg alle e2ds-volum$N$Nmerk: endringer i globale parametrar$Nkrev ein full restart for å gjelde",
"f1": "du kan sjå på:",
"g1": "du kan laste opp åt:",
"cc1": "brytarar og slikt:",
"h1": "skru av k304",
"i1": "skru på k304",
"j1": "k304 bryt tilkoplinga for kvar HTTP 304. Dette hjelp mot visse mellomtjenarar som kan sette seg fast / plutselig sluttar å laste sider, men det sett óg ytinga ned betydelig",
"k1": "nullstill innstillinger",
"l1": "logg inn:",
"ls3": "logg inn",
"lu4": "brukarnamn",
"lp4": "passord",
"lo3": "logg ut “{0}” overalt",
"lo2": "avslutt økta på alle nettlesarar",
"m1": "velkomen attende,",
"n1": "404: filen finnast ikkje &nbsp;┐( ´ -`)┌",
"o1": 'eller kanskje du ikkje har høve? prøv eit passord eller <a href="' + SR + '/?h">gå heim</a>',
"p1": "403: tilgang nektet &nbsp;~┻━┻",
"q1": 'prøv eit passord eller <a href="' + SR + '/?h">gå heim</a>',
"r1": "gå heim",
".s1": "kartlegg",
"t1": "handling",
"u2": "tid sidan nokon sist skreiv åt serveren$N( opplastning / namnendring / ... )$N$N17d = 17 dagar$N1h23 = 1 time 23 minutt$N4m56 = 4 minutt 56 sekund",
"v1": "kople åt",
"v2": "bruk denne serveren som ein lokal harddisk",
"w1": "bytt åt https",
"x1": "bytt passord",
"y1": "dine delinger",
"z1": "lås opp område:",
"ta1": "du må skrive eit nytt passord først",
"ta2": "gjenta for å stadfeste nytt passord:",
"ta3": "fant ein skrivefeil; vennligst prøv igjen",
"aa1": "innkommande:",
"ab1": "skru av no304",
"ac1": "skru på no304",
"ad1": "no304 stoppar all bruk av cache. Hvis ikkje k304 var nok, prøv denne. Vil mangedoble dataforbruk!",
"ae1": "utgående:",
"af1": "vis nylig opplasta filer",
"ag1": "vis kjente IdP-brukarar",
},
"pol": {
"a1": "odśwież",
"b1": "witaj, nieznajomy &nbsp; <small>(nie jesteś zalogowany)</small>",
"c1": "wyloguj się",
"d1": "zrzut stosu",
"d2": "pokazuje status wszystkich aktywnych wątków",
"e1": "przeładuj konfigurację",
"e2": "przeładuj pliki konfiguracyjne (konta/wolumeny/flagi wolumenów),$Ni przeskanuje wszystkie wolumeny e2ds$N$Nnotka: zmiany konfiguracji globalnej$Nwymagają pełnego uruchomienia ponownie serwera, aby zaczęły obowiązywać",
"f1": "możesz przeglądać:",
"g1": "możesz przesyłać do:",
"cc1": "inne:",
"h1": "wyłącz k304",
"i1": "włącz k304",
"j1": "włączenie k304 będzie odłączało klienta przy każdorazowym otrzymaniu kodu HTTP 304, co może zapobiec wieszaniu się wadliwych proxy, <em>ale</em> spowolni ogólne działanie",
"k1": "zresetuj ustawienia klienta",
"l1": "zaloguj się po więcej:",
"ls3": "zaloguj się", //m
"lu4": "nazwa użytkownika", //m
"lp4": "hasło", //m
"lo3": "wyloguj “{0}” wszędzie", //m
"lo2": "spowoduje to zakończenie sesji we wszystkich przeglądarkach", //m
"m1": "Witaj,",
"n1": "404 nie znaleziono &nbsp;┐( ´ -`)┌",
"o1": 'lub możesz nie mieć dostępu -- spróbuj wprowadzić hasło lub <a href="' + SR + '/?h">przejdź do strony głównej</a>',
"p1": "403 odmowa dostępu &nbsp;~┻━┻",
"q1": 'użyj hasła lub <a href="' + SR + '/?h">przejdź do strony głównej</a>',
"r1": "idź do strony głównej",
".s1": "przeskanuj ponownie",
"t1": "akcje",
"u2": "czas od ostatniej interakcji z serwerem$N( przesyłania / zmiany nazwy / ... )$N$N17d = 17 dni$N1h23 = 1 godzina 23 minuty$N4m56 = 4 minuty 56 sekund",
"v1": "połącz",
"v2": "używaj tego serwera jako dysku lokalnego",
"w1": "przejdź na HTTPS",
"x1": "zmień hasło",
"y1": "edytuj udostępnione",
"z1": "odblokuj udostępnienie:",
"ta1": "najpierw wprowadź nowe hasło",
"ta2": "powtórz hasło dla potwierdzenia:",
"ta3": "znaleziono literówkę, spróbuj ponownie",
"aa1": "pliki przychodzące:",
"ab1": "wyłącz no304",
"ac1": "włącz no304",
"ad1": "włączenie no304 wyłączy przechowywanie jakiejkolwiek pamięci podręcznej. Zmarnuje to olbrzymią ilość ruchu sieciowego!",
"ae1": "trwające pobierania:",
"af1": "pokaż ostatnio przesłane pliki",
"ag1": "pokaż znanych użytkowników IdP",
},
"por": {
"a1": "atualizar",
"b1": "olá &nbsp; <small>(você não está logado)</small>",
"c1": "encerrar sessão",
"d1": "despejar o estado da pilha",
"d2": "mostra o estado de todos os threads ativos",
"e1": "recarregar configuração",
"e2": "recarregar arquivos de configuração (contas/volumes/indicadores de volume),$N e reescanear todos os volumes e2ds$N$Nnota: qualquer alteração na configuração global$N requer uma reinicialização completa para ter efeito",
"f1": "você pode navegar:",
"g1": "você pode fazer upload para:",
"cc1": "outras coisas:",
"h1": "desativar k304",
"i1": "ativar k304",
"j1": "ativar k304 irá desconectar seu cliente em cada HTTP 304, o que pode evitar que alguns proxies com erros fiquem presos (parando de carregar páginas de repente), <em>mas</em> também irá desacelerar as coisas em geral",
"k1": "redefinir config. de cliente",
"l1": "faça login para mais:",
"ls3": "fazer login",
"lu4": "nome de usuário",
"lp4": "senha",
"lo3": "encerrar sessão de \"{0}\" em todos os lugares",
"lo2": "isso irá encerrar a sessão em todos os navegadores",
"m1": "bem-vindo de volta,",
"n1": "404 não encontrado &nbsp;┐( ´ -`)┌",
"o1": "ou talvez você não tenha acesso? -- tente com uma senha ou volte para o início",
"p1": "403 proibido &nbsp;~┻━┻",
"q1": "use uma senha ou volte para o início",
"r1": "ir para o início",
".s1": "reescanear",
"t1": "ação",
"u2": "tempo desde a última gravação no servidor$N( upload / renomear / ... )$N$N17d = 17 dias$N1h23 = 1 hora 23 minutos$N4m56 = 4 minutos 56 segundos",
"v1": "conectar",
"v2": "usar este servidor como um disco rígido local",
"w1": "mudar para https",
"x1": "mudar senha",
"y1": "editar recursos compartilhados",
"z1": "desbloquear este recurso compartilhado:",
"ta1": "primeiro digite sua nova senha",
"ta2": "repita para confirmar a nova senha:",
"ta3": "há um erro; por favor, tente novamente",
"aa1": "arquivos de entrada:",
"ab1": "desativar no304",
"ac1": "ativar no304",
"ad1": "ativar no304 irá desabilitar todo o armazenamento em cache; tente isso se k304 não for suficiente. Isso irá desperdiçar uma grande quantidade de tráfego de rede!",
"ae1": "downloads ativos:",
"af1": "mostrar uploads recentes",
"ag1": "mostrar usuários IdP conhecidos"
},
"spa": {
"a1": "actualizar",
"b1": "hola &nbsp; <small>(no has iniciado sesión)</small>",
"c1": "cerrar sesión",
"d1": "volcar estado de la pila",
"d2": "muestra el estado de todos los hilos activos",
"e1": "recargar configuración",
"e2": "recargar archivos de configuración (cuentas/volúmenes/indicadores de vol.),$Ny reescanear todos los volúmenes e2ds$N$Nnota: cualquier cambio en la configuración global$Nrequiere un reinicio completo para surtir efecto",
"f1": "puedes explorar:",
"g1": "puedes subir a:",
"cc1": "otras cosas:",
"h1": "desactivar k304",
"i1": "activar k304",
"j1": "activar k304 desconectará tu cliente en cada HTTP 304, lo que puede evitar que algunos proxies con errores se atasquen (dejando de cargar páginas de repente), <em>pero</em> también ralentizará las cosas en general",
"k1": "restablecer config. de cliente",
"l1": "inicia sesión para más:",
"ls3": "iniciar sesión", //m
"lu4": "nombre de usuario", //m
"lp4": "contraseña", //m
"lo3": "cerrar sesión de “{0}” en todas partes", //m
"lo2": "esto finalizará la sesión en todos los navegadores", //m
"m1": "bienvenido de nuevo,",
"n1": "404 no encontrado &nbsp;┐( ´ -`)┌",
"o1": '¿o quizás no tienes acceso? -- prueba con una contraseña o <a href=\"' + SR + '/?h\">vuelve al inicio</a>',
"p1": "403 prohibido &nbsp;~┻━┻",
"q1": 'usa una contraseña o <a href=\"' + SR + '/?h\">vuelve al inicio</a>',
"r1": "ir al inicio",
".s1": "reescanear",
"t1": "acción",
"u2": "tiempo desde la última escritura en el servidor$N( subida / renombrar / ... )$N$N17d = 17 días$N1h23 = 1 hora 23 minutos$N4m56 = 4 minutos 56 segundos",
"v1": "conectar",
"v2": "usar este servidor como un disco duro local",
"w1": "cambiar a https",
"x1": "cambiar contraseña",
"y1": "editar recursos compartidos",
"z1": "desbloquear este recurso compartido:",
"ta1": "primero escribe tu nueva contraseña",
"ta2": "repite para confirmar la nueva contraseña:",
"ta3": "hay un error; por favor, inténtalo de nuevo",
"aa1": "archivos entrantes:",
"ab1": "desactivar no304",
"ac1": "activar no304",
"ad1": "activar no304 desactivará todo el almacenamiento en caché; prueba esto si k304 no fue suficiente. ¡Esto desperdiciará una gran cantidad de tráfico de red!",
"ae1": "descargas activas:",
"af1": "mostrar subidas recientes",
"ag1": "mostrar usuarios IdP conocidos"
},
"swe": {
"a1": "uppdatera",
"b1": "tjena främling &nbsp; <small>(du är inte inloggad)</small>",
"c1": "logga ut",
"d1": "dumpa stacken",
"d2": "visar tillståndet på alla aktiva trådar",
"e1": "ladda om konfig.",
"e2": "ladda om konfigurationsfiler (konton/volymer/volflaggor),$Noch skanna om alla e2ds-volymer$N$Nobs.: ändrade globala inställningar$Nkräver en fullständig omstart",
"f1": "du kan bläddra:",
"g1": "du kan ladda upp till:",
"cc1": "annat:",
"h1": "avaktivera k304",
"i1": "aktivera k304",
"j1": "med k304 aktiverad kommer klienten att koppla bort sig vid varje HTTP 304-fel, vilket kan hindra vissa buggiga proxyservrar från att fastna (sidor slutar ladda), <em>men</em> saker kommer också att bli långsammare i allmänhet",
"k1": "återställ klientinställningar",
"l1": "logga in för att se mer:",
"ls3": "logga in", //m
"lu4": "användarnamn", //m
"lp4": "lösenord", //m
"lo3": "logga ut “{0}” överallt", //m
"lo2": "avsluta sessionen i alla webbläsare", //m
"m1": "välkommen tillbaka,",
"n1": "404 hittades inte &nbsp;┐( ´ -`)┌",
"o1": 'eller så har du kanske inte tillgång -- prova ett lösenord eller <a href="' + SR + '/?h">åk hem</a>',
"p1": "403 nekat &nbsp;~┻━┻",
"q1": 'använd ett lösenord eller <a href="' + SR + '/?h">åk hem</a>',
"r1": "åk hem",
".s1": "skanna om",
"t1": "åtgärd",
"u2": "tid sedan senaste serverskrivning$N( uppladdning / namnbyte / ... )$N$N17d = 17 dagar$N1h23 = 1 timme 23 minuter$N4m56 = 4 minuter 56 sekunder",
"v1": "koppla upp",
"v2": "använd denna server som en lokal disk",
"w1": "byt till https",
"x1": "byt lösenord",
"y1": "redigera utdelningar",
"z1": "lås upp denna utdelning:",
"ta1": "fyll i ditt nya lösenord",
"ta2": "upprepa det nya lösenordet:",
"ta3": "det blev fel; vänligen försök igen",
"aa1": "inkommande filer:",
"ab1": "avaktivera no304",
"ac1": "aktivera no304",
"ad1": "detta stänger av all cachning; prova detta om k304 inte räckte till. Detta kommer att slösa enorma mängder nätverkstrafik!",
"ae1": "aktiva nedladdningar:",
"af1": "visa senaste uppladdningar",
"ag1": "visa idp-cache"
},
"ukr": {
"a1": "оновити",
"b1": "привітик, незнайомцю &nbsp; <small>(ви не авторизовані)</small>",
"c1": "вийти",
"d1": "трасування стека",
"d2": "показує стан усіх активних потоків",
"e1": "перезавантажити конфіг",
"e2": "перезавантажити файли конфігурації (облікові записи/томи/прапорці),$Nта пересканувати всі томи e2ds$N$Nувага: будь-які зміни глобальних налаштувань$Nвимагають повного перезапуску",
"f1": "ви можете бачити:",
"g1": "ви можете завантажувати файли в:",
"cc1": "всяка всячина:",
"h1": "вимкнути k304",
"i1": "увімкнути k304",
"j1": "увімкнення k304 буде відключати ваш клієнт при кожному HTTP 304, що може запобігти зависанню деяких глючних проксі (раптово перестають завантажувати сторінки), <em>але</em> це також зробить усе повільнішим загалом",
"k1": "скинути налаштування клієнта",
"l1": "авторизуйтесь для інших опцій:",
"ls3": "увійти", //m
"lu4": "ім'я користувача", //m
"lp4": "пароль", //m
"lo3": "вийти з облікового запису “{0}” всюди", //m
"lo2": "це завершить сеанс у всіх браузерах", //m
"m1": "з поверненням,",
"n1": "404 не знайдено &nbsp;┐( ´ -`)┌",
"o1": 'або у вас немає доступу -- спробуйте авторизуватися або <a href="' + SR + '/?h">повернутися на головну</a>',
"p1": "403 доступ заборонений &nbsp;~┻━┻",
"q1": 'авторизуйтесь або <a href="' + SR + '/?h">поверніться на головну</a>',
"r1": "повернутися на головну",
".s1": "пересканувати",
"t1": "дія",
"u2": "час з останнього запису сервера$N( завантаження / перейменування / ... )$N$N17d = 17 днів$N1h23 = 1 година 23 хвилини$N4m56 = 4 хвилини 56 секунд",
"v1": "підключити",
"v2": "використовувати цей сервер як локальний HDD",
"w1": "перейти на https",
"x1": "змінити пароль",
"y1": "керування доступом",
"z1": "розблокувати:",
"ta1": "спочатку заповніть ваш новий пароль",
"ta2": "повторіть для підтвердження нового пароля:",
"ta3": "описка; спробуйте знову",
"aa1": "вхідні файли:",
"ab1": "вимкнути no304",
"ac1": "увімкнути no304",
"ad1": "увімкнення no304 вимкне все кешування; спробуйте це, якщо k304 було недостатньо. Це витратить величезну кількість мережевого трафіку!",
"ae1": "активні завантаження:",
"af1": "показати нещодавні завантаження",
"ag1": "показати відомих IdP-користувачів"
},
"rus": {
"a1": "обновить",
"b1": "приветик, незнакомец &nbsp; <small>(вы не авторизованы)</small>",
"c1": "выйти",
"d1": "трассировка стека",
"d2": "показывает состояние всех активных потоков",
"e1": "перезагрузить конфиг",
"e2": "перезагрузить файлы конфига (аккаунты/хранилища/флаги),$Nи пересканировать все хранилища с флагом e2ds$N$Nвнимание: изменения глобальных настроек$Nтребуют полного перезапуска сервера",
"f1": "вы можете видеть:",
"g1": "вы можете загружать файлы в:",
"cc1": "всякая всячина:",
"h1": "отключить k304",
"i1": "включить k304",
"j1": "включённый k304 будет отключать вас при получении HTTP 304, что может помочь при работе с некоторыми глючными прокси (перестают загружаться страницы), <em>но</em> это также сделает работу клиента медленнее",
"k1": "сбросить локальные настройки",
"l1": "авторизуйтесь для других опций:",
"ls3": "войти", //m
"lu4": "имя пользователя", //m
"lp4": "пароль", //m
"lo3": "выйти из “{0}” везде", //m
"lo2": "это завершит сеанс во всех браузерах", //m
"m1": "с возвращением,",
"n1": "404 не найдено &nbsp;┐( ´ -`)┌",
"o1": 'или у вас нет доступа -- попробуйте авторизоваться или <a href="' + SR + '/?h">вернуться на главную</a>',
"p1": "403 доступ запрещён &nbsp;~┻━┻",
"q1": 'авторизуйтесь или <a href="' + SR + '/?h">вернитесь на главную</a>',
"r1": "вернуться на главную",
".s1": "пересканировать",
"t1": "действия",
"u2": "время с последней записи на сервер$N( загрузка / переименование / ... )$N$N17d = 17 дней$N1h23 = 1 час 23 минут$N4m56 = 4 минут 56 секунд",
"v1": "подключить",
"v2": "использовать сервер как локальный диск",
"w1": "перейти на https",
"x1": "поменять пароль",
"y1": "управление доступом",
"z1": "разблокировать:",
"ta1": "сначала введите свой новый пароль",
"ta2": "повторите новый пароль:",
"ta3": "опечатка; попробуйте снова",
"aa1": "входящие файлы:",
"ab1": "отключить no304",
"ac1": "включить no304",
"ad1": "включённый no304 полностью отключит хеширование; используйте, если k304 не помог. Сильно увеличит объём трафика!",
"ae1": "активные скачивания:",
"af1": "показать недавние загрузки",
"ag1": "показать известных IdP-пользователей",
},
"nop": "ERROR: Password cannot be blank",
"nou": "ERROR: Username and/or password cannot be blank",
}
};
if (window.langmod)
langmod();
var d = Ls[sread("cpp_lang", Object.keys(Ls)) || lang] ||
Ls.eng || Ls.nor || Ls.chi;
var d = (Ls[lang] || Ls.eng).splash;
if (Ls.eng && d !== Ls.eng.splash)
for (var k in Ls.eng.splash)
if (d[k] === undefined)
d[k] = Ls.eng.splash[k];
d.wb = d.w;
@ -893,8 +105,25 @@ if (/\&re=/.test('' + location))
ebi('x').onclick = function (e) {
ev(e);
if (!pwi.value)
return redo(d.ta1);
return ebi('lm').innerHTML = d.ta1;
modal.prompt(d.ta2, "y", mok, null, stars);
};
})();
if (ebi('lf'))
ebi('lf').onsubmit = function() {
var un = ebi('lu');
if (ebi('lp').value && (!un || un.value))
return true;
ebi('lm').innerHTML = un ? d.nou : d.nop;
return false;
};
if (ebi('lp'))
ebi('lp').oninput = function() {
ebi('lm').innerHTML = this.value.length <= 64 ?
'' : 'ERROR: Password too long (max=64)';
};
J_SPL = 2;

View file

@ -10,7 +10,7 @@
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
<style>ul{padding-left:1.3em}li{margin:.4em 0}.txa{float:right;margin:0 0 0 1em}</style>
{{- html_head }}
{{ html_head }}
</head>
<body>
@ -64,7 +64,7 @@
<li>old version of rclone? replace all <code>=</code> with <code>&nbsp;</code> (space)</li>
</ul>
<p>if you want to use the native WebDAV client in windows instead (slow and buggy), first run <a href="{{ r }}/.cpr/a/webdav-cfg.bat">webdav-cfg.bat</a> to remove the 47 MiB filesize limit (also fixes latency and password login), then connect:</p>
<p>if you want to use the native WebDAV client in windows instead (slow and buggy), first run <a href="{{ r }}/.cpr/a/webdav-cfg.txt?dl=webdav-cfg.bat">webdav-cfg.bat</a> to remove the 47 MiB filesize limit (also fixes latency and password login), then connect:</p>
<pre>
{%- if un %}
net use <b>w:</b> http{{ s }}://{{ ep }}/{{ rvp }}{% if accs %} <b>{{ pw }}</b> /user:{{ b_un }}{% endif %}
@ -362,6 +362,11 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ args.theme }}";
{%- if js %}
<script src="{{ js }}_={{ ts }}"></script>
{%- endif %}
<script>
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
jsldp("J_UTL","util");
jsldp("J_SVC","svcs");
</script>
</body>
</html>

View file

@ -1,3 +1,7 @@
"use strict";
var J_SVC = 1;
var oa = QSA('pre');
for (var a = 0; a < oa.length; a++) {
var html = oa[a].innerHTML,
@ -104,3 +108,5 @@ ebi('qr').onclick = function () {
var txt = esc(url) + '<img class="b64" width="100" height="100" src="' + addq(url, 'qr') + '" />';
modal.alert(txt);
};
J_SVC = 2;

710
copyparty/web/tl/chi.js Normal file
View file

@ -0,0 +1,710 @@
// 以 //m 结尾的行是未经验证的机器翻译
Ls.chi = {
"tt": "中文",
"cols": {
"c": "操作按钮",
"dur": "持续时间",
"q": "质量 / 比特率",
"Ac": "音频编码",
"Vc": "视频编码",
"Fmt": "格式 / 容器",
"Ahash": "音频校验和",
"Vhash": "视频校验和",
"Res": "分辨率",
"T": "文件类型",
"aq": "音频质量 / 比特率",
"vq": "视频质量 / 比特率",
"pixfmt": "子采样 / 像素结构",
"resw": "水平分辨率",
"resh": "垂直分辨率",
"chs": "音频频道",
"hz": "采样率",
},
"hks": [
[
"misc",
["ESC", "关闭各种窗口"],
"file-manager",
["G", "切换列表 / 网格视图"],
["T", "切换缩略图 / 图标"],
["⇧ A/D", "缩略图大小"],
["ctrl-K", "删除选中项"],
["ctrl-X", "剪切选中项"],
["ctrl-C", "复制选中项"], //m
["ctrl-V", "粘贴到文件夹"],
["Y", "下载选中项"],
["F2", "重命名选中项"],
"file-list-sel",
["space", "切换文件选择"],
["↑/↓", "移动选择光标"],
["ctrl ↑/↓", "移动光标和视图"],
["⇧ ↑/↓", "选择上一个/下一个文件"],
["ctrl-A", "选择所有文件 / 文件夹"]
], [
"navigation",
["B", "切换面包屑导航 / 导航窗格"],
["I/K", "前一个/下一个文件夹"],
["M", "父文件夹(或折叠当前文件夹)"],
["V", "切换导航窗格中的文件夹 / 文本文件"],
["A/D", "导航窗格大小"]
], [
"audio-player",
["J/L", "上一首/下一首歌曲"],
["U/O", "跳过10秒向前/向后"],
["0..9", "跳转到0%..90%"],
["P", "播放/暂停(也可以启动)"],
["S", "选择正在播放的歌曲"], //m
["Y", "下载歌曲"]
], [
"image-viewer",
["J/L, ←/→", "上一张/下一张图片"],
["Home/End", "第一张/最后一张图片"],
["F", "全屏"],
["R", "顺时针旋转"],
["⇧ R", "逆时针旋转"],
["S", "选择图片"], //m
["Y", "下载图片"]
], [
"video-player",
["U/O", "跳过10秒向前/向后"],
["P/K/Space", "播放/暂停"],
["C", "继续播放下一段"],
["V", "循环"],
["M", "静音"],
["[ and ]", "设置循环区间"]
], [
"textfile-viewer",
["I/K", "前一个/下一个文件"],
["M", "关闭文本文件"],
["E", "编辑文本文件"],
["S", "选择文件(用于剪切/重命名)"],
["Y", "下载文本文件"], //m
["⇧ J", "美化json"], //m
]
],
"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": '前一项">pre',
"gou": '顶部">up',
"gon": '下一项">next',
"logout": " 登出",
"login": "登录", //m
"access": " 访问",
"ot_close": "关闭子菜单",
"ot_search": "按属性、路径/名称、音乐标签或上述内容的任意组合搜索文件$N$N&lt;code&gt;foo bar&lt;/code&gt; = 必须包含 «foo» 和 «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = 包含 «foo» 而不包含 «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = 以 «yama» 为开头的 «opus» 文件$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = 正好包含 «try unite»$N$N时间格式为 iso-8601, 比如:$N&lt;code&gt;2009-12-31&lt;/code&gt; or &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "取消发布:删除最近上传的内容,或中止未完成的内容",
"ot_bup": "bup基础上传器甚至支持 Netscape 4.0",
"ot_mkdir": "mkdir创建新目录",
"ot_md": "new-file创建新的文本文件", //m
"ot_msg": "msg向服务器日志发送消息",
"ot_mp": "媒体播放器选项",
"ot_cfg": "配置选项",
"ot_u2i": 'up2k上传文件如果你有写入权限或切换到搜索模式以查看文件是否存在于服务器上,$N$N上传是可恢复的多线程的保留文件时间戳但比 [🎈]&nbsp;(基础上传器)占用 更多的CPU<br /><br />上传过程中,此图标会变成进度指示器!',
"ot_u2w": 'up2k带有恢复支持的文件上传关闭浏览器后重新上传相同文件$N$N多线程的文件时间戳得以保留但比 [🎈]&nbsp; 基础上传器使用更多CPU<br /><br />上传过程中,这个图标会变成进度指示器!',
"ot_noie": '请使用 Chrome / Firefox / Edge',
"ab_mkdir": "创建目录",
"ab_mkdoc": "新建文本文件", //m
"ab_msg": "发送消息到服务器日志",
"ay_path": "跳转到文件夹",
"ay_files": "跳转到文件",
"wt_ren": "重命名选中的项目$N快捷键: F2",
"wt_del": "删除选中的项目$N快捷键: ctrl-K",
"wt_cut": "剪切选中的项目&lt;small&gt;(然后粘贴到其他地方)&lt;/small&gt;$N快捷键: ctrl-X",
"wt_cpy": "将选中的项目复制到剪贴板&lt;small&gt;(然后粘贴到其他地方)&lt;/small&gt;$N快捷键: ctrl-C", //m
"wt_pst": "粘贴之前剪切/复制的选择$N快捷键: ctrl-V",
"wt_selall": "选择所有文件$N快捷键: ctrl-A当文件被聚焦时",
"wt_selinv": "反转选择",
"wt_zip1": "将此文件夹下载为归档文件", //m
"wt_selzip": "将选择下载为归档文件",
"wt_seldl": "将选择下载为单独的文件$N快捷键: Y",
"wt_npirc": "复制 IRC 格式的曲目信息",
"wt_nptxt": "复制纯文本格式的曲目信息",
"wt_m3ua": "添加到 m3u 播放列表(稍后点击 <code>📻copy</code>", //m
"wt_m3uc": "复制 m3u 播放列表到剪贴板", //m
"wt_grid": "切换网格/列表视图$N快捷键: G",
"wt_prev": "上一曲$N快捷键: J",
"wt_play": "播放/暂停$N快捷键: P",
"wt_next": "下一曲$N快捷键: L",
"ul_par": "并行上传:",
"ut_rand": "随机化文件名",
"ut_u2ts": "将最后修改的时间戳$N从你的文件系统复制到服务器\">📅",
"ut_ow": "覆盖服务器上的现有文件?$N🛡: 从不(会生成一个新文件名)$N🕒: 服务器文件较旧则覆盖$N♻: 如果文件内容不同则总是覆盖$N⏭: 无条件跳过所有已存在的文件", //m
"ut_mt": "在上传时继续哈希其他文件$N$N如果你的 CPU 或硬盘是瓶颈,可能需要禁用",
"ut_ask": '上传开始前询问确认">💭',
"ut_pot": "通过简化 UI 来$N提高慢设备上的上传速度",
"ut_srch": "实际不上传,而是检查文件是否$N已经存在于服务器上将扫描你可以读取的所有文件夹",
"ut_par": "通过将其设置为 0 来暂停上传$N$N如果你的连接很慢/延迟高,$N$N请增加在局域网或服务器硬盘是瓶颈时保持为 1",
"ul_btn": "将文件/文件夹拖放到这里(或点击我)",
"ul_btnu": "上 传",
"ul_btns": "搜 索",
"ul_hash": "哈希",
"ul_send": "发送",
"ul_done": "完成",
"ul_idle1": "没有排队的上传任务",
"ut_etah": "平均 &lt;em&gt;hashing&lt;/em&gt; 速度和估计完成时间",
"ut_etau": "平均 &lt;em&gt;上传&lt;/em&gt; 速度和估计完成时间",
"ut_etat": "平均 &lt;em&gt;总&lt;/em&gt; 速度和估计完成时间",
"uct_ok": "成功完成",
"uct_ng": "失败/拒绝/未找到",
"uct_done": "成功和失败的组合",
"uct_bz": "正在哈希或上传",
"uct_q": "空闲,待处理",
"utl_name": "文件名",
"utl_ulist": "列表",
"utl_ucopy": "复制",
"utl_links": "链接",
"utl_stat": "状态",
"utl_prog": "进度",
// 保持简短:
"utl_404": "404",
"utl_err": "错误",
"utl_oserr": "OS错误",
"utl_found": "已找到",
"utl_defer": "延期",
"utl_yolo": "加速",
"utl_done": "完成",
"ul_flagblk": "文件已添加到队列</b><br>但另一个浏览器标签中有一个繁忙的 up2k<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_hfsz": "文件大小", //m
"cl_themes": "主题",
"cl_langs": "语言",
"cl_ziptype": "文件夹下载",
"cl_uopts": "up2k 开关",
"cl_favico": "网站图标",
"cl_bigdir": "最大目录数",
"cl_hsort": "#sort", //m
"cl_keytype": "键位符号",
"cl_hiddenc": "隐藏列",
"cl_hidec": "隐藏",
"cl_reset": "重置",
"cl_hpick": "点击列标题以在下表中隐藏",
"cl_hcancel": "列隐藏已取消",
"cl_rcm": "右键菜单", //m
"ct_grid": '网格视图',
"ct_ttips": '◔ ◡ ◔"> 工具提示',
"ct_thumb": '在网格视图中,切换图标或缩略图$N快捷键: T">🖼️ 缩略图',
"ct_csel": '在网格视图中使用 CTRL 和 SHIFT 进行文件选择">CTRL',
"ct_dl": '点击文件时强制下载(不内联显示)">dl', //m
"ct_ihop": '当图像查看器关闭时,滚动到最后查看的文件">滚动',
"ct_dots": '显示隐藏文件(如果服务器允许)">隐藏文件',
"ct_qdel": '删除文件时,只需确认一次">快删', //m
"ct_dir1st": '在文件之前排序文件夹">📁 排序',
"ct_nsort": '正确排序以数字开头的文件名">数字排序', //m
"ct_utc": '所有时间请使用UTC">UTC', //m
"ct_readme": '在文件夹列表中显示 README.md">📜 readme',
"ct_idxh": '显示 index.html 代替文件夹列表">htm',
"ct_sbars": '显示滚动条">⟊',
"cut_umod": "如果文件已存在于服务器上,将服务器的最后修改时间戳更新为与你的本地文件匹配(需要写入和删除权限)\">re📅",
"cut_turbo": "YOLO 按钮,你可能不想启用这个:$N$N如果你上传了大量文件并且由于某些原因需要重新启动$N并且想要尽快继续上传使用此选项$N$N这会用简单的 <em>&quot;服务器上的文件大小是否相同?&quot;</em> 替代哈希检查,$N因此如果文件内容不同它将不会被上传$N$N上传完成后你应该关闭此选项$N然后重新&quot;上传&quot;相同的文件以让客户端验证它们\">加速",
"cut_datechk": "除非启用「加速」按钮,否则没有效果$N$N略微减少 YOLO 因素;检查服务器上的文件时间戳是否与你的一致$N$N<em>理论上</em> 应该能捕捉到大多数未完成/损坏的上传,$N但不能替代之后禁用「加速」进行的验证\">日期检查",
"cut_u2sz": "每个上传块的大小(以 MiB 为单位);较大的值跨大西洋传输效果更好。在非常不可靠的连接上尝试较小的值",
"cut_flag": "确保一次只有一个标签页在上传$N -- 其他标签页也必须启用此选项$N -- 仅影响同一域名下的标签页",
"cut_az": "按字母顺序上传文件,而不是按最小文件优先$N$N按字母顺序可以更容易地查看服务器上是否出现了问题但在光纤/局域网上传稍微慢一些",
"cut_nag": "上传完成时的操作系统通知$N仅当浏览器或标签页不活跃时",
"cut_sfx": "上传完成时的声音警报$N仅当浏览器或标签页不活跃时",
"cut_mt": "使用多线程加速文件哈希$N$N这使用 Web Worker 并且需要更多内存(额外最多 512 MiB$N$N这使得 https 快 30%http 快 4.5 倍\">mt",
"cut_wasm": "使用基于 WASM 的哈希计算器代替浏览器内置的哈希功能;这可以提升在基于 Chrome 的浏览器上的速度,但会增加 CPU 使用率,而且许多旧版本的 Chrome 存在漏洞,启用此功能会导致浏览器占用所有内存并崩溃。\">wasm", //m
"cft_text": "网站图标文本(为空并刷新以禁用)",
"cft_fg": "前景色",
"cft_bg": "背景色",
"cdt_lim": "文件夹中显示的最大文件数",
"cdt_ask": "滚动到底部时,$N不会加载更多文件$N而是询问你该怎么做",
"cdt_hsort": "包含在媒体 URL 中的排序规则 (&lt;code&gt;,sorthref&lt;/code&gt;) 数量。将其设置为 0 时,点击媒体链接时也会忽略排序规则。", //m
"cdt_ren": "启用自定义右键菜单,按住 shift 键并右键单击仍可访问常规菜单", //m
"tt_entree": "显示导航面板(目录树侧边栏)$N快捷键: B",
"tt_detree": "显示面包屑导航$N快捷键: B",
"tt_visdir": "滚动到选定的文件夹",
"tt_ftree": "切换文件夹树 / 文本文件$N快捷键: V",
"tt_pdock": "在顶部的停靠窗格中显示父文件夹",
"tt_dynt": "随着树的展开自动增长",
"tt_wrap": "自动换行",
"tt_hover": "悬停时显示溢出的行$N当鼠标光标在左侧边栏中时滚动可能会中断",
"ml_pmode": "在文件夹末尾时...",
"ml_btns": "命令",
"ml_tcode": "转码",
"ml_tcode2": "转换为", //m
"ml_tint": "透明度",
"ml_eq": "音频均衡器",
"ml_drc": "动态范围压缩器",
"mt_loop": "循环播放当前的歌曲\">🔁", //m
"mt_one": "只播放一首歌后停止\">1⃣", //m
"mt_shuf": "在每个文件夹中随机播放歌曲\">🔀",
"mt_aplay": "如果链接中有歌曲 ID则自动播放,禁用此选项将停止在播放音乐时更新页面 URL 中的歌曲 ID以防止在设置丢失但 URL 保留时自动播放\">自动播放▶",
"mt_preload": "在歌曲快结束时开始加载下一首歌,以实现无缝播放\">预加载",
"mt_prescan": "在最后一首歌结束之前切换到下一个文件夹$N保持网页浏览器活跃$N以免停止播放\">自动切换",
"mt_fullpre": "尝试预加载整首歌;$N✅ 在 <b>不可靠</b> 连接上启用,$N❌ 可能在慢速连接上禁用\">加载整首歌",
"mt_fau": "在手机上,如果下一首歌未能快速预加载,防止音乐停止(可能导致标签显示异常)\">☕️",
"mt_waves": "波形进度条:$N显示音频幅度\">进度条",
"mt_npclip": "显示当前播放歌曲的剪贴板按钮\">♪剪切板",
"mt_m3u_c": "显示按钮以将所选歌曲$N复制为 m3u8 播放列表条目\">📻", //m
"mt_octl": "操作系统集成(媒体快捷键 / OSD\">OSD",
"mt_oseek": "允许通过操作系统集成进行跳转$N$N注意在某些设备如 iPhone$N这将替代下一首歌按钮\">seek",
"mt_oscv": "在 OSD 中显示专辑封面\">封面",
"mt_follow": "保持正在播放的曲目滚动到视图中\">🎯",
"mt_compact": "紧凑的控制按钮\">⟎",
"mt_uncache": "清除缓存&nbsp;$N如果你的浏览器缓存了一个损坏的歌曲副本而拒绝播放请尝试此操作\">uncache",
"mt_mloop": "循环打开的文件夹\">🔁 循环",
"mt_mnext": "加载下一个文件夹并继续\">📂 下一首",
"mt_mstop": "停止播放\">⏸ 停止", //m
"mt_cflac": "将 flac / wav 转换为 {0}\">flac",
"mt_caac": "将 aac / m4a 转换为 {0}\">aac",
"mt_coth": "将所有其他(不是 mp3转换为 {0}\">oth",
"mt_c2opus": "适合桌面电脑、笔记本电脑和安卓设备的最佳选择\">opus", //m
"mt_c2owa": "opus-weba适用于 iOS 17.5 及更新版本)\">owa", //m
"mt_c2caf": "opus-caf适用于 iOS 11 到 iOS 17\">caf", //m
"mt_c2mp3": "适用于非常旧的设备\">mp3", //m
"mt_c2flac": "最佳音质,但下载量很大\">flac", //m
"mt_c2wav": "无压缩播放(更占空间)\">wav", //m
"mt_c2ok": "不错的选择!", //m
"mt_c2nd": "这不是您的设备推荐的输出格式,但应该没问题。", //m
"mt_c2ng": "您的设备似乎不支持此输出格式,不过我们还是试试看吧。", //m
"mt_xowa": "iOS 系统仍存在无法后台播放 owa 音乐的错误,请改用 caf 或 mp3 格式。", //m
"mt_tint": "在进度条上设置背景级别0-100",
"mt_eq": "启用均衡器和增益控制;$N$Nboost &lt;code&gt;0&lt;/code&gt; = 标准 100% 音量(默认)$N$Nwidth &lt;code&gt;1 &nbsp;&lt;/code&gt; = 标准立体声(默认)$Nwidth &lt;code&gt;0.5&lt;/code&gt; = 50% 左右交叉反馈$Nwidth &lt;code&gt;0 &nbsp;&lt;/code&gt; = 单声道$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = 人声移除 )$N$N启用均衡器使无缝专辑完全无缝所以如果你在乎这一点请保持启用所有值设为零除了宽度 = 1",
"mt_drc": "启用动态范围压缩器(音量平滑器 / 限幅器);还会启用均衡器以平衡音频,因此如果你不想要它,请将均衡器字段除了 '宽度' 外的所有字段设置为 0$N$N降低 THRESHOLD dB 以上的音频的音量;每超过 THRESHOLD dB 的 RATIO 会有 1 dB 输出,所以默认值 tresh -24 和 ratio 12 意味着它的音量不应超过 -22 dB可以安全地将均衡器增益提高到 0.8,甚至在 ATK 0 和 RLS 如 90 的情况下提高到 1.8(仅在 Firefox 中有效;其他浏览器中 RLS 最大为 1$N$N见维基百科他们解释得更好",
"mb_play": "播放",
"mm_hashplay": "播放这个音频文件?",
"mm_m3u": "按 <code>Enter/确定</code> 播放\n按 <code>ESC/取消</code> 编辑", //m
"mp_breq": "需要 Firefox 82+ 或 Chrome 73+ 或 iOS 15+",
"mm_bload": "正在加载...",
"mm_bconv": "正在转换为 {0},请稍等...",
"mm_opusen": "你的浏览器无法播放 aac / m4a 文件;\n现在启用转码为 opus",
"mm_playerr": "播放失败:",
"mm_eabrt": "播放尝试已取消",
"mm_enet": "你的互联网连接有问题",
"mm_edec": "这个文件可能已损坏??",
"mm_esupp": "你的浏览器不支持这个音频格式",
"mm_eunk": "未知错误",
"mm_e404": "无法播放音频;错误 404文件未找到。",
"mm_e403": "无法播放音频;错误 403访问被拒绝。\n\n尝试按 F5 重新加载,也许你已被注销",
"mm_e500": "无法播放音频;错误 500检查服务器日志。", //m
"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": " 你想查看文件的结尾部分吗?这也将启用实时跟踪功能,能够实时显示新添加的文本行。", //m
"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要选择整个文件夹请先滚动到底部", //m
"f_dls": '当前文件夹中的文件链接已\n更改为下载链接',
"f_partial": "要安全下载正在上传的文件,请点击没有 <code>.PARTIAL</code> 文件扩展名的同名文件。请按取消或 Escape 执行此操作。\n\n按 确定 / 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": "选择至少一个要复制到剪贴板的项目", //m
"fs_sc": "分享你所在的文件夹",
"fs_ss": "分享选定的文件",
"fs_just1d": "你不能同时选择多个文件夹,也不能同时选择文件夹和文件",
"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/确定</code> 复制到剪贴板\n按 <code>ESC/取消</code> 关闭",
"frt_dec": "可能修复一些损坏的文件名\">url-decode",
"frt_rst": "将修改后的文件名重置为原始文件名\">↺ 重置",
"frt_abrt": "中止并关闭此窗口\">❌ 取消",
"frb_apply": "应用重命名",
"fr_adv": "批量 / 元数据 / 模式重命名\">高级",
"fr_case": "区分大小写的正则表达式\">case",
"fr_win": "Windows 安全名称;将 <code>&lt;&gt;:&quot;\\|?*</code> 替换为日文全角字符\">win",
"fr_slash": "将 <code>/</code> 替换为不会导致新文件夹创建的字符\">不使用 /",
"fr_re": "正则表达式搜索模式应用于原始文件名;$N可以在下面的格式字段中引用捕获组如&lt;code&gt;(1)&lt;/code&gt;和&lt;code&gt;(2)&lt;/code&gt;等等。",
"fr_fmt": "受到 foobar2000 的启发:$N&lt;code&gt;(title)&lt;/code&gt; 被歌曲名称替换,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; 仅当歌曲艺术家不为空时才包含&lt;code&gt;[此]&lt;/code&gt;部分$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; 将曲目编号填充为 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": "删除成功",
"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> 浏览器标签页可以粘贴它们\n因为选择非常庞大',
"fcc_ok": "已将 {0} 项复制到剪贴板", //m
"fcc_warn": '已将 {0} 项复制到剪贴板\n\n但只有 <b>这个</b> 浏览器标签页可以粘贴它们\n因为选择非常庞大', //m
"fp_apply": "确认并立即粘贴", //m
"fp_skip": "跳过冲突", //m
"fp_ecut": "首先剪切或复制一些文件/文件夹以粘贴/移动\n\n注意你可以在不同的浏览器标签页之间剪切/粘贴", //m
"fp_ename": "{0} 项不能移动到这里,因为名称已被占用。请在下方输入新名称以继续,或将名称留空(“跳过冲突”)以跳过这些项:", //m
"fcp_ename": "{0} 项不能复制到这里,因为名称已被占用。请在下方输入新名称以继续,或将名称留空(“跳过冲突”)以跳过这些项:", //m
"fp_emore": "还有一些文件名冲突需要解决", //m
"fp_ok": "移动成功",
"fcp_ok": "复制成功", //m
"fp_busy": "正在移动 {0} 项...\n\n{1}",
"fcp_busy": "正在复制 {0} 项...\n\n{1}", //m
"fp_abrt": "正在中止...", //m
"fp_err": "移动失败:\n",
"fcp_err": "复制失败:\n", //m
"fp_confirm": "将这些 {0} 项移动到这里?",
"fcp_confirm": "将这些 {0} 项复制到这里?", //m
"fp_etab": '无法从其他浏览器标签页读取剪贴板',
"fp_name": "从你的设备上传一个文件。给它一个名字:",
"fp_both_m": '<h6>选择粘贴内容</h6><code>Enter</code> = 从 «{1}» 移动 {0} 个文件\n<code>ESC</code> = 从你的设备上传 {2} 个文件',
"fcp_both_m": '<h6>选择粘贴内容</h6><code>Enter</code> = 从 «{1}» 复制 {0} 个文件\n<code>ESC</code> = 从你的设备上传 {2} 个文件', //m
"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>', //m
"mk_noname": "在左侧文本框中输入名称,然后再执行此操作 :p",
"nmd_i1": "还可以添加需要的文件扩展名,例如 <code>.md</code>", //m
"nmd_i2": "由于没有删除权限,你只能创建 <code>.md</code> 文件", //m
"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": "选择文件&nbsp;(用于剪切/删除/...$N快捷键: S\">选择",
"tvt_j": "美化json$N快捷键: shift-J\">j", //m
"tvt_edit": "在文本编辑器中打开文件$N快捷键: E\">✏️ 编辑",
"tvt_tail": "监视文件更改,并实时显示新增的行\">📡 跟踪", //m
"tvt_wrap": "自动换行\">↵", //m
"tvt_atail": "锁定到底部,显示最新内容\">⚓", //m
"tvt_ctail": "解析终端颜色ANSI 转义码)\">🌈", //m
"tvt_ntail": "滚动历史上限(保留多少字节的文本)", //m
"m3u_add1": "歌曲已添加到 m3u 播放列表", //m
"m3u_addn": "已添加 {0} 首歌曲到 m3u 播放列表", //m
"m3u_clip": "m3u 播放列表已复制到剪贴板\n\n请创建一个以 <code>.m3u</code> 结尾的文本文件,\n并将播放列表粘贴到该文件中\n这样就可以播放了", //m
"gt_vau": "不显示视频,仅播放音频\">🎧",
"gt_msel": "启用文件选择;按住 ctrl 键点击文件以覆盖$N$N&lt;em&gt;当启用时:双击文件/文件夹以打开它&lt;/em&gt;$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": "路径包含 &nbsp;(空格分隔)",
"s_f1": "名称包含 &nbsp;(用 -nope 否定)",
"s_t1": "标签包含 &nbsp;^=开头,$=结尾)",
"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": "无法从服务器加载未发布列表:\n\n错误 ",
"fu_xe2": "404: 文件未找到??",
"fz_tar": "未压缩的 gnu-tar 文件linux / mac",
"fz_pax": "未压缩的 pax 格式 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.04g1993 年 10 月)$N处理时间较长在下载开始之前",
"un_m1": "你可以删除下面的近期上传(或中止未完成的上传)",
"un_upd": "刷新",
"un_m4": "或分享下面可见的文件:",
"un_ulist": "显示",
"un_ucopy": "复制",
"un_flt": "可选过滤器:&nbsp; URL 必须包含",
"un_fclr": "清除过滤器",
"un_derr": '未发布删除失败:\n',
"un_f5": '出现问题,请尝试刷新或按 F5',
"un_uf5": "抱歉,你必须刷新页面(例如,按 F5 或 CTRL-R然后才能中止此上传",
"un_nou": '<b>警告:</b> 服务器太忙,无法显示未完成的上传;稍后点击“刷新”链接',
"un_noc": '<b>警告:</b> 服务器配置中未启用/允许完全上传文件的取消发布',
"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": '你的浏览器非常古老 -- 也许你应该 <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": '浏览器版本低,不支持通过拖动文件到窗口来上传文件',
"u_notdir": "不是文件夹!\n\n您的浏览器太旧\n请尝试将文件夹拖入窗口",
"u_uri": "要从其他浏览器窗口拖放图片,\n请将其拖放到大的上传按钮上",
"u_enpot": '切换到 <a href="#">简约 UI</a>(可能提高上传速度)',
"u_depot": '切换到 <a href="#">精美 UI</a>(可能降低上传速度)',
"u_gotpot": '切换到简化UI以提高上传速度\n\n随时可以不同意并切换回去',
"u_pott": "<p>个文件: &nbsp; <b>{0}</b> 已完成, &nbsp; <b>{1}</b> 失败, &nbsp; <b>{2}</b> 正在处理, &nbsp; <b>{3}</b> 排队中</p>",
"u_ever": "这是基本的上传工具; up2k 需要至少<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
"u_su2k": '这是基本的上传工具;<a href="#" id="u2yea">up2k</a> 更好',
"u_uput": '提高速度(跳过校验和)',
"u_ewrite": '你对这个文件夹没有写入权限',
"u_eread": '你对这个文件夹没有读取权限',
"u_enoi": '文件搜索在服务器配置中未启用',
"u_enoow": "无法覆盖此处的文件;需要删除权限", //m
"u_badf": '这些 {0} 个文件(共 {1} 个)被跳过,可能是由于文件系统权限:\n\n',
"u_blankf": '这些 {0} 个文件(共 {1} 个)是空白的;是否仍然上传?\n\n',
"u_applef": "这些 {0} 个文件(共 {1} 个)可能是不需要的;\n按 <code>确定/Enter</code> 跳过以下文件,\n按 <code>取消/ESC</code> 取消排除,并上传这些文件:\n\n", //m
"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": "此上传将在 {0} 后从服务器删除",
"u_asku": '将这些 {0} 个文件上传到 <code>{1}</code>',
"u_unpt": "你可以使用左上角的 🧯 撤销/删除此上传",
"u_bigtab": '将显示 {0} 个文件,可能会导致您的浏览器崩溃。您确定吗?',
"u_scan": '正在扫描文件...',
"u_dirstuck": '您的浏览器无法访问以下 {0} 个文件/文件夹,它们将被跳过:',
"u_etadone": '完成 ({0}, {1} 个文件)',
"u_etaprep": '(准备上传)',
"u_hashdone": '哈希完成',
"u_hashing": '哈希',
"u_hs": '正在等待服务器...',
"u_started": "文件现在正在上传 🚀", //m
"u_dupdefer": "这是一个重复文件。它将在所有其他文件上传后进行处理",
"u_actx": "单击此文本以防止切换到其他窗口/选项卡时性能下降",
"u_fixed": "好!&nbsp;已修复 👍",
"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": "进行上传握手时的网络错误;正在重试...",
"u_enethd": "测试目标存在时的网络错误;正在重试...",
"u_cbusy": "等待服务器在网络故障后再次信任我们...",
"u_ehsdf": "服务器磁盘空间不足!\n\n将继续重试以防有人\n释放足够的空间以继续",
"u_emtleak1": "看起来你的网页浏览器可能有内存泄漏;\n请",
"u_emtleak2": ' <a href="{0}">切换到 https推荐</a> 或 ',
"u_emtleak3": ' ',
"u_emtleakc": '尝试以下操作:\n<ul><li>按 <code>F5</code> 刷新页面</li><li>然后在&nbsp;<code>⚙️ 设置</code> 中禁用&nbsp;<code>mt</code>&nbsp;按钮</li><li>然后再次尝试上传</li></ul>上传会稍微慢一些,不过没关系。\n抱歉带来麻烦\n\nPSchrome 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>然后在上传 UI 中启用 <code>🥔</code>(土豆)<li>然后再次尝试上传</li></ul>\nPS: firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">希望会在某个时点修复此问题</a>',
"u_s404": "在服务器上未找到",
"u_expl": "解释",
"u_maxconn": "大多数浏览器限制为 6但 Firefox 允许你通过 <code>connections-per-server</code> 在 <code>about:config</code> 中提高限制",
"u_tu": '<p class="warn">警告:启用了 turbo<span>&nbsp;客户端可能无法检测和恢复不完整的上传;查看 turbo 按钮工具提示</span></p>',
"u_ts": '<p class="warn">警告:启用了 turbo<span>&nbsp;搜索结果可能不正确;查看 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": '允许取消发布 {0}',
"u_unp_ng": '取消发布将不被允许',
"ue_ro": '你对这个文件夹的访问是只读的\n\n',
"ue_nl": '你当前未登录',
"ue_la": '你当前以 "{0}" 登录',
"ue_sr": '你当前处于文件搜索模式\n\n通过点击大搜索按钮旁边的放大镜 🔎 切换到上传模式,然后重试上传\n\n抱歉',
"ue_ta": '尝试再次上传,现在应该能正常工作',
"ue_ab": "这份文件正在上传到另一个文件夹,必须完成该上传后,才能将文件上传到其他位置。\n\n您可以通过左上角的🧯中止并忘记该上传。", //m
"ur_1uo": "成功:文件上传成功",
"ur_auo": "成功:所有 {0} 个文件上传成功",
"ur_1so": "成功:文件在服务器上找到",
"ur_aso": "成功:所有 {0} 个文件在服务器上找到",
"ur_1un": "上传失败,抱歉",
"ur_aun": "所有 {0} 个上传失败,抱歉",
"ur_1sn": "文件未在服务器上找到",
"ur_asn": "这些 {0} 个文件未在服务器上找到",
"ur_um": "完成;\n{0} 个上传成功,\n{1} 个上传失败,抱歉",
"ur_sm": "完成;\n{0} 个文件在服务器上找到,\n{1} 个文件未在服务器上找到",
"rc_opn": "打开", //m
"rc_ply": "播放", //m
"rc_pla": "作为音频播放", //m
"rc_txt": "在文件查看器中打开", //m
"rc_md": "在文本编辑器中打开", //m
"rc_dl": "下载", //m
"rc_zip": "下载为压缩包", //m
"rc_del": "删除", //m
"rc_cut": "剪切", //m
"rc_cpy": "复制", //m
"rc_pst": "粘贴", //m
"rc_nfo": "新建文件夹", //m
"rc_nfi": "新建文件", //m
"rc_sal": "全选", //m
"rc_sin": "反选", //m
"lang_set": "刷新以使更改生效?",
"splash": {
"a1": "更新",
"b1": "你好 &nbsp; <small>(你尚未登录)</small>",
"c1": "登出",
"d1": "状态",
"d2": "显示所有活动线程的状态",
"e1": "重新加载配置",
"e2": "重新加载配置文件(账户/卷/卷标),$N并重新扫描所有 e2ds 卷$N$N注意任何全局设置的更改$N都需要完全重启才能生效",
"f1": "你可以查看:",
"g1": "你可以上传到:",
"cc1": "开关等",
"h1": "关闭 k304",
"i1": "开启 k304",
"j1": "k304 会在每个 HTTP 304 时断开连接。这有助于避免某些代理服务器卡住或突然停止加载页面,但也会显著降低性能。",
"k1": "重置设置",
"l1": "登录:",
"ls3": "登录", //m
"lu4": "用户名", //m
"lp4": "密码", //m
"lo3": "在所有地方注销 {0}", //m
"lo2": "这将结束在所有浏览器中的会话", //m
"m1": "欢迎回来,",
"n1": "404: 文件不存在 &nbsp;┐( ´ -`)┌",
"o1": '或者你可能没有权限?尝试输入密码或 <a href="' + SR + '/?h">回家</a>',
"p1": "403: 访问被拒绝 &nbsp;~┻━┻",
"q1": '尝试输入密码或 <a href="' + SR + '/?h">回家</a>',
"r1": "回家",
".s1": "映射",
"t1": "操作",
"u2": "自上次服务器写入的时间$N( 上传 / 重命名 / ... )$N$N17d = 17 天$N1h23 = 1 小时 23 分钟$N4m56 = 4 分钟 56 秒",
"v1": "连接",
"v2": "将此服务器用作本地硬盘",
"w1": "切换到 https",
"x1": "更改密码",
"y1": "你的分享",
"z1": "解锁区域",
"ta1": "请先输入新密码",
"ta2": "重复以确认新密码:",
"ta3": "发现拼写错误;请重试",
"nop": "错误:密码不能为空", //m
"nou": "错误:用户名和/或密码不能为空", //m
"aa1": "正在接收的文件:", //m
"ab1": "关闭 k304",
"ac1": "开启 k304",
"ad1": "启用 no304 将禁用所有缓存;如果 k304 不够,可以尝试此选项。这将消耗大量的网络流量!", //m
"ae1": "正在下载:", //m
"af1": "显示最近上传的文件", //m
"ag1": "查看已知 IdP 用户", //m
}
};

714
copyparty/web/tl/cze.js Normal file
View file

@ -0,0 +1,714 @@
// Řádky končící na //m jsou neověřené strojové překlady
Ls.cze = {
"tt": "Čeština",
"cols": {
"c": "tlačítka akcí",
"dur": "doba trvání",
"q": "kvalita / bitrate",
"Ac": "audio kodek",
"Vc": "video kodek",
"Fmt": "formát / kontejner",
"Ahash": "kontrolní součet audia",
"Vhash": "kontrolní součet videa",
"Res": "rozlišení",
"T": "typ souboru",
"aq": "kvalita zvuku / bitrate",
"vq": "kvalita videa / bitrate",
"pixfmt": "podvzorkování / struktura pixelů",
"resw": "horizontální rozlišení",
"resh": "vertikální rozlišení",
"chs": "audio kanály",
"hz": "vzorkovací frekvence",
},
"hks": [
[
"různé",
["ESC", "zavřít různé věci"],
"správce souborů",
["G", "přepnout seznam / zobrazení mřížky"],
["T", "přepnout náhledy / ikony"],
["⇧ A/D", "velikost náhledů"],
["ctrl-K", "smazat vybrané"],
["ctrl-X", "vyjmout výběr do schránky"],
["ctrl-C", "kopírovat výběr do schránky"],
["ctrl-V", "vložit (přesunout/kopírovat) zde"],
["Y", "stáhnout vybrané"],
["F2", "přejmenovat vybrané"],
"výběr souborů",
["space", "přepnout výběr souboru"],
["↑/↓", "posunout kurzor výběru"],
["ctrl ↑/↓", "posunout kurzor a zobrazení"],
["⇧ ↑/↓", "vybrat předchozí/následující soubor"],
["ctrl-A", "vybrat všechny soubory / složky"],
], [
"navigace",
["B", "přepnout drobečkovou navigaci / navigační panel"],
["I/K", "předchozí/následující složka"],
["M", "nadřazená složka (nebo sbalit aktuální)"],
["V", "přepnout složky / textové soubory v navigačním panelu"],
["A/D", "velikost navigačního panelu"],
], [
"audio přehrávač",
["J/L", "předchozí/následující skladba"],
["U/O", "přeskočit 10 sekund zpět/vpřed"],
["0..9", "přejít na 0%..90%"],
["P", "přehrát/pozastavit (také spustit)"],
["S", "vybrat přehrávanou skladbu"],
["Y", "stáhnout skladbu"],
], [
"prohlížeč obrázků",
["J/L, ←/→", "předchozí/následující obrázek"],
["Home/End", "první/poslední obrázek"],
["F", "celá obrazovka"],
["R", "otočit po směru hodinových ručiček"],
["⇧ R", "otočit proti směru hodinových ručiček"],
["S", "vybrat obrázek"],
["Y", "stáhnout obrázek"],
], [
"video přehrávač",
["U/O", "přeskočit 10 sekund zpět/vpřed"],
["P/K/Space", "přehrát/pozastavit"],
["C", "pokračovat přehráváním následující"],
["V", "smyčka"],
["M", "ztlumit"],
["[ and ]", "nastavit interval smyčky"],
], [
"prohlížeč textových souborů",
["I/K", "předchozí/následující soubor"],
["M", "zavřít textový soubor"],
["E", "upravit textový soubor"],
["S", "vybrat soubor (pro vyjmutí/kopírování/přejmenování)"],
["Y", "stáhnout textový soubor"], //m
["⇧ J", "zkrášlit json"], //m
]
],
"m_ok": "OK",
"m_ng": "Zrušit",
"enable": "Povolit",
"danger": "NEBEZPEČÍ",
"clipped": "zkopírováno do schránky",
"ht_s1": "sekunda",
"ht_s2": "sekundy",
"ht_s5": "sekund",
"ht_m1": "minuta",
"ht_m2": "minuty",
"ht_m5": "minut",
"ht_h1": "hodina",
"ht_h2": "hodiny",
"ht_h5": "hodin",
"ht_d1": "den",
"ht_d2": "dny",
"ht_d5": "dní",
"ht_and": " a ",
"goh": "ovládací panel",
"gop": 'předchozí sourozenec">předchozí',
"gou": 'nadřazená složka">nahoru',
"gon": 'následující složka">následující',
"logout": "Odhlásit ",
"login": "Přihlásit se", //m
"access": " přístup",
"ot_close": "zavřít podnabídku",
"ot_search": "hledat soubory podle atributů, cesty / názvu, hudebních tagů nebo jejich kombinace$N$N&lt;code&gt;foo bar&lt;/code&gt; = musí obsahovat jak «foo» tak «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = musí obsahovat «foo» ale ne «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = začíná na «yana» a je to «opus» soubor$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = obsahuje přesně «try unite»$N$Nformát data je iso-8601, jako$N&lt;code&gt;2009-12-31&lt;/code&gt; nebo &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: smazat vaše nedávné nahrání nebo zrušit nedokončené",
"ot_bup": "bup: základní nahrávač, podporuje i netscape 4.0",
"ot_mkdir": "mkdir: vytvořit nový adresář",
"ot_md": "new-file: vytvořit nový textový soubor", //m
"ot_msg": "msg: poslat zprávu do logu serveru",
"ot_mp": "možnosti přehrávače médií",
"ot_cfg": "možnosti konfigurace",
"ot_u2i": 'up2k: nahrát soubory (pokud máte oprávnění k zápisu) nebo přepnout do vyhledávacího režimu a podívat se, zda existují někde na serveru$N$Nnahrávání je obnovitelné, vícevláknové a časové značky souborů jsou zachovány, ale používá více CPU než [🎈]&nbsp; (základní nahrávač)<br /><br />během nahrávání se tato ikona stává indikátorem průběhu!',
"ot_u2w": 'up2k: nahrát soubory s podporou obnovení (zavřete prohlížeč a stejné soubory přetáhněte později)$N$Nvícevláknové a časové značky souborů jsou zachovány, ale používá více CPU než [🎈]&nbsp; (základní nahrávač)<br /><br />během nahrávání se tato ikona stává indikátorem průběhu!',
"ot_noie": 'Prosím použijte Chrome / Firefox / Edge',
"ab_mkdir": "vytvořit adresář",
"ab_mkdoc": "nový textový soubor", //m
"ab_msg": "poslat zprávu do logu serveru",
"ay_path": "přejít na složky",
"ay_files": "přejít na soubory",
"wt_ren": "přejmenovat vybrané položky$NKlávesová zkratka: F2",
"wt_del": "smazat vybrané položky$NKlávesová zkratka: ctrl-K",
"wt_cut": "vyjmout vybrané položky &lt;small&gt;(pak je vložit někam jinam)&lt;/small&gt;$NKlávesová zkratka: ctrl-X",
"wt_cpy": "kopírovat vybrané položky do schránky$N(pro vložení někam jinam)$NKlávesová zkratka: ctrl-C",
"wt_pst": "vložit dříve vyjmutý / zkopírovaný výběr$NKlávesová zkratka: ctrl-V",
"wt_selall": "vybrat všechny soubory$NKlávesová zkratka: ctrl-A (když je zaměřen soubor)",
"wt_selinv": "invertovat výběr",
"wt_zip1": "stáhnout tuto složku jako archiv",
"wt_selzip": "stáhnout výběr jako archiv",
"wt_seldl": "stáhnout výběr jako samostatné soubory$NKlávesová zkratka: Y",
"wt_npirc": "kopírovat informace o stopě ve formátu irc",
"wt_nptxt": "kopírovat informace o stopě v prostém textu",
"wt_m3ua": "přidat do m3u playlistu (klikněte později na <code>📻kopírovat</code>)",
"wt_m3uc": "kopírovat m3u playlist do schránky",
"wt_grid": "přepnout zobrazení mřížky / seznamu$NKlávesová zkratka: G",
"wt_prev": "předchozí stopa$NKlávesová zkratka: J",
"wt_play": "přehrát / pozastavit$NKlávesová zkratka: P",
"wt_next": "následující stopa$NKlávesová zkratka: L",
"ul_par": "paralelní nahrávání:",
"ut_rand": "náhodné názvy souborů",
"ut_u2ts": "kopírovat časovou značku poslední změny$Nz vašeho souborového systému na server\">📅",
"ut_ow": "přepsat existující soubory na serveru?$N🛡: nikdy (místo toho vytvoří nový název souboru)$N🕒: přepsat pokud je soubor na serveru starší než váš$N♻: vždy přepsat pokud se soubory liší$N⏭: bezpodmínečně přeskočit všechny existující soubory", //m
"ut_mt": "pokračovat v hashování ostatních souborů během nahrávání$N$Nmožná zakázat pokud je vaše CPU nebo HDD bottleneckem",
"ut_ask": 'požádat o potvrzení před zahájením nahrávání">💭',
"ut_pot": "zlepšit rychlost nahrávání na pomalých zařízeních$Nzjednodušením UI",
"ut_srch": "skutečně nenahrávat, místo toho zkontrolovat zda soubory již $N existují na serveru (prohledá všechny složky které můžete číst)",
"ut_par": "pozastavit nahrávání nastavením na 0$N$Nzvýšit pokud je vaše připojení pomalé / vysoká latence$N$Nponechat na 1 v LAN nebo pokud je HDD serveru bottleneckem",
"ul_btn": "přetáhněte soubory / složky<br>sem (nebo sem klikněte)",
"ul_btnu": "N A H R Á T",
"ul_btns": "H L E D A T",
"ul_hash": "hash",
"ul_send": "odeslat",
"ul_done": "hotovo",
"ul_idle1": "zatím nejsou zařazena žádná nahrávání",
"ut_etah": "průměrná rychlost &lt;em&gt;hashování&lt;/em&gt; a odhadovaný čas do dokončení",
"ut_etau": "průměrná rychlost &lt;em&gt;nahrávání&lt;/em&gt; a odhadovaný čas do dokončení",
"ut_etat": "průměrná &lt;em&gt;celková&lt;/em&gt; rychlost a odhadovaný čas do dokončení",
"uct_ok": "úspěšně dokončeno",
"uct_ng": "nedobré: selhalo / odmítnuto / nenalezeno",
"uct_done": "celkem",
"uct_bz": "hashování nebo nahrávání",
"uct_q": "nečinné, čekající",
"utl_name": "název souboru",
"utl_ulist": "seznam",
"utl_ucopy": "kopírovat",
"utl_links": "odkazy",
"utl_stat": "stav",
"utl_prog": "průběh",
// keep short:
"utl_404": "404",
"utl_err": "CHYBA",
"utl_oserr": "chyba OS",
"utl_found": "nalezeno",
"utl_defer": "odložit",
"utl_yolo": "YOLO",
"utl_done": "hotovo",
"ul_flagblk": "soubory byly přidány do fronty</b><br>nicméně v jiné kartě prohlížeče běží up2k,<br>takže čekáme až skončí",
"ul_btnlk": "konfigurace serveru uzamkla tento přepínač v tomto stavu",
"udt_up": "Nahrávání",
"udt_srch": "Hledání",
"udt_drop": "přetáhněte to sem",
"u_nav_m": '<h6>jasnačka, co máte?</h6><code>Enter</code> = Soubory (jeden nebo více)\n<code>ESC</code> = Jednu složku (včetně podsložek)',
"u_nav_b": '<a href="#" id="modal-ok">Soubory</a><a href="#" id="modal-ng">Jedna složka</a>',
"cl_opts": "přepínače",
"cl_hfsz": "velikost souboru", //m
"cl_themes": "téma",
"cl_langs": "jazyk",
"cl_ziptype": "stahování složky",
"cl_uopts": "up2k přepínače",
"cl_favico": "favicon",
"cl_bigdir": "velké adresáře",
"cl_hsort": "#řazení",
"cl_keytype": "notace kláves",
"cl_hiddenc": "skryté sloupce",
"cl_hidec": "skrýt",
"cl_reset": "resetovat",
"cl_hpick": "klepněte na záhlaví sloupců pro skrytí v tabulce níže",
"cl_hcancel": "skrývání sloupců zrušeno",
"cl_rcm": "kontextová nabídka", //m
"ct_grid": '田 mřížka',
"ct_ttips": '◔ ◡ ◔"> nápovědy',
"ct_thumb": 'v zobrazení mřížky přepnout ikony nebo náhledy$NKlávesová zkratka: T">🖼️ náhledy',
"ct_csel": 'použít CTRL a SHIFT pro výběr souborů v zobrazení mřížky">výběr',
"ct_dl": 'vynutit stažení (nezobrazovat inline) při kliknutí na soubor">dl', //m
"ct_ihop": 'když se zavře prohlížeč obrázků, posunout dolů k naposledy zobrazenému souboru">g⮯',
"ct_dots": 'zobrazit skryté soubory (pokud to server povoluje)">dotfiles',
"ct_qdel": 'při mazání souborů požádat o potvrzení jen jednou">rychlé mazání',
"ct_dir1st": 'řadit složky před soubory">📁 první',
"ct_nsort": 'přirozené řazení (pro názvy souborů s úvodními číslicemi)">přirozené řazení',
"ct_utc": 'zobrazit všechny časy v UTC">UTC',
"ct_readme": 'zobrazit README.md v seznamech složek">📜 readme',
"ct_idxh": 'zobrazit index.html místo seznamu složky">htm',
"ct_sbars": 'zobrazit posuvníky">⟊',
"cut_umod": "pokud soubor na serveru již existuje, aktualizovat časovou značku posledního změny serveru tak, aby odpovídala vašemu lokálnímu souboru (vyžaduje oprávnění k zápisu+mazání)\">re📅",
"cut_turbo": "yolo tlačítko, pravděpodobně to NECHCETE povolit:$N$Npoužijte to pokud jste nahrávali obrovské množství souborů a museli jste restartovat z nějakého důvodu a chcete pokračovat v nahrávání ASAP$N$Ntoto nahradí hash-kontrolu jednoduchým <em>&quot;má to stejnou velikost souboru na serveru?&quot;</em> takže pokud se obsah souborů liší, NEBUDE nahrán$N$Nměli byste to vypnout když nahrávání skončí a pak znovu &quot;nahrát&quot; stejné soubory aby je klient ověřil\">turbo",
"cut_datechk": "nemá žádný efekt pokud není povoleno turbo tlačítko$N$Nsnižuje yolo faktor o trochu; kontroluje zda časové značky souborů na serveru odpovídají vašim$N$Nměl by <em>teoreticky</em> zachytit většinu nedokončených / poškozených nahrávání, ale není náhradou za ověřovací průchod s turbem vypnutým poté\">kontrola data",
"cut_u2sz": "velikost (v MiB) každého kusu nahrávání; velké hodnoty lépe létají přes atlantik. Zkuste nízké hodnoty na velmi nespolehlivých připojeních",
"cut_flag": "zajistit aby nahrávala jen jedna karta najednou $N -- ostatní karty to musí mít také povoleno $N -- ovlivňuje jen karty na stejné doméně",
"cut_az": "nahrávat soubory v abecedním pořadí, spíše než nejmenší-soubor-první$N$Nabecední pořadí může usnadnit kontrolu zda se něco pokazilo na serveru, ale činí nahrávání mírně pomalejší na optice / LAN",
"cut_nag": "notifikace OS když nahrávání skončí$N(jen pokud prohlížeč nebo karta není aktivní)",
"cut_sfx": "zvukové upozornění když nahrávání skončí$N(jen pokud prohlížeč nebo karta není aktivní)",
"cut_mt": "použít vícevláknové zpracování pro zrychlení hashování souborů$N$Ntoto používá web-workers a vyžaduje$Nvíce RAM (až 512 MiB navíc)$N$Ndělá https o 30% rychlejší a http 4,5x rychlejší\">mt",
"cut_wasm": "použijte wasm místo vestavěného hashování prohlížeče; zlepšuje rychlost na prohlížečích založených na chrome ale zvyšuje zátěž CPU, mnoho starších verzí chrome má chyby které způsobují že prohlížeč spotřebuje veškerou RAM a spadne pokud je toto povoleno\">wasm",
"cft_text": "text favicon (prázdné a obnovte pro zakázání)",
"cft_fg": "barva popředí",
"cft_bg": "barva pozadí",
"cdt_lim": "maximální počet souborů k zobrazení ve složce",
"cdt_ask": "při posunování na konec,$Nmísto načítání více souborů,$N se zeptat co dělat",
"cdt_hsort": "kolik pravidel řazení (&lt;code&gt;,sorthref&lt;/code&gt;) zahrnout do media-URL. Nastavení na 0 bude také ignorovat pravidla řazení zahrnutá v media odkazech při kliknutí na ně",
"cdt_ren": "povolit vlastní kontextovou nabídku, běžnou nabídku lze otevřít podržením klávesy shift a kliknutím pravým tlačítkem", //m
"tt_entree": "zobrazit navigační panel (postranní strom adresářů)$NKlávesová zkratka: B",
"tt_detree": "zobrazit drobečkovou navigaci$NKlávesová zkratka: B",
"tt_visdir": "posunout k vybrané složce",
"tt_ftree": "přepnout strom složek / textové soubory$NKlávesová zkratka: V",
"tt_pdock": "zobrazit nadřazené složky v ukotveném panelu nahoře",
"tt_dynt": "automaticky rozrůstat jak se strom rozšiřuje",
"tt_wrap": "zalomení řádků",
"tt_hover": "odhalit přetékající řádky při najetí$N( ruší posun pokud kurzor myši $N&nbsp; není v levém okraji )",
"ml_pmode": "na konci složky...",
"ml_btns": "příkazy",
"ml_tcode": "transkódovat",
"ml_tcode2": "transkódovat na",
"ml_tint": "odstín",
"ml_eq": "audio ekvalizér",
"ml_drc": "kompresor dynamického rozsahu",
"mt_loop": "smyčka/opakovat jednu skladbu\">🔁",
"mt_one": "zastavit po jedné skladbě\">1⃣",
"mt_shuf": "zamíchat skladby v každé složce\">🔀",
"mt_aplay": "automatické přehrávání pokud je ID skladby v odkazu kterým jste přišli na server$N$Nzakázání toho také zastaví aktualizaci URL stránky s ID skladby při přehrávání hudby, aby se zabránilo automatickému přehrávání pokud se tato nastavení ztratí ale URL zůstane\">a▶",
"mt_preload": "začít načítat následující skladbu před koncem pro plynulé přehrávání\">přednahrání",
"mt_prescan": "přejít do následující složky před tím než$Nskončí poslední skladba, aby byl webprohlížeč$Nspokojen aby nezastavil přehrávání\">nav",
"mt_fullpre": "zkusit přednahrát celou skladbu;$N✅ povolit na <b>nespolehlivých</b> připojeních,$N❌ <b>zakázat</b> na pomalých připojeních pravděpodobně\">úplné",
"mt_fau": "na telefonech zabránit zastavení hudby, pokud se další píseň nenahraje dostatečně rychle (může způsobit chybné zobrazení tagů)\">☕️",
"mt_waves": "vlnový posuvník:$Nzobrazit amplitudu zvuku v posuvníku\">~s",
"mt_npclip": "zobrazit tlačítka pro kopírování aktuálně přehrávané písně do schránky\">/np",
"mt_m3u_c": "zobrazit tlačítka pro kopírování$Nvybraných písní jako položky m3u8 playlistu\">📻",
"mt_octl": "integrace s OS (mediální klávesy / osd)\">os-ctl",
"mt_oseek": "povolit posunování přes integraci s OS$N$Npoznámka: na některých zařízeních (iPhone),$Nto nahradí tlačítko další písně\">seek",
"mt_oscv": "zobrazit obal alba v osd\">art",
"mt_follow": "udržet přehrávanou stopu v zobrazení\">🎯",
"mt_compact": "kompaktní ovládání\">⟎",
"mt_uncache": "vymazat cache &nbsp;(zkuste to, pokud váš prohlížeč uložil$Nporušenou kopii písně a odmítá ji přehrát)\">uncache",
"mt_mloop": "opakovat otevřenou složku\">🔁 loop",
"mt_mnext": "načíst další složku a pokračovat\">📂 next",
"mt_mstop": "zastavit přehrávání\">⏸ stop",
"mt_cflac": "převést flac / wav na {0}\">flac",
"mt_caac": "převést aac / m4a na {0}\">aac",
"mt_coth": "převést všechny ostatní (ne mp3) na {0}\">oth",
"mt_c2opus": "nejlepší volba pro desktopy, laptopy, android\">opus",
"mt_c2owa": "opus-weba, pro iOS 17.5 a novější\">owa",
"mt_c2caf": "opus-caf, pro iOS 11 až 17\">caf",
"mt_c2mp3": "použijte na velmi starých zařízeních\">mp3",
"mt_c2flac": "nejlepší kvalita zvuku, ale obrovské stahování\">flac",
"mt_c2wav": "nekomprimované přehrávání (ještě větší)\">wav",
"mt_c2ok": "výborně, dobrá volba",
"mt_c2nd": "to není doporučený výstupní formát pro vaše zařízení, ale v pořádku",
"mt_c2ng": "vaše zařízení, zdá se, nepodporuje tento výstupní formát, ale zkusíme to",
"mt_xowa": "v iOS jsou chyby bránící přehrávání na pozadí s tímto formátem; použijte prosím caf nebo mp3",
"mt_tint": "úroveň pozadí (0-100) na posuvníku$Nabyste učinili ukládání do vyrovnávací paměti méně rušivým",
"mt_eq": "povoluje ekvalizér a ovládání zisku;$N$Nboost &lt;code&gt;0&lt;/code&gt; = standardní 100% hlasitost (nezměněno)$N$Nwidth &lt;code&gt;1 &nbsp;&lt;/code&gt; = standardní stereo (nezměněno)$Nwidth &lt;code&gt;0.5&lt;/code&gt; = 50% levý-pravý crossfeed$Nwidth &lt;code&gt;0 &nbsp;&lt;/code&gt; = mono$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = odstranění vokálů :^)$N$Npovolení ekvalizéru činí alba bez mezer zcela bez mezer, takže to nechte zapnuté se všemi hodnotami na nule (kromě width = 1), pokud vám na tom záleží",
"mt_drc": "povoluje kompresor dynamického rozsahu (vyrovnávač hlasitosti / brickwaller); také povolí EQ pro vyvážení špaget, takže nastavte všechna EQ pole kromě 'width' na 0, pokud to nechcete$N$Nsnižuje hlasitost zvuku nad THRESHOLD dB; pro každý RATIO dB za THRESHOLD je 1 dB výstupu, takže výchozí hodnoty tresh -24 a ratio 12 znamenají, že by nikdy nemělo být hlasitější než -22 dB a je bezpečné zvýšit boost ekvalizéru na 0.8, nebo dokonce 1.8 s ATK 0 a obrovským RLS jako 90 (funguje pouze ve firefoxu; RLS je max 1 v jiných prohlížečích)$N$N(viz wikipedia, vysvětlují to mnohem lépe)",
"mb_play": "přehrát",
"mm_hashplay": "přehrát tento audio soubor?",
"mm_m3u": "stiskněte <code>Enter/OK</code> pro Přehrání\nstiskněte <code>ESC/Zrušit</code> pro Úpravu",
"mp_breq": "potřebujete firefox 82+ nebo chrome 73+ nebo iOS 15+",
"mm_bload": "nyní se načítá...",
"mm_bconv": "převádí se na {0}, čekejte prosím...",
"mm_opusen": "váš prohlížeč nemůže přehrát aac / m4a soubory;\ntranscoding na opus je nyní povolen",
"mm_playerr": "přehrávání selhalo: ",
"mm_eabrt": "Pokus o přehrávání byl zrušen",
"mm_enet": "Vaše internetové připojení je nestabilní",
"mm_edec": "Tento soubor je údajně poškozený??",
"mm_esupp": "Váš prohlížeč nerozumí tomuto audio formátu",
"mm_eunk": "Neznámá chyba",
"mm_e404": "Nelze přehrát audio; chyba 404: Soubor nenalezen.",
"mm_e403": "Nelze přehrát audio; chyba 403: Přístup odepřen.\n\nZkuste stisknout F5 pro obnovení, možná jste se odhlásili",
"mm_e500": "Nelze přehrát audio; chyba 500: Zkontrolujte logy serveru.",
"mm_e5xx": "Nelze přehrát audio; chyba serveru ",
"mm_nof": "žádné další audio soubory v okolí nenalezeny",
"mm_prescan": "Hledám hudbu k dalšímu přehrání...",
"mm_scank": "Další píseň nalezena:",
"mm_uncache": "cache vymazána; všechny písně se znovu stáhnou při dalším přehrávání",
"mm_hnf": "tato píseň již neexistuje",
"im_hnf": "tento obrázek již neexistuje",
"f_empty": 'tato složka je prázdná',
"f_chide": 'toto skryje sloupec «{0}»\n\nmůžete odkrýt sloupce v záložce nastavení',
"f_bigtxt": "tento soubor má {0} MiB -- opravdu zobrazit jako text?",
"f_bigtxt2": "zobrazit pouze konec souboru? to také povolí sledování/tailing, zobrazí nově přidané řádky textu v reálném čase",
"fbd_more": '<div id="blazy">zobrazuji <code>{0}</code> z <code>{1}</code> souborů; <a href="#" id="bd_more">zobraz {2}</a> nebo <a href="#" id="bd_all">zobraz všechny</a></div>',
"fbd_all": '<div id="blazy">zobrazuji <code>{0}</code> z <code>{1}</code> souborů; <a href="#" id="bd_all">zobraz všechny</a></div>',
"f_anota": "pouze {0} z {1} položek bylo vybráno;\npro výběr celé složky nejprve přejděte na konec",
"f_dls": 'odkazy na soubory v aktuální složce byly\nzměněny na odkazy ke stažení',
"f_partial": "Pro bezpečné stažení souboru, který se aktuálně nahrává, klikněte prosím na soubor se stejným názvem, ale bez přípony <code>.PARTIAL</code>. Stiskněte prosím Zrušit nebo Escape.\n\nStisknutím OK / Enter ignorujete toto varování a pokračujete ve stahování <code>.PARTIAL</code> dočasného souboru, což téměř jistě vyústí jako poškozená data.",
"ft_paste": "vložit {0} položek$NKlávesová zkratka: ctrl-V",
"fr_eperm": 'nelze přejmenovat:\nnemáte oprávnění “přesunout” v této složce',
"fd_eperm": 'nelze smazat:\nnemáte oprávnění “smazat” v této složce',
"fc_eperm": 'nelze vyjmout:\nnemáte oprávnění “přesunout” v této složce',
"fp_eperm": 'nelze vložit:\nnemáte oprávnění “zapisovat” v této složce',
"fr_emore": "vyberte alespoň jednu položku k přejmenování",
"fd_emore": "vyberte alespoň jednu položku ke smazání",
"fc_emore": "vyberte alespoň jednu položku k vyjmutí",
"fcp_emore": "vyberte alespoň jednu položku k zkopírování do schránky",
"fs_sc": "sdílet složku, ve které se nacházíte",
"fs_ss": "sdílet vybrané soubory",
"fs_just1d": "nelze vybrat více než jednu složku,\nnebo míchat soubory a složky v jednom výběru",
"fs_abrt": "❌ zrušit",
"fs_rand": "🎲 náhodný.název",
"fs_go": "✅ vytvořit sdílení",
"fs_name": "název",
"fs_src": "zdroj",
"fs_pwd": "heslo",
"fs_exp": "vypršení",
"fs_tmin": "min",
"fs_thrs": "hodin",
"fs_tdays": "dní",
"fs_never": "navždy",
"fs_pname": "volitelný název odkazu; bude náhodný, pokud je prázdný",
"fs_tsrc": "soubor nebo složka ke sdílení",
"fs_ppwd": "volitelné heslo",
"fs_w8": "vytváření sdílení...",
"fs_ok": "stiskněte <code>Enter/OK</code> pro zkopírování do schránky\nstiskněte <code>ESC/Zrušit</code> pro zavření",
"frt_dec": "může opravit některé případy porušených názvů souborů\">url-decode",
"frt_rst": "resetovat změněné názvy souborů zpět na původní\">↺ reset",
"frt_abrt": "zrušit a zavřít toto okno\">❌ cancel",
"frb_apply": "PŘEJMENOVAT",
"fr_adv": "dávkové / metadata / přejmenování podle vzoru\">pokročilé",
"fr_case": "regex citlivý na velikost písmen\">velikost",
"fr_win": "názvy bezpečné pro windows; nahradit <code>&lt;&gt;:&quot;\\|?*</code> japonskými plnošířkovými znaky\">win",
"fr_slash": "nahradit <code>/</code> znakem který nezpůsobí vytvoření nových složek\">žádné /",
"fr_re": "vzor regex hledání k aplikaci na původní názvy souborů; zachycené skupiny mohou být odkazovány v poli formátu níže jako &lt;code&gt;(1)&lt;/code&gt; a &lt;code&gt;(2)&lt;/code&gt; atd.",
"fr_fmt": "inspirováno foobar2000:$N&lt;code&gt;(title)&lt;/code&gt; je nahrazeno názvem skladby,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; přeskočí [tuto] část pokud je umělec prázdný$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; doplní číslo stopy na 2 číslice",
"fr_pdel": "smazat",
"fr_pnew": "uložit jako",
"fr_pname": "zadejte název pro vaše nové přednastavení",
"fr_aborted": "zrušeno",
"fr_lold": "starý název",
"fr_lnew": "nový název",
"fr_tags": "tagy pro vybrané soubory (pouze pro čtení, jen pro referenci):",
"fr_busy": "přejmenovávám {0} položek...\n\n{1}",
"fr_efail": "přejmenování selhalo:\n",
"fr_nchg": "{0} z nových názvů bylo změněno kvůli <code>win</code> a/nebo <code>žádné /</code>\n\nPokračovat s těmito změněnými novými názvy?",
"fd_ok": "mazání OK",
"fd_err": "mazání selhalo:\n",
"fd_none": "nic nebylo smazáno; možná blokováno konfigurací serveru (xbd)?",
"fd_busy": "mažu {0} položek...\n\n{1}",
"fd_warn1": "SMAZAT těchto {0} položek?",
"fd_warn2": "<b>Poslední šance!</b> Nelze vrátit zpět. Smazat?",
"fc_ok": "vyjmout {0} položek",
"fc_warn": 'vyjmout {0} položek\n\nale: pouze <b>tato</b> karta prohlížeče je může vložit\n(protože výběr je tak absolutně masivní)',
"fcc_ok": "zkopírováno {0} položek do schránky",
"fcc_warn": 'zkopírováno {0} položek do schránky\n\nale: pouze <b>tato</b> karta prohlížeče je může vložit\n(protože výběr je tak absolutně masivní)',
"fp_apply": "použít tyto názvy",
"fp_skip": "přeskočit konflikty", //m
"fp_ecut": "nejprve vyjměte nebo zkopírujte nějaké soubory / složky k vložení / přesunutí\n\npoznámka: můžete vyjmout / vložit přes různé karty prohlížeče",
"fp_ename": "{0} položek sem nelze přesunout protože názvy jsou již obsazené. Dejte jim nové názvy níže pro pokračování, nebo název nechte prázdný (\"přeskočit konflikty\") pro přeskočení:", //m
"fcp_ename": "{0} položek sem nelze zkopírovat protože názvy jsou již obsazené. Dejte jim nové názvy níže pro pokračování, nebo název nechte prázdný (\"přeskočit konflikty\") pro přeskočení:", //m
"fp_emore": "stále jsou některé kolize názvů souborů k opravě",
"fp_ok": "přesun OK",
"fcp_ok": "kopírování OK",
"fp_busy": "přesouvám {0} položek...\n\n{1}",
"fcp_busy": "kopíruji {0} položek...\n\n{1}",
"fp_abrt": "přerušuji...", //m
"fp_err": "přesun selhal:\n",
"fcp_err": "kopírování selhalo:\n",
"fp_confirm": "přesunout těchto {0} položek sem?",
"fcp_confirm": "zkopírovat těchto {0} položek sem?",
"fp_etab": 'selhalo čtení schránky z jiné karty prohlížeče',
"fp_name": "nahrávání souboru z vašeho zařízení. Dejte mu název:",
"fp_both_m": '<h6>vyberte co vložit</h6><code>Enter</code> = Přesunout {0} souborů z «{1}»\n<code>ESC</code> = Nahrát {2} souborů z vašeho zařízení',
"fcp_both_m": '<h6>vyberte co vložit</h6><code>Enter</code> = Kopírovat {0} souborů z «{1}»\n<code>ESC</code> = Nahrát {2} souborů z vašeho zařízení',
"fp_both_b": '<a href="#" id="modal-ok">Přesunout</a><a href="#" id="modal-ng">Nahrát</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Kopírovat</a><a href="#" id="modal-ng">Nahrát</a>',
"mk_noname": "napište název do textového pole vlevo předtím než to uděláte :p",
"nmd_i1": "můžeš také přidat příponu souboru, například <code>.md</code>", //m
"nmd_i2": "můžeš vytvářet pouze <code>.md</code> soubory, protože nemáš oprávnění mazat", //m
"tv_load": "Načítání textového dokumentu:\n\n{0}\n\n{1}% ({2} z {3} MiB načteno)",
"tv_xe1": "nelze načíst textový soubor:\n\nchyba ",
"tv_xe2": "404, soubor nenalezen",
"tv_lst": "seznam textových souborů v",
"tvt_close": "návrat do zobrazení složky$NKlávesová zkratka: M (nebo Esc)\">❌ zavřít",
"tvt_dl": "stáhnout tento soubor$NKlávesová zkratka: Y\">💾 stáhnout",
"tvt_prev": "zobrazit předchozí dokument$NKlávesová zkratka: i\">⬆ předchozí",
"tvt_next": "zobrazit následující dokument$NKlávesová zkratka: K\">⬇ další",
"tvt_sel": "vybrat soubor &nbsp; ( pro vyjmutí / kopírování / mazání / ... )$NKlávesová zkratka: S\">výběr",
"tvt_j": "zkrášlit json$NKlávesová zkratka: shift-J\">j", //m
"tvt_edit": "otevřít soubor v textovém editoru$NKlávesová zkratka: E\">✏️ upravit",
"tvt_tail": "sledovat soubor pro změny; zobrazit nové řádky v reálném čase\">📡 sledovat",
"tvt_wrap": "zalamování slov\">↵",
"tvt_atail": "zamknout posun na konec stránky\">⚓",
"tvt_ctail": "dekódovat barvy terminálu (ansi escape kódy)\">🌈",
"tvt_ntail": "limit zpětného posouvání (kolik bajtů textu ponechat načtených)",
"m3u_add1": "skladba přidána do m3u playlistu",
"m3u_addn": "{0} skladeb přidáno do m3u playlistu",
"m3u_clip": "m3u playlist nyní zkopírován do schránky\n\nměli byste vytvořit nový textový soubor pojmenovaný něco.m3u a vložit playlist do tohoto dokumentu; toto ho učiní přehratelným",
"gt_vau": "nezobrazovat videa, jen přehrát zvuk\">🎧",
"gt_msel": "povolit výběr souborů; ctrl-klik na soubor pro přepsání$N$N&lt;em&gt;když aktivní: dvojklik na soubor / složku pro otevření&lt;/em&gt;$N$NKlávesová zkratka: S\">výběr více",
"gt_crop": "ořez náhledů na střed\">ořez",
"gt_3x": "náhledy s vysokým rozlišením\">3x",
"gt_zoom": "zoom",
"gt_chop": "rozdělit",
"gt_sort": "řadit podle",
"gt_name": "název",
"gt_sz": "velikost",
"gt_ts": "datum",
"gt_ext": "typ",
"gt_c1": "více zkrátit názvy souborů (zobrazit méně)",
"gt_c2": "méně zkrátit názvy souborů (zobrazit více)",
"sm_w8": "hledám...",
"sm_prev": "výsledky hledání níže jsou z předchozího dotazu:\n ",
"sl_close": "zavřít výsledky hledání",
"sl_hits": "zobrazuji {0} zásahů",
"sl_moar": "načíst více",
"s_sz": "velikost",
"s_dt": "datum",
"s_rd": "cesta",
"s_fn": "název",
"s_ta": "tagy",
"s_ua": "nahráno@",
"s_ad": "pokročilé",
"s_s1": "minimum MiB",
"s_s2": "maximum MiB",
"s_d1": "min. iso8601",
"s_d2": "max. iso8601",
"s_u1": "nahráno po",
"s_u2": "a/nebo před",
"s_r1": "cesta obsahuje &nbsp; (oddělené mezerami)",
"s_f1": "název obsahuje &nbsp; (negace s -ne)",
"s_t1": "tagy obsahují &nbsp; (^=začátek, konec=$)",
"s_a1": "specifické vlastnosti metadat",
"md_eshow": "nelze vykreslit ",
"md_off": "[📜<em>readme</em>] zakázáno v [⚙️] -- dokument skryt",
"badreply": "Selhalo parsování odpovědi ze serveru",
"xhr403": "403: Přístup odepřen\n\nzkuste stisknout F5, možná jste se odhlásili",
"xhr0": "neznámý (pravděpodobně ztraceno spojení se serverem, nebo server je offline)",
"cf_ok": "omlouváme se za to -- DD" + wah + "oS ochrana se aktivovala\n\nvěci by se měly obnovit asi za 30 sekund\n\npokud se nic nestane, stiskněte F5 pro obnovení stránky",
"tl_xe1": "nelze vypsat podsložky:\n\nchyba ",
"tl_xe2": "404: Složka nenalezena",
"fl_xe1": "nelze vypsat soubory ve složce:\n\nchyba ",
"fl_xe2": "404: Složka nenalezena",
"fd_xe1": "nelze vytvořit podsložku:\n\nchyba ",
"fd_xe2": "404: Nadřazená složka nenalezena",
"fsm_xe1": "nelze odeslat zprávu:\n\nchyba ",
"fsm_xe2": "404: Nadřazená složka nenalezena",
"fu_xe1": "selhalo načtení unpost seznamu ze serveru:\n\nchyba ",
"fu_xe2": "404: Soubor nenalezen??",
"fz_tar": "nekomprimovaný gnu-tar soubor (linux / mac)",
"fz_pax": "nekomprimovaný tar formátu pax (pomalejší)",
"fz_targz": "gnu-tar s gzip kompresí úrovně 3$N$Nto je obvykle velmi pomalé, takže$Npoužijte místo toho nekomprimovaný tar",
"fz_tarxz": "gnu-tar s xz kompresí úrovně 1$N$Nto je obvykle velmi pomalé, takže$Npoužijte místo toho nekomprimovaný tar",
"fz_zip8": "zip s utf8 názvy souborů (možná problematické na windows 7 a starších)",
"fz_zipd": "zip s tradičními cp437 názvy souborů, pro opravdu starý software",
"fz_zipc": "cp437 s crc32 vypočítaným brzy,$Npro MS-DOS PKZIP v2.04g (říjen 1993)$N(trvá déle zpracovat před začátkem stahování)",
"un_m1": "můžete smazat vaše nedávné nahrání (nebo zrušit nedokončené) níže",
"un_upd": "obnovit",
"un_m4": "nebo sdílet soubory viditelné níže:",
"un_ulist": "zobrazit",
"un_ucopy": "kopírovat",
"un_flt": "volitelný filtr:&nbsp; URL musí obsahovat",
"un_fclr": "vymazat filtr",
"un_derr": 'unpost-delete selhalo:\n',
"un_f5": 'něco se pokazilo, zkuste prosím obnovit, nebo stiskněte F5',
"un_uf5": "omlouváme se ale musíte obnovit stránku (například stisknutím F5 nebo CTRL-R) předtím než toto nahrávání může být zrušeno",
"un_nou": '<b>varování:</b> server je příliš zaneprázdněn pro zobrazení nedokončených nahrávání; za chvíli klikněte na odkaz "obnovit"',
"un_noc": '<b>varování:</b> unpost plně nahraných souborů není povoleno/dovoleno v konfiguraci serveru',
"un_max": "zobrazuji prvních 2000 souborů (použijte filtr)",
"un_avail": "{0} nedávných nahrávání může být smazáno<br />{1} nedokončených může být zrušeno",
"un_m2": "řazeno podle času nahrávání; nejnovější první:",
"un_no1": "počkej! žádná nahrávání nejsou dostatečně nedávná",
"un_no2": "počkej! žádná nahrávání odpovídající tomuto filtru nejsou dostatečně nedávná",
"un_next": "smazat dalších {0} souborů níže",
"un_abrt": "zrušit",
"un_del": "smazat",
"un_m3": "načítám vaše nedávné nahrání...",
"un_busy": "mažu {0} souborů...",
"un_clip": "{0} odkazů zkopírováno do schránky",
"u_https1": "měli byste",
"u_https2": "přejít na https",
"u_https3": "pro lepší výkon",
"u_ancient": "váš prohlížeč je úctyhodně starý -- možná byste měli <a href=\"#\" onclick=\"goto('bup')\">použít bup</a>",
"u_nowork": "vyžadován firefox 53+ nebo chrome 57+ nebo iOS 11+",
"tail_2old": "vyžadován firefox 105+ nebo chrome 71+ nebo iOS 14.5+",
"u_nodrop": "váš prohlížeč je příliš starý pro nahrávání přetažením (drag-and-drop)",
"u_notdir": "toto není složka!\n\nváš prohlížeč je příliš starý,\nzkuste prosím soubory přetáhnout",
"u_uri": "pro přetažení obrázků z jiných oken prohlížeče,\nje prosím přetáhněte na velké tlačítko pro nahrávání",
"u_enpot": "přepnout na <a href=\"#\">potato UI</a> (může zrychlit nahrávání)",
"u_depot": "přepnout na <a href=\"#\">fancy UI</a> (může zpomalit nahrávání)",
"u_gotpot": "přepínám na potato UI pro zrychlení nahrávání,\n\npokud nesouhlasíte, klidně jej přepněte zpět!",
"u_pott": "<p>soubory: &nbsp; <b>{0}</b> dokončeno, &nbsp; <b>{1}</b> selhalo, &nbsp; <b>{2}</b> nahrává se, &nbsp; <b>{3}</b> ve frontě</p>",
"u_ever": "toto je základní nahrávání; up2k vyžaduje alespoň<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
"u_su2k": "toto je základní nahrávání; <a href=\"#\" id=\"u2yea\">up2k</a> je lepší",
"u_uput": "optimalizovat pro rychlost (přeskočit kontrolní součet)",
"u_ewrite": "nemáte oprávnění k zápisu do této složky",
"u_eread": "nemáte oprávnění ke čtení této složky",
"u_enoi": "vyhledávání souborů není povoleno v konfiguraci serveru",
"u_enoow": "přepsání zde nebude fungovat; je vyžadováno oprávnění k mazání",
"u_badf": "Těchto {0} souborů (z celkem {1}) bylo přeskočeno, pravděpodobně kvůli oprávněním v souborovém systému:\n\n",
"u_blankf": "Těchto {0} souborů (z celkem {1}) je prázdných; přesto je nahrát?\n\n",
"u_applef": "Těchto {0} souborů (z celkem {1}) je pravděpodobně nežádoucích;\nStiskněte <code>OK/Enter</code> pro PŘESKOČENÍ následujících souborů,\nStiskněte <code>Zrušit/ESC</code> pro Zahrnutí a NAHRÁNÍ i těchto souborů:\n\n",
"u_just1": "\nMožná to bude fungovat lépe, když vyberete pouze jeden soubor",
"u_ff_many": "pokud používáte <b>Linux / MacOS / Android,</b> takové množství souborů <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>může</em> shodit Firefox!</a>\npokud se to stane, zkuste to prosím znovu (nebo použijte Chrome).",
"u_up_life": "Tento upload bude smazán ze serveru\n{0} po jeho dokončení",
"u_asku": "Nahrát {0} souborů do <code>{1}</code>",
"u_unpt": "toto nahrávání můžete vrátit zpět / smazat pomocí 🧯 vlevo nahoře",
"u_bigtab": "chystám se zobrazit {0} souborů\n\nto může shodit váš prohlížeč, jste si jisti?",
"u_scan": "Skenuji soubory...",
"u_dirstuck": "procházení adresáře se zaseklo při pokusu o přístup k následujícím {0} položkám; budou přeskočeny:",
"u_etadone": "Hotovo ({0}, {1} souborů)",
"u_etaprep": "(příprava na nahrávání)",
"u_hashdone": "hashování dokončeno",
"u_hashing": "hashování",
"u_hs": "navazuji spojení...",
"u_started": "soubory se nyní nahrávají; viz [🚀]",
"u_dupdefer": "duplikát; bude zpracován po všech ostatních souborech",
"u_actx": "klikněte na tento text, abyste zabránili ztrátě<br />výkonu při přepínání do jiných oken/záložek",
"u_fixed": "OK!&nbsp; Opraveno 👍",
"u_cuerr": "nepodařilo se nahrát část {0} z {1};\npatrně neškodné, pokračuji\n\nsoubor: {2}",
"u_cuerr2": "server odmítl nahrání (část {0} z {1});\nzopakuji později\n\nsoubor: {2}\n\nchyba ",
"u_ehstmp": "zopakuji pokus; viz vpravo dole",
"u_ehsfin": "server odmítl požadavek na dokončení nahrávání; opakuji pokus...",
"u_ehssrch": "server odmítl požadavek na vyhledávání; opakuji pokus...",
"u_ehsinit": "server odmítl požadavek na zahájení nahrávání; opakuji pokus...",
"u_eneths": "síťová chyba při navazování spojení pro nahrávání; opakuji pokus...",
"u_enethd": "síťová chyba při ověřování existence cíle; opakuji pokus...",
"u_cbusy": "čekám, až nám server po síťovém problému začne znovu důvěřovat...",
"u_ehsdf": "na serveru došlo místo na disku!\n\nbudu to zkoušet dál, pro případ, že někdo\nuvolní dostatek místa pro pokračování",
"u_emtleak1": "vypadá to, že váš webový prohlížeč může mít únik paměti (memory leak);\nprosím",
"u_emtleak2": " <a href=\"{0}\">přejděte na https (doporučeno)</a> nebo ",
"u_emtleak3": " ",
"u_emtleakc": "zkuste následující:\n<ul><li>stiskněte <code>F5</code> pro obnovení stránky</li><li>poté vypněte tlačítko &nbsp;<code>mt</code>&nbsp; v &nbsp;<code>⚙️ nastavení</code></li><li>a zkuste nahrávání znovu</li></ul>Nahrávání bude o něco pomalejší, ale co se dá dělat.\nOmlouváme se za potíže!\n\nPS: chrome v107 <a href=\"https://bugs.chromium.org/p/chromium/issues/detail?id=1354816\" target=\"_blank\">obsahuje opravu</a> pro tento problém",
"u_emtleakf": "zkuste následující:\n<ul><li>stiskněte <code>F5</code> pro obnovení stránky</li><li>poté zapněte <code>🥔</code> (potato) v rozhraní nahrávání<li>a zkuste nahrávání znovu</li></ul>\nPS: firefox snad <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\">bude mít opravu</a> v některé z příštích verzí",
"u_s404": "nenalezeno na serveru",
"u_expl": "vysvětlit",
"u_maxconn": "většina prohlížečů omezuje počet na 6, ale firefox umožňuje toto navýšit pomocí <code>connections-per-server</code> v <code>about:config</code>",
"u_tu": "<p class=\"warn\">VAROVÁNÍ: turbo zapnuto, <span>&nbsp;klient nemusí detekovat a obnovit nedokončené nahrávání; viz nápovědu u tlačítka turbo</span></p>",
"u_ts": "<p class=\"warn\">VAROVÁNÍ: turbo zapnuto, <span>&nbsp;výsledky vyhledávání mohou být nesprávné; viz nápovědu u tlačítka turbo</span></p>",
"u_turbo_c": "turbo je vypnuto v konfiguraci serveru",
"u_turbo_g": "vypínám turbo, protože nemáte oprávnění\nk výpisu adresářů na tomto svazku",
"u_life_cfg": 'automatické smazání po <input id="lifem" p="60" /> min (nebo <input id="lifeh" p="3600" /> hodinách)',
"u_life_est": 'nahrání bude smazáno <span id="lifew" tt="local time">---</span>',
"u_life_max": 'tato složka vynucuje\nmax. životnost {0}',
"u_unp_ok": 'unpost je povoleno pro {0}',
"u_unp_ng": 'unpost NEBUDE povoleno',
"ue_ro": 'váš přístup k této složce je pouze pro čtení\n\n',
"ue_nl": 'momentálně nejste přihlášeni',
"ue_la": 'momentálně jste přihlášeni jako "{0}"',
"ue_sr": 'momentálně jste v režimu vyhledávání souborů\n\npřepněte do režimu nahrávání kliknutím na lupu 🔎 (vedle velkého tlačítka HLEDAT) a zkuste nahrávání znovu\n\nomlouváme se',
"ue_ta": 'zkuste nahrávání znovu, nyní by to mělo fungovat',
"ue_ab": "tento soubor se již nahrává do jiné složky a toto nahrávání musí být dokončeno předtím, než může být soubor nahrán jinam.\n\nMůžete zrušit a zapomenout na původní nahrávání pomocí levého horního 🧯",
"ur_1uo": "OK: Soubor úspěšně nahrán",
"ur_auo": "OK: Všech {0} souborů úspěšně nahráno",
"ur_1so": "OK: Soubor nalezen na serveru",
"ur_aso": "OK: Všech {0} souborů nalezeno na serveru",
"ur_1un": "Nahrání selhalo, omlouváme se",
"ur_aun": "Všech {0} nahrání selhalo, omlouváme se",
"ur_1sn": "Soubor NEBYL nalezen na serveru",
"ur_asn": "{0} souborů NEBYLO nalezeno na serveru",
"ur_um": "Dokončeno;\n{0} nahrání OK,\n{1} nahrání selhalo, omlouváme se",
"ur_sm": "Dokončeno;\n{0} souborů nalezeno na serveru,\n{1} souborů NENALEZENO na serveru",
"rc_opn": "otevřít", //m
"rc_ply": "přehrát", //m
"rc_pla": "přehrát jako zvuk", //m
"rc_txt": "otevřít v prohlížeči souborů", //m
"rc_md": "otevřít v textovém editoru", //m
"rc_dl": "stáhnout", //m
"rc_zip": "stáhnout jako archiv", //m
"rc_del": "smazat", //m
"rc_cut": "vyjmout", //m
"rc_cpy": "kopírovat", //m
"rc_pst": "vložit", //m
"rc_nfo": "nová složka", //m
"rc_nfi": "nový soubor", //m
"rc_sal": "vybrat vše", //m
"rc_sin": "invertovat výběr", //m
"lang_set": "obnovit stránku, aby se změna projevila?",
"splash": {
"a1": "obnovit",
"b1": "ahoj cizinče &nbsp; <small>(nejsi přihlášen)</small>",
"c1": "odhlásit se",
"d1": "vypsat zásobníku",
"d2": "zobrazit stav všech aktivních vláken",
"e1": "znovu načíst konfiguraci",
"e2": "znovu načíst konfigurační soubory (accounts/volumes/volflags),$Na prohledat všechny e2ds úložiště$N$Npoznámka: všechny změny globálních nastavení$Nvyžadují úplné restartování, aby se projevily",
"f1": "můžeš procházet:",
"g1": "můžeš nahrávat do:",
"cc1": "další věci:",
"h1": "zakázat k304",
"i1": "povolit k304",
"j1": "povolení k304 odpojí vašeho klienta při každém HTTP 304, což může zabránit některým chybovým proxy serverům, aby se zasekly (náhle nenačítaly stránky), <em>ale</em> také to obecně zpomalí věci",
"k1": "resetovat nastavení klienta",
"l1": "přihlaste se pro více:",
"ls3": "přihlásit se", //m
"lu4": "uživatelské jméno", //m
"lp4": "heslo", //m
"lo3": "odhlásit “{0}” všude", //m
"lo2": "tímto ukončíte relaci ve všech prohlížečích", //m
"m1": "vítej zpět,",
"n1": "404 nenalezeno &nbsp;┐( ´ -`)┌",
"o1": 'nebo možná nemáš přístup -- zkus heslo nebo <a href="' + SR + '/?h">jdi domů</a>',
"p1": "403 zakázáno &nbsp;~┻━┻",
"q1": 'použij heslo nebo <a href="' + SR + '/?h">jdi domů</a>',
"r1": "jdi domů",
".s1": "znovu prohledat",
"t1": "akce",
"u2": "čas od posledního zápisu na server$N( upload / rename / ... )$N$N17d = 17 dní$N1h23 = 1 hodina 23 minut$N4m56 = 4 minuty 56 sekund",
"v1": "připojit",
"v2": "použít tento server jako místní HDD",
"w1": "přepnout na https",
"x1": "změnit heslo",
"y1": "upravit sdílení",
"z1": "odblokovat toto sdílení:",
"ta1": "nejprve vyplňte své nové heslo",
"ta2": "zopakujte pro potvrzení nového hesla:",
"ta3": "nalezen překlep; zkuste to prosím znovu",
"nop": "CHYBA: Heslo nesmí být prázdné", //m
"nou": "CHYBA: Uživatelské jméno a/nebo heslo nesmí být prázdné", //m
"aa1": "příchozí soubory:",
"ab1": "deaktivovat no304",
"ac1": "povolit no304",
"ad1": "povolení no304 deaktivuje veškeré mezipaměti; zkuste to, pokud k304 nestačilo. To ovšem zapříčíní obrovské množství síťového provozu!",
"ae1": "aktivní stahování:",
"af1": "zobrazit nedávné nahrávání",
"ag1": "zobrazit známé uživatele IdP", //m
}
};

710
copyparty/web/tl/deu.js Normal file
View file

@ -0,0 +1,710 @@
// Zeilen, die mit //m enden, sind nicht verifizierte maschinelle Übersetzungen
Ls.deu = {
"tt": "Deutsch",
"cols": {
"c": "Aktionen",
"dur": "Dauer",
"q": "Qualität / Bitrate",
"Ac": "Audiocodec",
"Vc": "Videocodec",
"Fmt": "Format / Container",
"Ahash": "Audio Checksumme",
"Vhash": "Video Checksumme",
"Res": "Auflösung",
"T": "Dateityp",
"aq": "Audioqualität / Bitrate",
"vq": "Videoqualität / Bitrate",
"pixfmt": "Subsampling / Pixelstruktur",
"resw": "horizontale Auflösung",
"resh": "vertikale Auflösung",
"chs": "Audiokanäle",
"hz": "Abtastrate",
},
"hks": [
[
"misc",
["ESC", "Dinge schliessen"],
"file-manager",
["G", "zwischen Liste und Gitter wechseln"],
["T", "zwischen Vorschaubildern und Symbolen wechseln"],
["⇧ A/D", "Vorschaubildergrösse ändern"],
["STRG-K", "Auswahl löschen"],
["STRG-X", "Auswahl ausschneiden"],
["STRG-C", "Auswahl in Zwischenablage kopieren"],
["STRG-V", "Zwischenablage hier einfügen"],
["Y", "Auswahl herunterladen"],
["F2", "Auswahl umbenennen"],
"file-list-sel",
["LEER", "Dateiauswahl aktivieren"],
["↑/↓", "Cursor verschieben"],
["STRG ↑/↓", "Cursor und Bildschirm verschieben"],
["⇧ ↑/↓", "Vorherige / nächste Datei auswählen"],
["STRG-A", "Alle Dateien / Ordner auswählen"],
], [
"navigation",
["B", "Zwischen Brotkrumen und Navpane wechseln"],
["I/K", "vorheriger / nächster Ordner"],
["M", "übergeordneter Ordner (oder Vorherigen einklappen)"],
["V", "Zwischen Textdateien und Navpane wechseln"],
["A/D", "Grösse der Navpane ändern"],
], [
"audio-player",
["J/L", "Vorheriger / nächster Song"],
["U/O", "10 Sek. vor- / zurückspringen"],
["0..9", "zu 0%..90% springen"],
["P", "Wiedergabe / Pause"],
["S", "aktuell abgespielten Song auswählen"],
["Y", "Song herunterladen"],
], [
"image-viewer",
["J/L, ←/→", "vorheriges / nächstes Bild"],
["Pos1/Ende", "erstes / letztes Bild"],
["F", "Vollbild"],
["R", "im Uhrzeigersinn drehen"],
["⇧ R", "gegen den Uhrzeigensinn drehen"],
["S", "Bild auswählen"],
["Y", "Bild herunterladen"],
], [
"video-player",
["U/O", "10 Sek. vor- / zurückspringen"],
["P/K/LEER", "Wiedergabe / Pause"],
["C", "continue playing next"],
["V", "Wiederholungs-Wiedergabe (Loop)"],
["M", "Stummschalten"],
["[ und ]", "Loop-Interval einstellen"],
], [
"textfile-viewer",
["I/K", "vorherige / nächste Datei"],
["M", "Textdatei schliessen"],
["E", "Textdatei bearbeiten"],
["S", "Textdatei auswählen (für Ausschneiden / Kopieren / Umbenennen)"],
["Y", "Textdatei herunterladen"],
["⇧ J", "json verschönern"],
]
],
"m_ok": "OK",
"m_ng": "Abbrechen",
"enable": "Aktivieren",
"danger": "ACHTUNG",
"clipped": "in Zwischenablage kopiert",
"ht_s1": "Sekunde",
"ht_s2": "Sekunden",
"ht_m1": "Minute",
"ht_m2": "Minuten",
"ht_h1": "Stunde",
"ht_h2": "Stunden",
"ht_d1": "Tag",
"ht_d2": "Tage",
"ht_and": " und ",
"goh": "Einstellungen",
"gop": 'zum vorherigen Ordner springen">vorh.',
"gou": 'zum übergeordneter Ordner springen">hoch',
"gon": 'zum nächsten Ordner springen">nächst.',
"logout": "Abmelden ",
"login": "Anmelden",
"access": " Zugriff",
"ot_close": "Submenu schliessen",
"ot_search": "Dateien nach Attributen, Pfad/Name, Musiktags oder beliebiger Kombination suchen$N$N&lt;code&gt;foo bar&lt;/code&gt; = muss «foo» und «bar» enthalten,$N&lt;code&gt;foo -bar&lt;/code&gt; = muss «foo» aber nicht «bar» enthalten,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = beginnt mit «yana» und ist «opus»-Datei$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = genau «try unite» enthalten$N$NDatumsformat ist iso-8601, z.B.$N&lt;code&gt;2009-12-31&lt;/code&gt; oder &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: lösche deine letzten Uploads oder breche unvollständige ab",
"ot_bup": "bup: Basic Uploader, unterstützt sogar Neuheiten wie Netscape 4.0",
"ot_mkdir": "mkdir: neuen Ordner erstellen",
"ot_md": "new-file: neue Textdatei erstellen",
"ot_msg": "msg: eine Nachricht an das Server-Log schicken",
"ot_mp": "Media Player-Optionen",
"ot_cfg": "Konfigurationsoptionen",
"ot_u2i": 'up2k: Dateien hochladen (wenn du Schreibrechte hast) oder in den Suchmodus wechseln, um zu prüfen, ob sie bereits auf dem Server existieren$N$NUploads sind fortsetzbar, multithreaded und behalten Dateizeitstempel, verbrauchen aber mehr CPU als [🎈]&nbsp; (der einfache Uploader)<br /><br />während Uploads wird dieses Symbol zu einem Fortschrittsanzeiger!',
"ot_u2w": 'up2k: Dateien mit Wiederaufnahme-Unterstützung hochladen (Browser schließen und später dieselben Dateien erneut hochladen)$N$Nmultithreaded, behält Dateizeitstempel, verbraucht aber mehr CPU als [🎈]&nbsp; (der einfache Uploader)<br /><br />während Uploads wird dieses Symbol zu einem Fortschrittsanzeiger!',
"ot_noie": 'Bitte benutze Chrome / Firefox / Edge',
"ab_mkdir": "Ordner erstellen",
"ab_mkdoc": "Textdatei erstellen",
"ab_msg": "Nachricht an Server Log senden",
"ay_path": "zu Ordnern springen",
"ay_files": "zu Dateien springen",
"wt_ren": "ausgewählte Elemente umbenennen$NHotkey: F2",
"wt_del": "ausgewählte Elemente löschen$NHotkey: STRG-K",
"wt_cut": "ausgewählte Elemente ausschneiden &lt;small&gt;(um sie dann irgendwo anders einzufügen)&lt;/small&gt;$NHotkey: STRG-X",
"wt_cpy": "ausgewählte Elemente in Zwischenablage kopieren$N(um sie dann irgendwo anders einzufügen)$NHotkey: ctrl-C",
"wt_pst": "zuvor ausgeschnittenen / kopierte Elemente einfügen$NHotkey: STRG-V",
"wt_selall": "alle Dateien auswählen$NHotkey: STRG-A (wenn Datei fokusiert)",
"wt_selinv": "Auswahl invertieren",
"wt_zip1": "Diesen Ordner als Archiv herunterladen",
"wt_selzip": "Auswahl als Archiv herunterladen",
"wt_seldl": "Auswahl als separate Dateien herunterladen$NHotkey: Y",
"wt_npirc": "kopiere Titelinfo als IRC-formattierten Text",
"wt_nptxt": "kopiere Titelinfo als Text",
"wt_m3ua": "Zu M3U-Wiedergabeliste hinzufügen (wähle später <code>📻copy</code>)",
"wt_m3uc": "M3U-Wiedergabeliste in Zwischenablage kopieren",
"wt_grid": "Zwischen Gitter und Liste wechseln$NHotkey: G",
"wt_prev": "Vorheriger Titel$NHotkey: J",
"wt_play": "Wiedergabe / Pause$NHotkey: P",
"wt_next": "Nächster Titel$NHotkey: L",
"ul_par": "Parallele Uploads:",
"ut_rand": "Zufällige Dateinamen",
"ut_u2ts": "Zuletzt geändert-Zeitstempel von$Ndeinem Dateisystem auf den Server übertragen\">📅",
"ut_ow": "Existierende Dateien auf dem Server überschreiben?$N🛡: Nie (generiert einen neuen Dateinamen)$N🕒: Überschreiben, wenn Server-Datei älter ist als meine$N♻: Überschreiben, wenn der Dateiinhalt anders ist$N⏭: Vorhandene Dateien immer überspringen",
"ut_mt": "Andere Dateien während des Uploads hashen$N$Nsolltest du deaktivieren, falls deine CPU oder Festplatte zum Flaschenhals werden könnte",
"ut_ask": 'Vor dem Upload nach Bestätigung fragen">💭',
"ut_pot": "Verbessert Upload-Geschwindigkeit$Nindem das UI weniger komplex gemacht wird",
"ut_srch": "nicht wirklich hochladen, stattdessen prüfen ob Datei bereits auf dem Server existiert (scannt alle Ordner, die du lesen kannst)",
"ut_par": "setze auf 0 zum Pausieren$N$Nerhöhe, wenn deine Verbindung langsam / instabil ist$N$lass auf 1 im LAN oder wenn die Festplatte auf dem Server ein Flaschenhals ist",
"ul_btn": "Dateien / Ordner hier<br>ablegen (oder klick mich)",
"ul_btnu": "U P L O A D",
"ul_btns": "S U C H E N",
"ul_hash": "hash",
"ul_send": "senden",
"ul_done": "fertig",
"ul_idle1": "keine Uploads in der Warteschlange",
"ut_etah": "durchschnittl. &lt;em&gt;hashing&lt;/em&gt; Geschw. &amp; gesch. Restzeit",
"ut_etau": "durchschnittl. &lt;em&gt;upload&lt;/em&gt; Geschw. &amp; gesch. Restzeit",
"ut_etat": "durchschnittl. &lt;em&gt;total&lt;/em&gt; Geschw. &amp; gesch. Restzeit",
"uct_ok": "Erfolgreich abgeschlossen",
"uct_ng": "no-good: fehlgeschlagen / abgelehnt / nicht gefunden",
"uct_done": "ok and ng zusammen",
"uct_bz": "wird gehasht oder hochgeladen",
"uct_q": "ausstehend",
"utl_name": "Dateiname",
"utl_ulist": "Liste",
"utl_ucopy": "kopieren",
"utl_links": "Links",
"utl_stat": "Status",
"utl_prog": "Fortschritt",
// keep short:
"utl_404": "404",
"utl_err": "Fehler",
"utl_oserr": "OS-Fehler",
"utl_found": "gefunden",
"utl_defer": "zurückstellen",
"utl_yolo": "YOLO",
"utl_done": "fertig",
"ul_flagblk": "Die Dateien wurden zur Warteschlange hinzugefügt</b><br>jedoch ist up2k gerade in einem anderen Browsertab aktiv.<br>Ich warte, bis der Upload abgeschlossen ist.",
"ul_btnlk": "Die Serverkonfiguration hat diese Einstellung gesperrt",
"udt_up": "Upload",
"udt_srch": "Suchen",
"udt_drop": "hier ablegen",
"u_nav_m": '<h6>okay, was gibts??</h6><code>Eingabe</code> = Dateien (1 oder mehr)\n<code>ESC</code> = 1 Ordner (inkl. Unterordner)',
"u_nav_b": '<a href="#" id="modal-ok">Dateien</a><a href="#" id="modal-ng">1 Ordner</a>',
"cl_opts": "Schalter",
"cl_hfsz": "Dateigröße",
"cl_themes": "Themes",
"cl_langs": "Sprache",
"cl_ziptype": "Ordner Download",
"cl_uopts": "up2k Schalter",
"cl_favico": "Favicon",
"cl_bigdir": "grosse Ordner",
"cl_hsort": "#sort",
"cl_keytype": "Schlüsselnotation",
"cl_hiddenc": "Spalten verstecken",
"cl_hidec": "verstecken",
"cl_reset": "zurücksetzen",
"cl_hpick": "zum Verstecken, tippe auf Spaltenüberschriften in der Tabelle unten",
"cl_hcancel": "Spaltenbearbeitung abgebrochen",
"cl_rcm": "Rechtsklick-Menü",
"ct_grid": '田 Das Raster&trade;',
"ct_ttips": '◔ ◡ ◔"> Tooltips',
"ct_thumb": 'In Raster-Ansicht, zwischen Icons und Vorschau wechseln$NHotkey: T">🖼️ Vorschaubilder',
"ct_csel": 'Benutze STRG und UMSCHALT für Dateiauswahl in Raster-Ansicht">sel',
"ct_dl": 'Beim Klick auf Dateien sie immer herunterladen (nicht einbetten)">dl',
"ct_ihop": 'Wenn die Bildanzeige geschlossen ist, scrolle runter zu den zuletzt angesehenen Dateien">g⮯',
"ct_dots": 'Verstecke Dateien anzeigen (wenn durch den Server erlaubt)">dotfiles',
"ct_qdel": 'Nur einmal fragen, wenn mehrere Dateien gelöscht werden">qdel',
"ct_dir1st": 'Ordner vor Dateien sortieren">📁 zuerst',
"ct_nsort": 'Natürliche Sortierung (für Dateinamen mit führenden Ziffern)">nsort',
"ct_utc": 'Für alle Zeitangaben UTC verwenden">UTC',
"ct_readme": 'README.md in Dateiliste anzeigen">📜 readme',
"ct_idxh": 'index.html anstelle von Dateiliste anzeigen">htm',
"ct_sbars": 'Scrollbars zeigen">⟊',
"cut_umod": "Sollte die Datei bereits auf dem Server existieren, den 'Zuletzt geändert'-Zeitstempel an deine lokale Datei anpassen (benötigt Lese- und Löschrechte)\">re📅",
"cut_turbo": "der YOLO-Knopf, den du wahrscheinlich NICHT aktivieren willst:$N$NBenutze ihn, falls du ne Menge Zeug hochladen wolltest und aus irgendeinem Grund neustarten musstest und du so schnell wie möglich weitermachen willst.$N$Ndies ersetzt den Hash-Check mit einem einfachen <em>&quot;Ist die Datei auf dem Server gleich gross?&quot;</em>, wenn die Datei also anderen Inhalt hat, wird sie NICHT nochmal hochgeladen!$N$NDu solltest dieses Feature ausschalten, sobald der Upload fertig ist und dann die gleichen Dateien nochmal &quot;hochladen&quot;, damit der Client sie verifizieren kann.\">turbo",
"cut_datechk": "Funktioniert nur in kombination mit dem Turbo-Knopf$N$NReduziert den YOLO-Faktor ein bisschen; prüft, ob der Zeitstempel deiner Datei mit dem auf dem Server übereinstimmt$N$Nsollte <em>theoretisch</em> die meisten unfertigen / korrupten Uploads erwischen, ist aber nicht zu gebrauchen, um einen Prüfdurchgang nach einem Turbo-Upload zu machen\">date-chk",
"cut_u2sz": "Grösse (in MiB) für jeden Upload-Chunk; mit grossen Werten fliegen die Bits besser über den Atlantik. Versuche kleine Werte, wenn du eine schlechte Verbindung hast (z.B. du benutzt mobile Daten in Deutschland)",
"cut_flag": "Stelle sicher, dass nur ein Tab auf einmal Dateien hochlädt$N -- andere Tabs müssen diese Funktion auch aktiviert haben $N -- funktioniert nur bei Tabs mit der gleichen Domäne",
"cut_az": "Lädt Dateien in alphabetischer Reihenfolge hoch, anstatt nach Dateigrösse$N$NAlphabethische Reihenfolge kann es einfacher machen, Server-Fehler mit naktem Auge zu erkennen, macht aber Uploads über Glassfaser / LAN etwas langsamer",
"cut_nag": "Benachrichtigung über das Betriebssystem abgeben, wenn Upload fertig ist$N(nur wenn Browser oder Tab nicht im Vordergrund ist)",
"cut_sfx": "Spielt ein Ton ab, wenn Upload fertig ist$N(nur wenn Browser oder Tab nicht im Vordergrund ist)",
"cut_mt": "Multithreading benutzen um Datei-Hashing zu beschleunigen$N$NDies nutzt Web-Workers und benötigt$Nmehr RAM (bis zu 512 MiB extra)$N$Nbeschleunigt HTTPS 30% schneller, HTTP um 4.5x\">mt",
"cut_wasm": "benutzt WASM anstelle des Browser-eigenen Hashers; verbessert Geschwindigkeit auf Chromium-basierten Browsern, erhöht aber die CPU-Auslastung. Viele ältere Versionen von Chrome haben Memory-Leaks, die den gesamten RAM verbrauchen und dann crashen, wenn diese Funktion aktiviert ist.\">wasm",
"cft_text": "Favicon Text (leer lassen und neuladen zum Deaktivieren)",
"cft_fg": "Vordergrundfarbe",
"cft_bg": "Hintergrundfarbe",
"cdt_lim": "max. Anz. Dateien, die in einem Ordner gezeigt werden sollen",
"cdt_ask": "beim Runterscrollen nach $NAktion fragen statt mehr,$NDateien zu laden",
"cdt_hsort": "Menge an Sortierregeln (&lt;code&gt;,sorthref&lt;/code&gt;) in Media-URLs enthalten sein sollen. Ein Wert von 0 sorgt dafür, dass Sortierregeln in Media-URLs ignoriert werden",
"cdt_ren": "spezielles Rechtsklick-Menü aktivieren, das Browser-Menü ist weiterhin mit Shift + Rechtsklick erreichbar",
"tt_entree": "Navpane anzeigen (Ordnerbaum Sidebar)$NHotkey: B",
"tt_detree": "Breadcrumbs anzeigen$NHotkey: B",
"tt_visdir": "zu ausgewähltem Ordner scrollen",
"tt_ftree": "zw. Ordnerbaum / Textdateien wechseln$NHotkey: V",
"tt_pdock": "übergeordnete Ordner in einem angedockten Fenster oben anzeigen",
"tt_dynt": "autom. wachsen wenn Baum wächst",
"tt_wrap": "Zeilenumbruch",
"tt_hover": "Beim Hovern überlange Zeilen anzeigen$N(Scrollen funktioniert nicht ausser $N&nbsp; Cursor ist im linken Gutter)",
"ml_pmode": "am Ende des Ordners...",
"ml_btns": "cmds",
"ml_tcode": "transcodieren",
"ml_tcode2": "transcodieren zu",
"ml_tint": "färben",
"ml_eq": "Audio Equalizer",
"ml_drc": "Dynamic Range Compressor",
"mt_loop": "Song wiederholen\">🔁",
"mt_one": "Wiedergabe nach diesem Song beenden\">1⃣",
"mt_shuf": "Zufällige Wiedergabe im Ordner\">🔀",
"mt_aplay": "automatisch abspielen, wenn der Link, mit dem du auf den Server zugreifst, eine Titel-ID enthält$N$NDeaktivieren verhindert auch, dass die Seiten-URL bei Musikwiedergabe mit Titel-IDs aktualisiert wird, um Autoplay zu verhindern, falls diese Einstellungen verloren gehen, die URL aber bestehen bleibt\">a▶",
"mt_preload": "nächsten Titel gegen Ende vorladen für nahtlose Wiedergabe\">Vorladen",
"mt_prescan": "vor Ende des letzten Titels zum nächsten Ordner wechseln,$Ndamit der Browser die$NWiedergabe nicht stoppt\">Navigation",
"mt_fullpre": "versuchen, den gesamten Titel vorzuladen;$N✅ bei <b>unzuverlässiger</b> Verbindung aktivieren,$N❌ bei langsamer Verbindung deaktivieren\">vollst&auml;ndig",
"mt_fau": "auf Handys verhindern, dass Musik stoppt, wenn der nächste Titel nicht schnell genug vorlädt (kann zu fehlerhafter Tag-Anzeige führen)\">☕️",
"mt_waves": "Wellenform-Suchleiste:$NAudio-Amplitude in der Leiste anzeigen\">~s",
"mt_npclip": "Buttons zum Kopieren des aktuellen Titels anzeigen\">/np",
"mt_m3u_c": "Buttons zum Kopieren der$Nausgewählten Titel als m3u8-Wiedergabeliste anzeigen\">📻",
"mt_octl": "OS-Integration (Media-Hotkeys/OSD)\">os-ctl",
"mt_oseek": "Suchen via OS-Integration erlauben$N$NHinweis: auf einigen Geräten (iPhones)$Nersetzt dies den nächsten-Titel-Button\">Suchen",
"mt_oscv": "Albumcover in OSD anzeigen\">Cover",
"mt_follow": "den spielenden Titel im Blick behalten\">🎯",
"mt_compact": "kompakte Steuerelemente\">⟎",
"mt_uncache": "Cache leeren &nbsp;(probier das, wenn dein Browser$Neine defekte Kopie eines Titels zwischenspeichert und sich weigert, ihn abzuspielen)\">Cache leeren",
"mt_mloop": "offenen Ordner wiederholen\">🔁 Schleife",
"mt_mnext": "nächsten Ordner laden und fortfahren\">📂 nächster",
"mt_mstop": "Wiedergabe beenden\">⏸ Stop",
"mt_cflac": "FLAC / WAV zu {0} konvertierebn\">flac",
"mt_caac": "AAC / M4A zu {0} konvertieren\">aac",
"mt_coth": "Convertiere alle Dateien (die nicht MP3 sind) zu {0}\">oth",
"mt_c2opus": "Beste Wahl für Desktops, Laptops, Android\">opus",
"mt_c2owa": "opus-weba, für iOS 17.5 und neuer\">owa",
"mt_c2caf": "opus-caf, für iOS 11 bis 17\">caf",
"mt_c2mp3": "benutze dieses Format für ältere Geräte\">mp3",
"mt_c2flac": "beste Klangqualität, aber riesige Downloads\">flac",
"mt_c2wav": "unkomprimierte Wiedergabe (noch größer)\">wav",
"mt_c2ok": "Gute Wahl, Chef!",
"mt_c2nd": "Das ist nicht das empfohlene Ausgabeformat für dein Gerät, aber passt schon",
"mt_c2ng": "Dein Gerät scheint dieses Ausgabeformat nicht zu unterstützen, aber lass trotzdem mal probieren",
"mt_xowa": "Es gibt Bugs in iOS, die die Hintergrund-Wiedergabe mit diesem Format verhindern; bitte nutze caf oder mp3 stattdessen",
"mt_tint": "Hintergrundlevel (0-100) auf der Seekbar$Num Buffern weniger ablenkend zu machen",
"mt_eq": "Aktiviert Equalizer und Lautstärkeregelung;$N$Nboost &lt;code&gt;0&lt;/code&gt; = Standard 100% Lautstärke (unverändert)$N$Nwidth &lt;code&gt;1 &nbsp;&lt;/code&gt; = Standard Stereo (unverändert)$Nwidth &lt;code&gt;0.5&lt;/code&gt; = 50% Links-Rechts-Crossfeed$Nwidth &lt;code&gt;0 &nbsp;&lt;/code&gt; = Mono$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = Gesangsentfernung :^)$N$NDer Equalizer macht nahtlose Alben vollständig nahtlos, also lass' ihn mit allen Werten auf Null (außer width = 1) aktiviert, wenn dir das wichtig ist",
"mt_drc": "Aktiviert den Dynamic Range Compressor (Lautstärkeglättung/-begrenzung); aktiviert auch den Equalizer zum Ausgleich, setze alle EQ-Felder außer 'width' auf 0, wenn du das nicht willst$N$Nsenkt die Lautstärke von Audio über SCHWELLENWERT dB; für jedes VERHÄLTNIS dB über SCHWELLENWERT gibt es 1 dB Ausgabe, also bedeuten Standardwerte von tresh -24 und ratio 12, dass es nie lauter als -22 dB werden sollte und der Equalizer-Boost sicher auf 0.8 oder sogar 1.8 mit ATK 0 und einem großen RLS wie 90 erhöht werden kann (funktioniert nur in Firefox; in anderen Browsern ist RLS max. 1)$N$N(siehe Wikipedia, dort wird es viel besser erklärt)",
"mb_play": "Abspielen",
"mm_hashplay": "Diese Audiodatei abspielen?",
"mm_m3u": "Drücke <code>Eingabe/OK</code> zum Abspielen\nDrücke <code>ESC/Abbrechen</code> zum Bearbeiten",
"mp_breq": "Benötigt Firefox 82+ oder Chrome 73+ oder iOS 15+",
"mm_bload": "Lädt...",
"mm_bconv": "Konvertiere zu {0}, bitte warte...",
"mm_opusen": "Dein Browser kann AAC- / M4A-Dateien nicht abspielen;\nUmwandlung zu Opus ist jetzt aktiv",
"mm_playerr": "Wiedergabefehler: ",
"mm_eabrt": "Der Wiedergabeversuch wurde abgebrochen",
"mm_enet": "Dein Internet läuft auf Edge, wa?",
"mm_edec": "Die Datei scheint beschädigt zu sein??",
"mm_esupp": "Dein Browser versteht dieses Audioformat nicht",
"mm_eunk": "Unbekannter Fehler",
"mm_e404": "Konnte Datei nicht abspielen; Fehler 404: Datei nicht gefunden.",
"mm_e403": "Konnte Datei nicht abspielen; Fehler 403: Zugriff verweigert.\n\nDrücke F5 zum Neuladen, vielleicht wurdest du abgemeldet",
"mm_e500": "Konnte Datei nicht abspielen; Fehler 500: Prüfe die Serverlogs.",
"mm_e5xx": "Konnte Datei nicht abspielen; Server Fehler ",
"mm_nof": "finde keine weiteren Audiodateien in der Nähe",
"mm_prescan": "Suche nach Musik zum Abspielen...",
"mm_scank": "Nächster Song gefunden:",
"mm_uncache": "Cache geleert; Alle Songs werden beim nächsten Abspielversuch neu heruntergeladen",
"mm_hnf": "dieser Song existiert nicht mehr",
"im_hnf": "dieses Bild existiert nicht mehr",
"f_empty": 'Dieser Ordner ist leer',
"f_chide": 'Dies blendet die Spalte «{0}» aus\n\nDu kannst Spalten in den Einstellungen wieder einblenden.',
"f_bigtxt": "Diese Datei ist {0} MiB gross -- Sicher, dass du sie als Text anzeigen willst?",
"f_bigtxt2": "Möchtest du stattdessen nur das Ende der Datei anzeigen? Das aktiviert ausserdem die Folgen- und Verfolgen-Funktion, welche neu hinzugefügte Textzeilen in Echtzeit anzeigt",
"fbd_more": '<div id="blazy">zeige <code>{0}</code> von <code>{1}</code> Dateien; <a href="#" id="bd_more">{2} anzeigen</a> oder <a href="#" id="bd_all">alle anzeigen</a></div>',
"fbd_all": '<div id="blazy">zeige <code>{0}</code> von <code>{1}</code> Dateien; <a href="#" id="bd_all">alle anzeigen</a></div>',
"f_anota": "nur {0} der {1} Elemente wurden ausgewählt;\num den gesamten Ordner auszuwählen, zuerst nach unten scrollen",
"f_dls": 'die Dateilinks im aktuellen Ordner wurden\nin Downloadlinks geändert',
"f_partial": "Um eine Datei sicher herunterzuladen, die gerade hochgeladen wird, klicke bitte die Datei mit dem gleichen Namen, aber ohne die <code>.PARTIAL</code>-Endung. Bitte drücke Abbrechen oder Escape, um dies zu tun.\n\nWenn du auf OK / Eingabe drückst, ignorierst du diese Warnung und lädst die <code>.PARTIAL</code>-Datei herunter, die ziemlich sicher beschädigte Daten enthält.",
"ft_paste": "{0} Elemente einfügen$NHotkey: STRG-V",
"fr_eperm": 'Umbenennen fehlgeschlagen:\nDir fehlt die "Verschieben"-Berechtigung in diesem Ordner',
"fd_eperm": 'Löschen fehlgeschlagen:\nDir fehlt die "Löschen"-Berechtigung in diesem Ordner',
"fc_eperm": 'Ausschneiden fehlgeschlagen:\nDir fehlt die "Verschieben"-Berechtigung in diesem Ordner',
"fp_eperm": 'Einfügen fehlgeschlagen:\nDir fehlt die "Schreiben"-Berechtigung in diesem Ordner',
"fr_emore": "Wähle mindestens ein Element zum Umbenennen aus",
"fd_emore": "Wähle mindestens ein Element zum Löschen aus",
"fc_emore": "Wähle mindestens ein Element zum Ausschneiden aus",
"fcp_emore": "Wähle mindestens ein Element aus, um es in die Zwischenablage zu kopieren",
"fs_sc": "Teile diesen Ordner",
"fs_ss": "Teile die ausgewählten Dateien",
"fs_just1d": "Du kannst nicht mehrere Ordner auswählen \noder Dateien und Ordner in der Auswahl mischen.",
"fs_abrt": "❌ Abbrechen",
"fs_rand": "🎲 Zufallsname",
"fs_go": "✅ Share erstellen",
"fs_name": "Name",
"fs_src": "Quelle",
"fs_pwd": "Passwort",
"fs_exp": "Ablauf",
"fs_tmin": "Minuten",
"fs_thrs": "Stunden",
"fs_tdays": "Tage",
"fs_never": "nie",
"fs_pname": "optionaler Linkname; zufällig wenn leer",
"fs_tsrc": "zu teilende Datei oder Ordner",
"fs_ppwd": "optionales Passwort",
"fs_w8": "erstelle Share...",
"fs_ok": "drücke <code>Eingabe/OK</code> für Zwischenablage\ndrücke <code>ESC/Abbrechen</code> zum Schliessen",
"frt_dec": "Kann Fälle von beschädigten Dateien beheben\">url-decode",
"frt_rst": "Geänderte Dateinamen auf Orginale zurücksetzen\">↺ zurücksetzen",
"frt_abrt": "Abbrechen und dieses Fenster schliessen\">❌ abbrechen",
"frb_apply": "ÜBERNEHMEN",
"fr_adv": "Stapel-/Metadaten-/Musterumbenennung\">erweitert",
"fr_case": "Groß-/Kleinschreibung beachten (Regex)\">Großschreibung",
"fr_win": "Windows-kompatible Namen; ersetzt <code>&lt;&gt;:&quot;\\|?*</code> durch japanische Fullwidth-Zeichen\">win",
"fr_slash": "Ersetzt <code>/</code> durch ein Zeichen, das keine neuen Ordner erstellt\">no /",
"fr_re": "Regex-Suchmuster für Originaldateinamen; Erfassungsgruppen können im Formatfeld unten als &lt;code&gt;(1)&lt;/code&gt; und &lt;code&gt;(2)&lt;/code&gt; usw. referenziert werden",
"fr_fmt": "inspiriert von foobar2000:$N&lt;code&gt;(title)&lt;/code&gt; wird durch Songtitel ersetzt,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; überspringt [diesen] Teil falls Interpret leer$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; füllt die Titelnummer auf 2 Ziffern auf",
"fr_pdel": "Löschen",
"fr_pnew": "Speichern als",
"fr_pname": "Gib der Vorlage einen Namen",
"fr_aborted": "Abgebrochen",
"fr_lold": "Alter Name",
"fr_lnew": "Neuer Name",
"fr_tags": "Tags für die ausgewählten Dateien (liest nur, als Referenz):",
"fr_busy": "Benenne {0} Elemente um...\n\n{1}",
"fr_efail": "Umbenennen fehlgeschlagen:\n",
"fr_nchg": "{0} der neuen Namen wurden angepasst durch <code>win</code> und/oder <code>no /</code>\n\nMöchtest du mit diesen geänderten Namen fortfahren?",
"fd_ok": "Löschen OK",
"fd_err": "Löschen fehlgeschlagen:\n",
"fd_none": "Nichts würde gelöscht; vielleicht durch die Serverkonfiguration blockiert (xbd)?",
"fd_busy": "Lösche {0} Elemente...\n\n{1}",
"fd_warn1": "Diese {0} Elemente LÖSCHEN?",
"fd_warn2": "<b>Ich frage das letzte Mal!</b> Was weg ist, ist weg. Keine Chance, das rückgängig zu machen. Löschen?",
"fc_ok": "{0} Elemente ausgeschnitten",
"fc_warn": '{0} Elemente in die Zwischenablage kopiert\n\nAber: nur <b>dieses</b> Browsertab kann sie einfügen\n(da deine Auswahl so abartig riesig war)',
"fcc_ok": "{0} Elemente in die Zwischenablage kopiert",
"fcc_warn": '{0} Elemente in die Zwischenablage kopiert\n\nAber: nur <b>dieses</b> Browsertab kann sie einfügen\n(da deine Auswahl so abartig riesig war)',
"fp_apply": "Diese Namen verwenden",
"fp_skip": "Konflikte überspringen",
"fp_ecut": "Kopiere erst ein paar Dateien / Ordner, um sie einzufügen\n\nTipp: Ausschneiden und Kopieren funktioniert über Browsertabs hinweg",
"fp_ename": '{0} Elemente konnten nicht verschoben werden, weil bereits andere Dateien mit diesen Namen existieren. Gib ihnen unten neue Namen um fortzufahren, oder lass das Feld leer um sie zu überspringen ("Konflikte überspringen" macht das automatisch):',
"fcp_ename": '{0} Elemente konnten nicht kopiert werden, weil bereits andere Dateien mit diesen Namen existieren. Gib ihnen unten neue Namen um fortzufahren, oder lass das Feld leer um sie zu überspringen ("Konflikte überspringen" macht das automatisch):',
"fp_emore": "Es gibt noch ein paar Dateinamen, die geändert werden müssen",
"fp_ok": "Verschieben OK",
"fcp_ok": "Kopieren OK",
"fp_busy": "Verschiebe {0} Elemente...\n\n{1}",
"fcp_busy": "Kopiere {0} Elemente...\n\n{1}",
"fp_abrt": "wird abgebrochen...",
"fp_err": "Verschieben fehlgeschlagen:\n",
"fcp_err": "Kopieren fehlgeschlagen:\n",
"fp_confirm": "Diese {0} Elemente hierher verschieben?",
"fcp_confirm": "Diese {0} Elemente hierher kopieren?",
"fp_etab": 'Konnte die Zwischenablage nicht vom anderen Browsertab lesen',
"fp_name": "Lade Datei von deinem Gerät hoch. Gib ihr einen Namen:",
"fp_both_m": '<h6>Wähle, was eingefügt werden soll</h6><code>Eingabe</code> = {0} Dateien von «{1}» verschieben\n<code>ESC</code> = {2} Dateien von deinem Gerät hochladen',
"fcp_both_m": '<h6>Wähle, was eingefügt werden soll</h6><code>Eingabe</code> = {0} Dateien von «{1}» kopieren\n<code>ESC</code> = {2} Dateien von deinem Gerät hochladen',
"fp_both_b": '<a href="#" id="modal-ok">Verschieben</a><a href="#" id="modal-ng">Hochladen</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Kopieren</a><a href="#" id="modal-ng">Hochladen</a>',
"mk_noname": "Tipp' mal vorher lieber einen Namen in das Textfeld links, bevor du das machst :p",
"nmd_i1": "Füge auch die Dateiendung hinzu, z.B. <code>.md</code>",
"nmd_i2": "Du kannst nur <code>.md</code>-Dateien erstellen, da dir Lösch-Rechte fehlen",
"tv_load": "Textdatei wird geladen:\n\n{0}\n\n{1}% ({2} von {3} MiB geladen)",
"tv_xe1": "Konnte Textdatei nicht laden:\n\nFehler ",
"tv_xe2": "404, Datei nicht gefunden",
"tv_lst": "Liste der Textdateien in",
"tvt_close": "Zu Ordneransicht zurück$NHotkey: M (oder Esc)\">❌ Schliessen",
"tvt_dl": "Diese Datei herunterladen$NHotkey: Y\">💾 Herunterladen",
"tvt_prev": "Vorheriges Dokument zeigen$NHotkey: i\">⬆ vorh.",
"tvt_next": "Nächstes Dokument zeigen$NHotkey: K\">⬇ nächst.",
"tvt_sel": "Wählt diese Datei aus &nbsp; ( zum Ausschneiden / Kopieren / Löschen / ... )$NHotkey: S\">ausw.",
"tvt_j": "json verschönern$NHotkey: shift-J\">j",
"tvt_edit": "Datei im Texteditor zum Bearbeiten öffnen$NHotkey: E\">✏️ bearb.",
"tvt_tail": "Datei auf Veränderungen überwachen; Neue Zeilen werden in Echtzeit angezeigt\">📡 folgen",
"tvt_wrap": "Zeilenumbruch\">↵",
"tvt_atail": "Automatisch nach unten scrollen\">⚓",
"tvt_ctail": "Terminal-Farben dekodieren (ANSI Escape Codes)\">🌈",
"tvt_ntail": "Scrollback limitieren (Menge an Bytes an Text, die geladen bleiben sollen)",
"m3u_add1": "Song wurde zur M3U-Playlist hinzugefügt",
"m3u_addn": "{0} Songs zur M3U-Playlist hinzugefügt",
"m3u_clip": "M3U-Playlist in die Zwischenablage kopiert\n\nDu solltest eine neue Datei mit dem Namen something.m3u erstellen und die Playlist da rein kopieren; damit wird die Playlist abspielbar",
"gt_vau": "nur Ton abspielen, kein Video zeigen\">🎧",
"gt_msel": "Dateiauswahl aktivieren; STRG-klicke eine Datei zum überschreiben$N$N&lt;em&gt;wenn aktiv: Datei / Ordner doppelklicken zum Öffnen&lt;/em&gt;$N$NHotkey: S\">multiselect",
"gt_crop": "Vorschaubilder mittig zuschneiden\">crop",
"gt_3x": "hochauflösende Vorschaubilder\">3x",
"gt_zoom": "zoom",
"gt_chop": "kürzen",
"gt_sort": "sortieren nach",
"gt_name": "Name",
"gt_sz": "Grösse",
"gt_ts": "Datum",
"gt_ext": "Typ",
"gt_c1": "Dateinamen mehr kürzen (weniger zeigen)",
"gt_c2": "Dateinamen weniger kürzen (mehr zeigen)",
"sm_w8": "Suche ...",
"sm_prev": "Die Suchresultate gehören zu einer vorherigen Suchanfrage:\n ",
"sl_close": "Suchresultate schliessen",
"sl_hits": "Zeige {0} Treffer",
"sl_moar": "Mehr laden",
"s_sz": "Grösse",
"s_dt": "Datum",
"s_rd": "Pfad",
"s_fn": "Name",
"s_ta": "Tags",
"s_ua": "up@",
"s_ad": "adv.",
"s_s1": "minimum MiB",
"s_s2": "maximum MiB",
"s_d1": "min. iso8601",
"s_d2": "max. iso8601",
"s_u1": "hochgeladen nach",
"s_u2": "und/oder vor",
"s_r1": "Pfad enthält &nbsp; (Leerzeichen-separiert)",
"s_f1": "Name enthält &nbsp; (negieren mit -nope)",
"s_t1": "Tags enthält &nbsp; (^=start, end=$)",
"s_a1": "spezifische Metadaten-Eigenschaften",
"md_eshow": "Kann nicht rendern ",
"md_off": "[📜<em>readme</em>] deaktiviert in [⚙️] -- Dokument versteckt",
"badreply": "Hab die Antwort vom Server nicht verstanden. (badreply)",
"xhr403": "403: Zugriff verweigert\n\nVersuche, F5 zu drücken. Vielleicht wurdest du abgemeldet.",
"xhr0": "Unbekannt (wahrschenlich Verbindung zum Server verloren oder der Server ist offline)",
"cf_ok": "Sorry dafür -- Der DD" + wah + "oS-Schutz hat angeschlagen.\n\nEs sollte in etwa 30 Sekunden weitergehen.\n\nFalls nichts passiert, drück' F5, um die Seite neuzuladen",
"tl_xe1": "Konnte Unterordner nicht auflisten:\n\nFehler ",
"tl_xe2": "404: Ordner nicht gefunden",
"fl_xe1": "Konnte Dateien in Ordner nicht auflisten:\n\nFehler ",
"fl_xe2": "404: Ordner nicht gefunden",
"fd_xe1": "Konnte Unterordner nicht erstellen:\n\nFehler ",
"fd_xe2": "404: Übergeordneter Ordner nicht gefunden",
"fsm_xe1": "Konnte Nachricht nicht senden:\n\nFehler ",
"fsm_xe2": "404: Übergeordneter Ordner nicht gefunden",
"fu_xe1": "Konnte unpost-Liste nicht laden:\n\nFehler ",
"fu_xe2": "404: Datei nicht gefunden??",
"fz_tar": "Unkomprimierte GNU TAR-Datei (Linux / Mac)",
"fz_pax": "Unkomprimierte pax-Format TAR-Datei (langsamer)",
"fz_targz": "GNU-TAR mit gzip Level 3 Kompression$N$Nüblicherweise recht langsam,$Nbenutze stattdessen ein unkomprimiertes TAR",
"fz_tarxz": "GNU-TAR mit xz level 1 Kompression$N$Nüblicherweise recht langsam,$Nbenutze stattdessen ein unkomprimiertes TAR",
"fz_zip8": "ZIP mit UTF8-Dateinamen (könnte kaputt gehen auf Windows 7 oder älter)",
"fz_zipd": "ZIP mit traditionellen CP437-Dateinamen, für richtig alte Software",
"fz_zipc": "CP437 mit früh berechnetem CRC32,$Nfür MS-DOS PKZIP v2.04g (Oktober 1993)$N(braucht länger zum Verarbeiten, bevor der Download starten kann)",
"un_m1": "Unten kannst du deine neusten Uploads löschen (oder unvollständige abbrechen)",
"un_upd": "Neu laden",
"un_m4": "Oder die unten sichtbaren Dateien teilen:",
"un_ulist": "Anzeigen",
"un_ucopy": "Kopieren",
"un_flt": "Optionale Filter:&nbsp; URL muss enthalten",
"un_fclr": "Filter löschen",
"un_derr": 'unpost-delete fehlgeschlagen:\n',
"un_f5": 'Etwas ist kaputt gegangen, versuche die Seite neuzuladen (drücke dazu F5)',
"un_uf5": "Sorry, aber du musst die Seite neuladen (z.B. in dem du F5 oder STRG-R drückst) bevor zu diesen Upload abbrechen kannst",
"un_nou": '<b>Warnung:</b> Der Server ist grade zu beschäftigt, um unvollständige Uploads anzuzeigen; Drücke den "Neu laden"-Link in ein paar Sekunden',
"un_noc": '<b>Warnung:</b> unpost von vollständig hochgeladenen Dateien ist über die Serverkonfiguration gesperrt',
"un_max": "Zeige die ersten 2000 Dateien (benutze Filter, um die gewünschten Dateien zu finden)",
"un_avail": "{0} zuletzt hochgeladene Dateien können gelöscht werden<br />{1} Unvollständige können abgebrochen werden",
"un_m2": "Sortiert nach Upload-Zeitpunkt; neuste zuerst:",
"un_no1": "Hoppala! Es gibt keine ausreichend aktuellen Uploads.",
"un_no2": "Pech gehabt! Kein Upload, der zu dem Filter passen würde, ist neu genug",
"un_next": "Lösche die nächsten {0} Dateien",
"un_abrt": "Abbrechen",
"un_del": "Löschen",
"un_m3": "Deine letzten Uploads werden geladen ...",
"un_busy": "Lösche {0} Dateien ...",
"un_clip": "{0} Links in die Zwischenablage kopiert",
"u_https1": "für bessere Performance solltest du",
"u_https2": "auf HTTPS wechseln",
"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+",
"u_nodrop": 'Dein Browser ist zu alt für Drag-and-Drop Uploads',
"u_notdir": "Das ist kein Ordner!\n\nDein Browser ist zu alt,\nversuch stattdessen dragdrop",
"u_uri": "Um Bilder per Drag-and-Drop aus anderen Browserfenstern hochzuladen,\nlass' sie bitte über dem grossen Upload-Button fallen",
"u_enpot": 'Zu <a href="#">Potato UI</a> wechseln (kann Upload-Geschw. verbessern)',
"u_depot": 'Zu <a href="#">fancy UI</a> wechseln (kann Upload-Geschw. verschlechtern)',
"u_gotpot": 'Wechsle zu Potato UI für verbesserte Upload-Geschwindigkeit,\n\nwenn du anderer Meinung bist, kannst du gerne zurück wechseln',
"u_pott": "<p>Dateien: &nbsp; <b>{0}</b> fertig, &nbsp; <b>{1}</b> fehlgeschlagen, &nbsp; <b>{2}</b> in Bearbeitung, &nbsp; <b>{3}</b> ausstehend</p>",
"u_ever": "Dies ist der Basic Uploader; up2k benötigt mind. <br>Chrome 21 // Firefox 13 // Edge 12 // Opera 12 // Safari 5.1",
"u_su2k": 'Dies ist der Basic Uploader; <a href="#" id="u2yea">up2k</a> ist besser',
"u_uput": 'Für Geschwindigkeit optimieren (Checksum überspringen)',
"u_ewrite": 'Du hast kein Schreibzugriff auf diesen Ordner',
"u_eread": 'Du hast kein Lesezugriff auf diesen Ordner',
"u_enoi": 'file-search ist in der Serverkonfiguration nicht aktiviert',
"u_enoow": "Überschreiben wird hier nicht funktionieren; benötige Lösch-Berechtigung",
"u_badf": 'Diese {0} Dateien (von insgesammt {1}) wurden übersprungen, wahrscheinlich wegen Dateisystem-Berechtigungen:\n\n',
"u_blankf": 'Diese {0} Dateien (von insgesammt {1}) sind leer; trotzdem hochladen?\n\n',
"u_applef": 'Diese {0} Dateien (von insgesammt {1}) sind möglicherweise unerwünscht;\n<code>OK/Eingabe</code> drücken, um die folgenden Dateien zu überspringen.\nDrücke <code>Abbrechen/ESC</code> um sie NICHT zu überspringen und diese AUCH HOCHZULADEN:\n\n',
"u_just1": '\nFunktioniert vielleicht besser, wenn du nur eine Datei auswählst',
"u_ff_many": "Falls du <b>Linux / MacOS / Android</b> benutzt, <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>könnte</em> Firefox mit dieser Menge an Dateien crashen!</a>\nFalls das passiert, probier nochmal (oder benutz Chrome).",
"u_up_life": "Dieser Upload wird vom Server gelöscht\n{0} nachdem er abgeschlossen ist",
"u_asku": 'Diese {0} Dateien nach <code>{1}</code> hochladen',
"u_unpt": "Du kannst diesen Upload rückgängig machen mit dem 🧯 oben-links",
"u_bigtab": 'Versuche {0} Dateien anzuzeigen.\n\nDas könnte dein Browser crashen, bist du dir wirklich sicher?',
"u_scan": 'Scanne Dateien...',
"u_dirstuck": 'Ordner-Iterator blieb hängen beim Versuch, diese {0} Einträge zu lesen; überspringe:',
"u_etadone": 'Fertig ({0}, {1} Dateien)',
"u_etaprep": '(Upload wird vorbereitet)',
"u_hashdone": 'Hashing vollständig',
"u_hashing": 'Hash',
"u_hs": 'Wir schütteln uns die Hände ("handshaking")...',
"u_started": "Dateien werden hochgeladen; siehe [🚀]",
"u_dupdefer": "Duplikat; wird nach allen anderen Dateien verarbeitet",
"u_actx": "Klicke diesen Text um Performance-<br />Einbusen zu Vermeiden beim Wechsel auf andere Fenster/Tabs",
"u_fixed": "OK!&nbsp; Habs repariert 👍",
"u_cuerr": "failed to upload chunk {0} of {1};\nprobably harmless, continuing\n\nfile: {2}",
"u_cuerr2": "server rejected upload (chunk {0} of {1});\nwill retry later\n\nfile: {2}\n\nerror ",
"u_ehstmp": "versuche nochmal; siehe unten-rechts",
"u_ehsfin": "Der Server hat die Anfrage zum Abschluss des Uploads abgelehnt; versuche nochmal...",
"u_ehssrch": "Der Server hat die Anfrage zur Suche abgelehnt; versuche nochmal...",
"u_ehsinit": "Der Server hat die Anfrage zum Start des Uploads abgelehnt; versuche nochmal...",
"u_eneths": "Netzwerkfehler beim Upload-Handshake; versuche nochmal...",
"u_enethd": "Netzwerkfehler beim Testen der Existenz des Ziels; versuche nochmal...",
"u_cbusy": "Der Server mag uns grade nicht mehr nach einem Netzwerkglitch, warte einen Moment...",
"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_emtleakc": 'versuche folgendes:\n<ul><li>drücke <code>F5</code> um die Seite neu zu laden</li><li>deaktivere dann den &nbsp;<code>mt</code>&nbsp; Button in den &nbsp;<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",
"u_expl": "erklären",
"u_maxconn": "die meisten Browser limitieren dies auf 6, aber Firefox lässt mehr zu unter <code>connections-per-server</code> in <code>about:config</code>",
"u_tu": '<p class="warn">WARNUNG: Turbo aktiviert, <span>&nbsp;Client könnte unvollständige Uploads verpassen und nicht wiederholen; siehe Turbo-Button Tooltip</span></p>',
"u_ts": '<p class="warn">WARNUNG: Turbo aktiviert, <span>&nbsp;Suchresultate können inkorrekt sein; siehe Turbo-Button Tooltip</span></p>',
"u_turbo_c": "Turbo deaktiviert in der Serverkonfiguration",
"u_turbo_g": "Turbo deaktiviert, da du keine Listen-Berechtigung\nauf diesem Volume hast",
"u_life_cfg": 'Autodelete nach <input id="lifem" p="60" /> min (or <input id="lifeh" p="3600" /> h)',
"u_life_est": 'Upload wird gelöscht <span id="lifew" tt="local time">---</span>',
"u_life_max": 'Dieser Ordner erzwingt eine\nmax Lebensdauer von {0}',
"u_unp_ok": 'unpost ist erlaubt für {0}',
"u_unp_ng": 'unpost wird NICHT erlaubt',
"ue_ro": 'Du hast nur Lese-Zugriff auf diesen Ordner\n\n',
"ue_nl": 'Du bist nicht angemeldet',
"ue_la": 'Du bist angemeldet als "{0}"',
"ue_sr": 'Du bist derzeit im Suchmodus\n\nWechsle zum Upload-Modus indem du auf die Lupe 🔎 klickst (neben dem grossen SUCHEN Button), und versuche den Upload nochmal.\n\nSorry',
"ue_ta": 'Versuche den Upload nochmal, sollte jetzt klappen',
"ue_ab": "Diese Datei wird gerade in einem anderen Ordner hochgeladen, dieser Upload muss zuerst abgeschlossen werden, bevor die Datei woanders hochgeladen werden kann.\n\nDu kannst den Upload abbrechen und vergessen mit dem 🧯 oben-links",
"ur_1uo": "OK: Datei erfolgreich hochgeladen",
"ur_auo": "OK: Alle {0} Dateien erfolgreich hochgeladen",
"ur_1so": "OK: Datei auf dem Server gefunden",
"ur_aso": "OK: Alle {0} Dateien auf dem Server gefunden",
"ur_1un": "Upload fehlgeschlagen, sorry",
"ur_aun": "Alle {0} Uploads fehlgeschlagen, sorry",
"ur_1sn": "Datei wurde NICHT auf dem Server gefunden",
"ur_asn": "Die {0} Dateien wurden NICHT auf dem Server gefunden",
"ur_um": "Fertig;\n{0} Uploads OK,\n{1} Uploads fehlgeschlagen, sorry",
"ur_sm": "Fertig;\n{0} Uploads gefunden auf dem Server,\n{1} Dateien NICHT gefunden auf dem Server",
"rc_opn": "öffnen",
"rc_ply": "abspielen",
"rc_pla": "als Audio abspielen",
"rc_txt": "als Text öffnen",
"rc_md": "im Texteditor öffnen",
"rc_dl": "herunterladen",
"rc_zip": "als Archiv herunterladen",
"rc_del": "löschen",
"rc_cut": "ausschneiden",
"rc_cpy": "kopieren",
"rc_pst": "einfügen",
"rc_nfo": "neuer Ordner",
"rc_nfi": "neue Datei",
"rc_sal": "alles auswählen",
"rc_sin": "auswahl umkehren",
"lang_set": "Neuladen um Änderungen anzuwenden?",
"splash": {
"a1": "Neu laden",
"b1": "Tach, wie geht's? &nbsp; <small>(Du bist nicht angemeldet)</small>",
"c1": "Abmelden",
"d1": "Zustand",
"d2": "Zeigt den Zustand aller aktiven Threads",
"e1": "Config neu laden",
"e2": "Konfigurationsdatei neu laden (Accounts/Volumes/VolFlags)$Nund scannt alle e2ds-Volumes$N$NBeachte: Jegliche Änderung an globalen Einstellungen$Nbenötigt einen Neustart zum Anwenden",
"f1": "Du kannst lesen:",
"g1": "Du kannst hochladen nach:",
"cc1": "Andere Dinge:",
"h1": "k304 deaktivieren",
"i1": "k304 aktivieren",
"j1": "k304 trennt die Clientverbindung bei jedem HTTP 304, was Bugs mit problematischen Proxies vorbeugen kann (z.B. nicht ladenden Seiten), macht Dinge aber generell langsamer",
"k1": "Client-Einstellungen zurücksetzen",
"l1": "Melde dich an für mehr:",
"ls3": "Anmelden",
"lu4": "Benutzername",
"lp4": "Passwort",
"lo3": "“{0}” überall abmelden",
"lo2": "Das beendet die Sitzung in allen Browsern",
"m1": "Willkommen zurück,",
"n1": "404 Nicht gefunden &nbsp;┐( ´ -`)┌",
"o1": 'or maybe you don\'t have access -- try a password or <a href="' + SR + '/?h">go home</a>',
"p1": "403 Verboten &nbsp;~┻━┻",
"q1": 'Benutze ein Passwort oder <a href="' + SR + '/?h">gehe zur Homepage</a>',
"r1": "Gehe zur Homepage",
".s1": "Neu scannen",
"t1": "Aktion",
"u2": "time since the last server write$N( upload / rename / ... )$N$N17d = 17 days$N1h23 = 1 hour 23 minutes$N4m56 = 4 minutes 56 seconds",
"v1": "Verbinden",
"v2": "Benutze diesen Server als lokale Festplatte",
"w1": "Zu HTTPS wechseln",
"x1": "Passwort ändern",
"y1": "Shares bearbeiten",
"z1": "Share entsperren:",
"ta1": "Trage zuerst dein Passwort ein",
"ta2": "Wiederhole dein Passwort zur Bestätigung:",
"ta3": "Da stimmt etwas nicht; probier's nochmal",
"nop": "FEHLER: Passwort darf nicht leer sein",
"nou": "FEHLER: Benutzername und/oder Passwort dürfen nicht leer sein",
"aa1": "Eingehende Dateien:",
"ab1": "no304 deaktivieren",
"ac1": "no304 aktivieren",
"ad1": "Das Aktivieren von no304 deaktiviert jegliche Form von Caching; probier dies, wenn k304 nicht genug war. Dies verschwendet eine grosse Menge Netzwerk-Traffic!",
"ae1": "Aktive Downloads:",
"af1": "Zeige neue Uploads",
"ag1": "Bekannte IdP-Benutzer anzeigen", //m
}
};

710
copyparty/web/tl/epo.js Normal file
View file

@ -0,0 +1,710 @@
// Linioj, finiĝantaj per "//m", estas nekontrolitaj maŝinaj tradukoj
Ls.epo = {
"tt": "Esperanto",
"cols": {
"c": "ago-butonoj",
"dur": "daŭro",
"q": "kvalito / bitrapido",
"Ac": "sonkodeko",
"Vc": "videokodeko",
"Fmt": "formato / ujo",
"Ahash": "kontrolsumo de aŭdio",
"Vhash": "kontrolsumo de video",
"Res": "distingivo",
"T": "dosiertipo",
"aq": "kvalito / bitrapido de aŭdio",
"vq": "kvalito / bitrapido de video",
"pixfmt": "specimenado / strukturo de bilderoj",
"resw": "horizontala distingivo",
"resh": "vertikala distingivo",
"chs": "nombro de aŭdio-kanaloj",
"hz": "sonpecrapido",
},
"hks": [
[
"misc",
["ESK", "malfermi variajn aferojn"],
"file-manager",
["G", "baskuli inter lista kaj krada vido"],
["T", "baskuli montradon de bildetoj"],
["⇧ A/D", "grandeco de bildetoj"],
["stir-K", "forigi elektitajn"],
["stir-X", "eltondi elektaĵon al tondujo"],
["stir-C", "kopii elektaĵon al tondujo"],
["stir-V", "alglui (movi/kopii) ĉi tien"],
["Y", "elŝuti elektitajn"],
["F2", "alinomi elektitajn"],
"file-list-sel",
["spacoklavo", "baskuli elektadon de dosieroj"],
["↑/↓", "movi elektado-kursoron"],
["stir ↑/↓", "movi kursoron kaj vidujon"],
["⇧ ↑/↓", "elekti (mal)sekvan dosieron"],
["stir-A", "elekti ĉiujn dosier(uj)ojn"],
], [
"navigation",
["B", "baskuli inter paĝnivela kaj arbovida navigo"],
["I/K", "(mal-)sekva dosierujo"],
["M", "parent folder (or unexpand current)"],
["V", "baskuli inter montrado de dosierujoj aŭ tekst-dosieroj en toggle folders / textfiles en arbovida navig-panelo"],
["A/D", "grandeco de arbovida navig-panelo"],
], [
"audio-player",
["J/L", "(mal-)sekva kanto"],
["U/O", "iri 10 sekundoj (mal)antaŭen"],
["0..9", "iri al 0%..90%"],
["P", "ludi/paŭzigi (ankaŭ komencas)"],
["S", "elekti ludantan kanton"],
["Y", "elŝuti kanton"],
], [
"image-viewer",
["J/L, ←/→", "(mal)sekva bildo"],
["Home/End", "unua/lasta bildo"],
["F", "plenekrana vido"],
["R", "turni dekstrumen"],
["⇧ R", "turni maldekstrumen"],
["S", "elekti bildon"],
["Y", "elŝuti bildon"],
], [
"video-player",
["U/O", "iri 10 sekundoj (mal)antaŭen"],
["P/K/Spaco", "ludi/paŭzigi"],
["C", "??continue playing next"],
["V", "cikla ludado"],
["M", "silentigi"],
["[ and ]", "agordi intervalon de cikla ludado"],
], [
"textfile-viewer",
["I/K", "(mal)sekva dosiero"],
["M", "fermi dosieron"],
["E", "redakti dosieron"],
["S", "elekti dosieron (por eltondado/kopiado/alinomado)"],
["Y", "elŝuti tekstodosieron"], //m
["⇧ J", "beligi json"], //m
]
],
"m_ok": "OK",
"m_ng": "Rezigni",
"enable": "Ŝalti",
"danger": "DANĜERO",
"clipped": "kopiita al tondujo",
"ht_s1": "sekundo",
"ht_s2": "sekundoj",
"ht_m1": "minuto",
"ht_m2": "minutoj",
"ht_h1": "horo",
"ht_h2": "horoj",
"ht_d1": "tago",
"ht_d2": "tagoj",
"ht_and": " kaj ",
"goh": "stirpanelo",
"gop": 'malsekva dosierujo">malsekva',
"gou": 'supra dosierujo">supren',
"gon": 'sekva dosierujo">sekva',
"logout": "Adiaŭi kiel ",
"login": "Ensaluti",
"access": " atingo",
"ot_close": "fermi submenuon",
"ot_search": "serĉi dosierojn per atributoj, indiko / nomo, etikedoj de muziko aŭ ĉiu kombinaĵo de tiuj parametroj$N$N&lt;code&gt;foo bar&lt;/code&gt; = devas enhavi ambaŭ «foo» kaj «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = devas enhavi «foo», sed ne «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = komenci per «yana» kaj esti dosieron de formato «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = enhavi precipe «try unite»$N$Nformato de datoj estas iso-8601, ekzemple$N&lt;code&gt;2009-12-31&lt;/code&gt; aŭ &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: forigi viaj plej lastaj alŝutoj, aŭ ĉesigi nefinigitajn",
"ot_bup": "bup: fundamenta alŝutilo, funkias eĉ kun netscape 4.0",
"ot_mkdir": "mkdir: krei novan dosierujon",
"ot_md": "new-file: krei novan tekstodosieron", //m
"ot_msg": "msg: sendi mesaĝon al servila protokolo",
"ot_mp": "agordoj de medialudilo",
"ot_cfg": "aliaj agordoj",
"ot_u2i": 'up2k: alŝuti dosierojn (se vi havas skribo-atingon) aŭ ŝalti ŝerc-reĝimon por determini, ĉu dosieroj jam ekzistas ie ĉe la servilo$N$Nalŝutoj estas daŭrigeblaj, plurfadenaj, kaj prezervas tempindikojn, sed ĝi estas pli procesor-intensa ol [🎈]&nbsp; (la fundamenta alŝutilo)<br /><br />dum alŝutado, ĉi tiu simbolo iĝas plenumindikilo!',
"ot_u2w": 'up2k: alŝuti dosierojn kun subteno de daŭrigeblo (fermu vian retumilon kaj demetu la samajn dosierojn poste)$N$Nalŝutoj estas daŭrigeblaj, plurfadenaj, kaj prezervas tempindikojn, sed ĝi estas pli procesor-intensa ol [🎈]&nbsp; (la fundamenta alŝutilo)<br /><br />dum alŝutado, ĉi tiu simbolo iĝas plenumindikilo!',
"ot_noie": 'Bonvolu uzi retumilojn Chrome / Firefox / Edge',
"ab_mkdir": "krei dosierujon",
"ab_mkdoc": "krei tekstodosieron", //m
"ab_msg": "sendi mesaĝon al protokolo",
"ay_path": "iri al dosierujoj",
"ay_files": "iri al dosieroj",
"wt_ren": "alinomi elektitajn aĵojn$NFulmoklavo: F2",
"wt_del": "forigi elektitajn aĵojn$NFulmoklavo: stir-K",
"wt_cut": "eltondi elektitajn aĵojn &lt;small&gt;(do alglui ien aliloke)&lt;/small&gt;$NFulmoklavo: stir-X",
"wt_cpy": "kopii elektitajn aĵojn al tondujo$N(por alglui ien aliloke)$NFulmoklavo: stir-C",
"wt_pst": "alglui antaŭe eltonditajn / kopiitajn aĵojn$NFulmoklavo: stir-V",
"wt_selall": "elekti ĉiujn dosierojn$NFulmoklavo: stir-A (se dosiero estas elektita)",
"wt_selinv": "inversigi elektaĵon",
"wt_zip1": "elŝuti dosierujon kiel arkivo",
"wt_selzip": "elŝuti elektaĵon kiel arkivo",
"wt_seldl": "elŝuti elektaĵon kiel apartaj dosieroj$NFulmoklavo: Y",
"wt_npirc": "kopii IRC-formatan muzikaĵ-informon",
"wt_nptxt": "kopii tekstan muzikaĵ-informon",
"wt_m3ua": "aldoni al m3u-ludliston (klaku butonon <code>📻copy</code> poste)",
"wt_m3uc": "kopii m3u-ludliston al tondujo",
"wt_grid": "baskuli kradan / listan vidon$NFulmoklavo: G",
"wt_prev": "malsekva muzikaĵo$NFulmoklavo: J",
"wt_play": "ludi / paŭzigi$NFulmoklavo: P",
"wt_next": "sekva muzikaĵo$NFulmoklavo: L",
"ul_par": "paralelaj alŝutoj:",
"ut_rand": "hazardigi dosiernomojn",
"ut_u2ts": "kopii la tempon de lasta modifo$Nel via dosiersistemo al la servilo\">📅",
"ut_ow": "ĉu anstataŭigi dosierojn ĉe la servilo?$N🛡: neniam (dosiero estos alŝutita kun nova dosiernomo)$N🕒: anstataŭigi, se servila dosiero estas pli malnova ol via$N♻: ĉiam anstataŭigi, se dosieroj estas malsamaj$N⏭: senkondiĉe preterlasi ĉiujn ekzistantajn dosierojn", //m
"ut_mt": "daŭri kalkuladon de kontrolsumoj por aliaj dosieroj dum alŝutado$N$Nmalŝaltinda, se via procesoro aŭ disko ne estas sufiĉe rapidaj",
"ut_ask": 'peti konfirmon antaŭ komenco de alŝutado">💭',
"ut_pot": "plirapidigi alŝutadon por malrapidaj komputiloj$Nper malkomplikado de fasado",
"ut_srch": "ne alŝuti ion ajn, nur kontroli, ke la dosieroj $N jam ekzistas ĉe la servilo (ĉiuj dosierujoj, kiuj vi povas legi, estos skanitaj)",
"ut_par": "paŭzi alŝutadon per agordado kiel 0$N$Npligrandigi, se via konekto estas malrapida aŭ malfruema$N$Nagordi kiel 1, se la loka reto aŭ servila disko ne estas sufiĉe rapidaj",
"ul_btn": "demeti dosier(uj)ojn<br>ĉi tien (aŭ alklaki ĉi tien)",
"ul_btnu": "A L Ŝ U T I",
"ul_btns": "S E R Ĉ I",
"ul_hash": "k-sumado",
"ul_send": "sendado",
"ul_done": "finita",
"ul_idle1": "neniuj alŝutoj envicigitaj",
"ut_etah": "meza rapido de &lt;em&gt;kontrolsumado&lt;/em&gt;, kaj pritaksita tempo ĝis la fino",
"ut_etau": "meza rapido de &lt;em&gt;alŝutado&lt;/em&gt;, kaj pritaksita tempo ĝis la fino",
"ut_etat": "meza &lt;em&gt;tuta&lt;/em&gt; rapido, kaj pritaksita tempo ĝis la fino",
"uct_ok": "sukcese plenumita",
"uct_ng": "malbona: malsukceso / malakcepto / ne trovita (no good)",
"uct_done": "ambaŭ ok kaj ng",
"uct_bz": "kontrolsumado aŭ alŝutado (busy)",
"uct_q": "envicigita (queue)",
"utl_name": "dosiernomo",
"utl_ulist": "listigi",
"utl_ucopy": "kopii",
"utl_links": "ligilojn",
"utl_stat": "stato",
"utl_prog": "progreso",
// keep short:
"utl_404": "404",
"utl_err": "ERARO",
"utl_oserr": "OS-eraro",
"utl_found": "trovita",
"utl_defer": "postigita",
"utl_yolo": "rapidega",
"utl_done": "finita",
"ul_flagblk": "la dosieroj estis aldonita al la vico,</b><br>sed alia langeto de retumilo jam alŝutas dosierojn per up2k,<br>do tiu alŝutado devas finiĝi unue",
"ul_btnlk": "la agordado de servilo ne permesas ŝanĝi tiun agordon",
"udt_up": "Alŝuti",
"udt_srch": "Serĉi",
"udt_drop": "demetu ĉi tien",
"u_nav_m": '<h6>do, kion vi havas ĉi tie?</h6><code>Enter</code> = Dosierojn (unu al multaj)\n<code>ESK</code> = Unu dosierujon (eble kun subdosierujoj)',
"u_nav_b": '<a href="#" id="modal-ok">Dosierojn</a><a href="#" id="modal-ng">Unu dosierujo</a>',
"cl_opts": "ŝaltiloj",
"cl_hfsz": "dosiergrando",
"cl_themes": "etoso",
"cl_langs": "lingvo",
"cl_ziptype": "elŝutado de dosieroj",
"cl_uopts": "agordoj de up2k",
"cl_favico": "retpaĝsimbolo",
"cl_bigdir": "grandaj ujoj",
"cl_hsort": "#ordigo",
"cl_keytype": "skemo de fulmoklavoj",
"cl_hiddenc": "kaŝitaj kolumnoj",
"cl_hidec": "kaŝi",
"cl_reset": "restarigi",
"cl_hpick": "alklaki la kapojn de kolumnoj por kasi en la suban tabelon",
"cl_hcancel": "kaŝado de kolumno nuligita",
"cl_rcm": "dekstra-klaka menuo", //m
"ct_grid": '田 krado',
"ct_ttips": '◔ ◡ ◔"> ŝpruchelpiloj',
"ct_thumb": 'dum krado-vido, baskuli montradon de simboloj aŭ bildetoj$NFulmoklavo: T">🖼️ bildetoj',
"ct_csel": 'uzi STIR kaj MAJ por elekti dosierojn en krado-vido">elekto',
"ct_dl": 'devigi elŝuton (ne montri enkadre) kiam dosiero estas alklakita">dl', //m
"ct_ihop": 'montri la lastan viditan bildo-dosieron post fermado de bildo-vidilo">g⮯',
"ct_dots": 'montri kaŝitajn dosierojn (se servilo permesas)">kaŝitaj',
"ct_qdel": 'peti konfirmon nur unufoje antaŭ forigado">rapid-forig.',
"ct_dir1st": 'ordigi dosierujojn antaŭ dosieroj">📁 unue',
"ct_nsort": 'numera ordigo de dosiernomoj (ekz. &lt;code&gt;2&lt;/code&gt; antaŭ &lt;code&gt;11&lt;/code&gt;)">№.ord',
"ct_utc": 'montri ĉiuj datoj kaj tempoj per UTC">UTC',
"ct_readme": 'montri enhavon de README.md en listaĵo de dosieroj">📜 readme',
"ct_idxh": 'montri paĝon index.html anstataŭ listaĵo de dosieroj">htm',
"ct_sbars": 'montri rulumskalojn">⟊',
"cut_umod": "se dosiero jam ekzistas en la servilo, ŝanĝi la tempon de lasta modifo laŭ via dosiero (bezonas permesojn write+delete)\">re📅igi",
"cut_turbo": "rapidigi alŝutojn KOSTE DE TUTA KONTROLADO:$N$Nuzinda, se vi alŝutis grandegajn dosierojn, devis haltigi la alŝutadon, kaj nun volas daŭrigi ĝin rapidege$N$Nse ĉi tiu agordo estas ŝaltita, anstataŭ kontrolsumado, la servilo nur kontrolas, ĉu la grando de via kaj servila dosieroj estas samaj, kaj ne realŝutas dosierojn kun samaj grandoj$N$Npost ĉio finiĝis, vi devus malŝalti ĉi tiun agordon, do provi &quot;alŝuti&quot; la tiuj samaj dosieroj — la kontrolsumado rekomencos kaj ne realŝutos ion ajn, se la alŝutado vere sukcesis\">rapidega",
"cut_datechk": "efektas nur se &quot;rapidega&quot; alŝutado estas ŝaltita$N$Nete plibonigas fidindon de kontrolado, per kontrolado de modifo-tempoj aldone al grandoj$N$N<em>teorie</em> estas sufiĉe por detekti nefinigitajn aŭ difektitajn alŝutojn, sed ne estas kompleta alternativo por sen-&quot;rapidega&quot; kontrolado\">dato-kontrolo",
"cut_u2sz": "grando (en MiBoj) de ĉiu alŝutanta ero; grandaj valoroj estas pli bonaj por longdistancaj konektoj, malgrandajn por malalt-kvalitaj konektoj",
"cut_flag": "certigi, ke nur unu langeto alŝutas samttempe $N -- aliaj langetoj devas ankaŭ ŝalti ĉi tiun agordon $N -- nur funkcias por langetoj de sama domajno",
"cut_az": "alŝuti dosierojn en alfabeta ordigo anstataŭ &quot;plej malgrandaj unue&quot;$N$Nalfabeta ordo igas pli simple vidi, ke okazis eraroj en la servilo, sed estas pli malrapida sur tre rapidaj konektoj (ekz. en la loka reto aŭ per fibrooptiko)",
"cut_nag": "sciigi per operaciumo je fino de alŝutado$N(nur se ĉi tiu langeto de retumilo ne estas aktiva)",
"cut_sfx": "sciigi per sono je fino de alŝutado$N(nur se ĉi tiu langeto de retumilo ne estas aktiva)",
"cut_mt": "kontrolsumi dosierojn pli rapide per multaj fadenoj$N$Nuzas teknologio Web Worker, bezonas pli da labormemoro (maksimume 512 MiB)$N$Nplirapidigas https je 30%, http je 4.5x\">mf",
"cut_wasm": "uzi WASM-modulon anstataŭ kontrolsumilaj funkcioj de retumilo; plirapidigas kontrolsumadon sur Chrome-bazitaj retumiloj, sed ankaŭ pli procesor-intensa; malnovaj versioj de Chrome havas difektojn, kiuj misuzas la tutan labormemoron kaj kraŝas la retumilon, se ĉi tiu agordo estas ŝaltita\">wasm",
"cft_text": "teksto de retpaĝsimbolo (blankigu kaj reŝargu la paĝon por malŝalti)",
"cft_fg": "teksta koloro",
"cft_bg": "fona koloro",
"cdt_lim": "maks. nombro de dosieroj por montri en dosierujo",
"cdt_ask": "je malsupro de paĝo, peti por ago$Nanstataŭ ŝarĝi pli da dosieroj",
"cdt_hsort": "kiom da ordigo-reguloj (&lt;code&gt;,sorthref&lt;/code&gt;) inkludi en adreso de la paĝo. Se agordita kiel 0, reguloj, inkluditaj en la adreso, estos ignoritaj",
"cdt_ren": "ebligi propran dekstra-klakan menuon, la normala menuo restas alirebla per shift + dekstra klako", //m
"tt_entree": "montri arbovidan navig-panelon$NFulmoklavo: B",
"tt_detree": "montri paĝnivelan navig-panelon$NFulmoklavo: B",
"tt_visdir": "rulumi al elektita dosierujo",
"tt_ftree": "baskuli dosieruj-arban aŭ teksto-dosieran vidon$NFulmoklavo: V",
"tt_pdock": "fiksi patrajn dosierojn sur supro de panelo",
"tt_dynt": "aŭtomate pligrandigi panelon",
"tt_wrap": "linifaldo",
"tt_hover": "montri kompletajn nomojn sur musumo$N( paneas rulumadon, se la kursoro de muso $N&nbsp; ne estas en la maldekstra malplenaĵo )",
"ml_pmode": "je la fino de dosierujo...",
"ml_btns": "komandoj",
"ml_tcode": "transkodi",
"ml_tcode2": "transkodi al",
"ml_tint": "kolorado",
"ml_eq": "ekvalizilo",
"ml_drc": "kompresoro",
"mt_loop": "ripeti unu kanton\">🔁",
"mt_one": "haltigi post unu kanto\">1⃣",
"mt_shuf": "ludi ĉiu dosierujo en hazarda ordo\">🔀",
"mt_aplay": "ludi aŭtomate, se ligilo enhavas identigilon de kanto$N$Nmalŝaltado de ĉi tiu agordo ankaŭ malŝaltas ĝisdatigadon de paĝ-adreso, por ke ludado ne rekomenciĝas, se la paĝo estos poste malfermita sen aliaj agordoj\">a▶",
"mt_preload": "komenci ŝargadon de sekva kanto antaŭ la fino de la nuna, por kontinua ludado\">antaŭŝarg.",
"mt_prescan": "eniri la sekvan dosierujon antaŭ la fino de la lasta kanto, $Npor ke la retumilo ne interrompis la ludadon\">nav",
"mt_fullpre": "antaŭŝargi la tutan kanton;$N✅ ŝalti por <b>malaltkvalitaj</b> konektoj,$N❌ eble <b>malŝalti</b> por malrapidaj konektoj\">full",
"mt_fau": "por poŝtelefonoj: komenci sekvan kanton, eĉ se ĝi ne estis tute ŝargita (povas difektigi la montradon de muzikaĵ-etikedoj)\">☕️",
"mt_waves": "bildigo:$Nmontri amplitudon de ludanta kanto en ludadbreto\">~",
"mt_npclip": "montri butonojn por kopiado de ludanta kanto\">/np",
"mt_m3u_c": "montri butonojn por kopiado de elektitaj kantoj kiel m3u8-ludlisto\">📻",
"mt_octl": "integrado kun operaciumo (medio-klavoj kaj montriloj)\">integr.",
"mt_oseek": "movi tra kanto per operaciumaj stiriloj$N$Nnoto: en iuj komputiloj (iPhone),$N ĉi tiu agordo anstataŭigas la butonon de sekva kanto\">movado",
"mt_oscv": "montri album-bildojn en montriloj\">bildo",
"mt_follow": "rulumi la pagon, por ke la ludanta kanto restas videbla\">🎯",
"mt_compact": "kompaktaj ruliloj\">⟎",
"mt_uncache": "malplenigi kaŝmemoron &nbsp;(uzinda, se via retumilo kaŝmemoris$Ndifektitan kopion de kanto, kaj ne povas ludi ĝin)\">🗑️ kaŝmem.",
"mt_mloop": "ripeti la nunan dosierujon\">🔁 ripeti",
"mt_mnext": "ŝargi la sekvan dosierujon kaj daŭrigi\">📂 sekva",
"mt_mstop": "haltigi ludadon\">⏸ haltigi",
"mt_cflac": "konverti el flac / wav al {0}\">flac",
"mt_caac": "konverti el aac / m4a al {0}\">aac",
"mt_coth": "konverti aliajn (krom mp3) al {0}\">aliaj",
"mt_c2opus": "pli bona elekto por propraj komputiloj kaj Android\">opus",
"mt_c2owa": "opus-weba, por iOS 17.5 kaj pli novaj\">owa",
"mt_c2caf": "opus-caf, por iOS 11-17\">caf",
"mt_c2mp3": "por tre malnovaj iloj\">mp3",
"mt_c2flac": "plej bona sonkvalito, sed grandegaj elŝutoj\">flac",
"mt_c2wav": "sendensigita ludado (pli bonaj elŝutoj)\">wav",
"mt_c2ok": "bona elekto",
"mt_c2nd": "ĉi tiu formato ne estas rekomendita por via aparato, sed ĝi ankaŭ funkcios",
"mt_c2ng": "via aparato ŝajne ne subtenas ĉi tiun formaton, sed ni provu uzi ĝin malgraŭe",
"mt_xowa": "estas difektoj en iOS, kiuj preventas fonan ludadon per ĉi tiu formato; bonvolu uzi caf aŭ mp3 anstataŭe",
"mt_tint": "travideblo (0-100) de ludadbreto$Nvi povas ŝanĝi ĝin, se ĝi aspektas tro distre dum ŝargado",
"mt_eq": "ŝaltas ekvalizilon kaj stirilon de plifortigado;$N$Nboost (plifortigado) &lt;code&gt;0&lt;/code&gt; = senmodifa 100%a laŭteco$N$Nwidth (larĝo) &lt;code&gt;1 &nbsp;&lt;/code&gt; = senmodifa dukanala sono$Nwidth (larĝo) &lt;code&gt;0.5&lt;/code&gt; = 50% miksado inter maldekstra kaj dekstra kanaloj$Nwidth (larĝo) &lt;code&gt;0 &nbsp;&lt;/code&gt; = unukanala sono$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = senvokigo :^)$N$Nŝaltita ekvalizilo ankaŭ forigas paŭzojn inter muzikaĵoj en senpaŭzaj albumoj, agordi ĉion kiel 0 (sed 'width' kiel 1), se vi volas nur tion",
"mt_drc": "ŝaltas kompresoron de dinamiko (glatigas laŭtecon de muzikaĵoj); ankaŭ ŝaltas ekvalizilon, do agordu ĉion (sed 'width') kiel 0, se vi ne volas ĝin; $N$Nplimalgrandigas laŭtecon de aŭdio super sojlo-valoro ('tresh') da dB; ĉiu proporcio-valoro ('ratio') da dB post 'tresh' 1 dB estos eligita, do implicitaj valoroj (tresh = -24, ratio = 12) faras, ke laŭteco neniam pli grandas ol -22 dB; tiel estas sendanĝera agordi 'boost'on kiel 0.8 aŭ eĉ 1.8 dum ATK = 0 kaj grandega RLS, kiel 90 (funkcias nur en Firefox, RLS estas maksimume 1 en aliaj retumiloj)$N$N(rigardu vikipedion, ĝi klariĝas pli bone)",
"mb_play": "ludi",
"mm_hashplay": "ludi ĉi tiun aŭdiodosieron?",
"mm_m3u": "premu <code>Enter/OK</code> por ludado \npremu <code>ESK/Rezigni</code> por redaktado",
"mp_breq": "bezonas Firefox 82+, Chrome 73+ aŭ iOS 15+",
"mm_bload": "ŝargado...",
"mm_bconv": "konvertado al formato {0}, bonvolu atendi...",
"mm_opusen": "via retumilo ne povas ludi dosierojn de formatoj aac / m4a;\ntranskodado al opus estas ŝaltigita",
"mm_playerr": "ludado malsukcesis: ",
"mm_eabrt": "Klopodo de ludado estis nuligita",
"mm_enet": "Via retkonekto estas nestabila",
"mm_edec": "Ĉi tiu dosiero estas ŝajne difektita??",
"mm_esupp": "Via retumilo ne komprenas ĉi tiun aŭdio-formaton",
"mm_eunk": "Nekonata eraro",
"mm_e404": "Ne povas ludi aŭdiaĵon; eraro 404: Dosiero ne trovita.",
"mm_e403": "Ne povas ludi aŭdiaĵon; eraro 403: Atingo malpermesita.\n\nKlopodu reŝargi paĝon per klavo F5, eble via seanco senvalidiĝis",
"mm_e500": "Ne povas ludi aŭdiaĵon; eraro 500: Rigardu la protokolojn de servilo.",
"mm_e5xx": "Ne povas ludi aŭdiaĵon; servila eraro ",
"mm_nof": "neniuj aŭdio-dosieroj trovitaj proksime",
"mm_prescan": "Serĉado por sekva aŭdiaĵo...",
"mm_scank": "Sekva muzikaĵo trovita:",
"mm_uncache": "kaŝmemoro malplenigita; ĉiuj muzikaĵoj estos reelŝutitaj dum sekva ludado",
"mm_hnf": "ĉi tiu muzikaĵo ne ekzistas plu",
"im_hnf": "ĉi tiu bildo ne ekzistas plu",
"f_empty": 'ĉi tiu dosierujo estas malplena',
"f_chide": 'ĉi tiu ago kaŝos kolumnon «{0}»\n\nvi povas malkaŝi kolumnojn en agordoj',
"f_bigtxt": "ĉi tiu dosiero estas {0}-MiB-granda -- ĉu vere malfermi kiel teksto?",
"f_bigtxt2": "ĉu malfermi nur la finon de dosiero? ĉi tiu reĝimo ankaŭ ŝaltos tujan ĝisdatigon, novaj linioj estos tuj montritaj",
"fbd_more": '<div id="blazy"><code>{0}</code> de <code>{1}</code> dosieroj montrataj; <a href="#" id="bd_more">montri {2}</a> aŭ <a href="#" id="bd_all">montri ĉiujn</a></div>',
"fbd_all": '<div id="blazy"><code>{0}</code> de <code>{1}</code> dosieroj montrataj; <a href="#" id="bd_all">montri ĉiujn</a></div>',
"f_anota": "nur {0} de {1} eroj estis elektita;\nrulumi al la malsupro por elekti la tutan dosierujon",
"f_dls": 'la ligiloj de dosieroj en ĉi tiu dosierujo estis\nanstataŭigitaj per elŝuto-ligiloj',
"f_partial": "Por sendifekta elŝuto de nune-alŝutata dosiero, elektu dosieron kun sama nomo, sed sen etendaĵo <code>.PARTIAL</code>. Bonvolu uzi la butonon \"Rezigni\" aŭ klavon ESK por fari tion.\n\nSe vi uzas OK / Enter, la provizora dosiero <code>.PARTIAL</code> estos elŝutita, kiu tre probable enhavas nekompletajn datumojn.",
"ft_paste": "alglui {0} erojn$NFulmoklavo: stir-V",
"fr_eperm": 'ne povas alinomi:\nvi ne havas permeson “move” en ĉi tiu dosierujo',
"fd_eperm": 'ne povas forigi:\nvi ne havas permeson “delete” en ĉi tiu dosierujo',
"fc_eperm": 'ne povas eltondi:\nvi ne havas permeson “move” en ĉi tiu dosierujo',
"fp_eperm": 'ne povas alglui:\nvi ne havas permeson “write” en ĉi tiu dosierujo',
"fr_emore": "elekti almenaŭ unu aĵon por alinomi",
"fd_emore": "elekti almenaŭ unu aĵon por forigi",
"fc_emore": "elekti almenaŭ unu aĵon por eltondi",
"fcp_emore": "elekti almenaŭ unu aĵon por kopii al tondujo",
"fs_sc": "kunhavigi la aktualan dosierujon",
"fs_ss": "kunhavigi la elektitajn dosierojn",
"fs_just1d": "vi ne povas elekti pli ol unu dosierujon\naŭ miksi dosierojn kaj dosierujojn en elektaĵo",
"fs_abrt": "❌ ĉesigi",
"fs_rand": "🎲 haz. nomo",
"fs_go": "✅ krei komunaĵon",
"fs_name": "nomo",
"fs_src": "indiko",
"fs_pwd": "pasvorto",
"fs_exp": "tempolimo",
"fs_tmin": "min",
"fs_thrs": "horoj",
"fs_tdays": "tagoj",
"fs_never": "eterna",
"fs_pname": "nomo de ligilo; estos hazarde kreita, se malplena",
"fs_tsrc": "dosier(uj)o por kunhavigi",
"fs_ppwd": "pasvorto (nedeviga)",
"fs_w8": "kreado de komunaĵo...",
"fs_ok": "premu <code>Enter/OK</code> por kopii al tondujo\npremu <code>ESK/Rezigni</code> por fermi",
"frt_dec": "povas ripari difektitajn dosiernomojn\">url-malkodo",
"frt_rst": "reagordi modifitajn dosiernomojn al originalaj\">↺ malfari",
"frt_abrt": "ĉesigi operacion kaj fermi ĉi tiun fenestron\">❌ rezigni",
"frb_apply": "ALINOMI",
"fr_adv": "amasa / metadatuma / ŝablona alinomado\">altnivela",
"fr_case": "uskleciva regula esprimo\">uskleco",
"fr_win": "Windows-taŭgaj nomoj; signoj <code>&lt;&gt;:&quot;\\|?*</code> estos anstataŭigitaj per japanaj duobla-larĝaj signoj\">win",
"fr_slash": "anstataŭigi <code>/</code>n per signo, kiu ne devigas kreadon de novaj dosierujoj\">sen /",
"fr_re": "ŝablono de regula esprimo, kiu estos aplikita al originalaj dosiernomoj; kaptogrupoj povas esti referencita en formatkampo, ekz. &lt;code&gt;(1)&lt;/code&gt;, &lt;code&gt;(2)&lt;/code&gt; k.t.p.",
"fr_fmt": "inspirita de foobar2000:$N&lt;code&gt;(title)&lt;/code&gt; anstataŭigitas per nomo de muzikaĵo,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; preterpasas [ĉi tiun] parton, se artisto ne estas specifita$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; aldonas nulojn en trakonombro ĝis 2 ciferoj",
"fr_pdel": "forigi",
"fr_pnew": "konservi kiel",
"fr_pname": "nomu vian novan ŝablonon",
"fr_aborted": "ĉesigita",
"fr_lold": "malnova nomo",
"fr_lnew": "nova nomo",
"fr_tags": "etikedoj por elektitaj dosieroj (ne redakteblas, nur por referenco):",
"fr_busy": "alinomado de {0} aĵoj...\n\n{1}",
"fr_efail": "alinomado malsukcesis:\n",
"fr_nchg": "{0} da novaj nomoj estis modifita pro reguloj <code>win</code> kaj/aŭ <code>sen /</code>\n\nĈu daŭrigi kun modifitaj nomoj?",
"fd_ok": "forigado sukcesis",
"fd_err": "forigado malsukcesis:\n",
"fd_none": "nenio estis forigita; eble servila eraro malpermesis ĝin (xbd)?",
"fd_busy": "forigado de {0} aĵoj...\n\n{1}",
"fd_warn1": "ĉu FORIGI ĉi tiujn {0} aĵojn?",
"fd_warn2": "<b>Averto!</b> Ĉi tiu ago ne malfareblas. Ĉu forigi?",
"fc_ok": "{0} aĵoj eltonditaj",
"fc_warn": '{0} aĵoj eltonditaj\n\nnur <b>ĉi tiu</b> langeto de retumilo povas alglui ilin\n(pro la grando de elektaĵo)',
"fcc_ok": "{0} aĵoj kopiitaj al tondujo",
"fcc_warn": '{0} aĵoj kopiitaj al tondujo\n\nnur <b>ĉi tiu</b> langeto de retumilo povas alglui ilin\n(pro la grando de elektaĵo)',
"fp_apply": "uzi ĉi tiujn nomojn",
"fp_skip": "preterpasi konfliktojn", //m
"fp_ecut": "unue eltondi aŭ kopii dosier(uj)ojn, do alglui ĝin poste\n\nnoto: tondujo ankaŭ funkcias inter aliaj langetoj de retumilo",
"fp_ename": "{0} aĵoj ne povas esti movitaj, ĉar iliaj nomoj estas jam uzataj. Alinomi ilin sube aŭ lasi la nomokampojn malplenaj (\"preterpasi konfliktojn\") por preterpasi:", //m
"fcp_ename": "{0} aĵoj ne povas esti kopiitaj, ĉar iliaj nomoj estas jam uzataj. Alinomi ilin sube aŭ lasi la nomokampojn malplenaj (\"preterpasi konfliktojn\") por preterpasi:", //m
"fp_emore": "ankoraŭ restas koincidoj de dosiernomoj, kiuj bezonas solvon",
"fp_ok": "movado sukcesis",
"fcp_ok": "kopiado sukcesis",
"fp_busy": "movado de {0} aĵoj...\n\n{1}",
"fcp_busy": "kopiado {0} aĵoj...\n\n{1}",
"fp_abrt": "ĉesigado...",
"fp_err": "movado malsukcesis:\n",
"fcp_err": "kopiado malsukcesis:\n",
"fp_confirm": "ĉu movi tiujn {0} aĵojn ĉi tien?",
"fcp_confirm": "ĉu kopii tiujn {0} aĵojn ĉi tien?",
"fp_etab": 'eraro dum legado de tondujo el alia langeto de retumilo',
"fp_name": "alŝutado de dosiero el via aparato. Nomi ĝin:",
"fp_both_m": '<h6>elektu, kion alglui</h6><code>Enter</code> = Movi {0} dosierojn al «{1}»\n<code>ESK</code> = Alŝuti {2} dosierojn el via aparato',
"fcp_both_m": '<h6>elektu, kion alglui</h6><code>Enter</code> = Kopii {0} dosierojn al «{1}»\n<code>ESK</code> = Alŝuti {2} dosierojn el via aparato',
"fp_both_b": '<a href="#" id="modal-ok">Movi</a><a href="#" id="modal-ng">Alŝuti</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Kopii</a><a href="#" id="modal-ng">Alŝuti</a>',
"mk_noname": "tajpu nomon en tekstokampo maldekstre antaŭ vi faras ĉi tion :p",
"nmd_i1": "vi povas aldoni la deziratan sufikson, ekzemple <code>.md</code>", //m
"nmd_i2": "vi povas krei nur <code>.md</code>-dosierojn ĉar vi ne havas forigan permeson", //m
"tv_load": "Ŝargado de teksto-dokumento:\n\n{0}\n\n{1}% ({2} da {3} MiB ŝargita)",
"tv_xe1": "ne povas ŝargi teksto-dosieron:\n\neraro ",
"tv_xe2": "404, dosiero ne trovita",
"tv_lst": "listo de teksto-dosieroj en",
"tvt_close": "reveni al vido de dosierujo$NFulmoklavo: M (aŭ Esk)\">❌ fermi",
"tvt_dl": "elŝuti ĉi tiun dosieron$NFulmoklavo: Y\">💾 elŝuti",
"tvt_prev": "montri malsekvan dokumenton$NFulmoklavo: i\">⬆ malsekva",
"tvt_next": "montri sekvan dokumenton$NFulmoklavo: K\">⬇ sekva",
"tvt_sel": "elekti dosieron &nbsp; ( por eltondado / kopiado / forigado / ... )$NFulmoklavo: S\">elekti",
"tvt_j": "beligi json$NFulmoklavo: shift-J\">j", //m
"tvt_edit": "malfermi dosieron en teksto-redaktilo$NFulmoklavo: E\">✏️ redakti",
"tvt_tail": "observi ŝanĝojn en dosiero; novaj linioj estos tuje montritaj\">📡 gvati",
"tvt_wrap": "linifaldo\">↵",
"tvt_atail": "alpingli rulumadon al malsupro de paĝo\">⚓",
"tvt_ctail": "malkodi ANSI-kodojn de terminal-koloroj\">🌈",
"tvt_ntail": "limo de rulumado (kiom da bajtoj de teksto konservi en memoro)",
"m3u_add1": "muzikaĵo aldonita al m3u-ludlisto",
"m3u_addn": "{0} muzikaĵoj aldonitaj al m3u-ludlisto",
"m3u_clip": "m3u-ludlisto kopiita al tondujo\n\nvi devus krei tekst-dosieron kun etendaĵo <code>.m3u</code> kaj alglui la tekston en ĝi por krei uzeblan ludliston",
"gt_vau": "ne montri videojn, nur ludi muzikaĵojn\">🎧",
"gt_msel": "ŝalti elektado-reĝimon; stir-klaki dosieron por ne-elekta ago$N$N&lt;em&gt;kiam ŝaltita: duoblaklako por malfermi dosier(uj)on&lt;/em&gt;$N$NFulmoklavo: S\">elektado",
"gt_crop": "stuci bildetojn\">stuci",
"gt_3x": "alt-kvalitaj bildetoj\">3x",
"gt_zoom": "grando",
"gt_chop": "nomlongo",
"gt_sort": "ordigi per",
"gt_name": "nomo",
"gt_sz": "grando",
"gt_ts": "dato",
"gt_ext": "tipo",
"gt_c1": "pli mallongaj dosiernomoj",
"gt_c2": "pli longaj dosiernomoj",
"sm_w8": "serĉado...",
"sm_prev": "serĉrezultoj sube venas al la lasta informpeto:\n ",
"sl_close": "fermi serĉrezultojn",
"sl_hits": "montrado de {0} kongruaĵoj",
"sl_moar": "ŝargi pli",
"s_sz": "grando",
"s_dt": "dato",
"s_rd": "vojo",
"s_fn": "nomo",
"s_ta": "etikedoj",
"s_ua": "alŝut📅",
"s_ad": "aliaj",
"s_s1": "minimuma MiB",
"s_s2": "maksimuma MiB",
"s_d1": "min. iso8601",
"s_d2": "maks. iso8601",
"s_u1": "alŝutita post",
"s_u2": "kaj/aŭ antaŭ",
"s_r1": "vojo enhavas &nbsp; (apartigi per spacoj)",
"s_f1": "nomo enhavas &nbsp; (negacii per minuso)",
"s_t1": "etikedoj enhavas &nbsp; (^=komenco, fino=$)",
"s_a1": "ecoj de metadatumoj",
"md_eshow": "ne povas montri ",
"md_off": "[📜<em>readme</em>] malŝaltita en [⚙️] -- dokumento kaŝita",
"badreply": "Eraro dum legado de respondo al servilo",
"xhr403": "403: Atingo malpermesita\n\nklopodu reŝargi paĝon per klavo F5, eble via seanco senvalidiĝis",
"xhr0": "nekonata (eble konekto al servilo estis perdita, aŭ servilo ne funkcias)",
"cf_ok": "pardonon -- DD" + wah + "oS-protekto aktiviĝis\n\nĉio devus esti bona 30 sekundoj post\n\nse nenio okazas, reŝargi per klavo F5",
"tl_xe1": "ne povas listigi subdosierujojn:\n\neraro ",
"tl_xe2": "404: Dosierujo ne trovita",
"fl_xe1": "ne povas listigi dosierojn en dosierujo:\n\neraro ",
"fl_xe2": "404: Dosierujo ne trovita",
"fd_xe1": "ne povas krei subdosierujon:\n\neraro ",
"fd_xe2": "404: Patra dosierujo ne trovita",
"fsm_xe1": "ne povas sendi mesaĝon:\n\neraro ",
"fsm_xe2": "404: Patra dosierujo ne trovita",
"fu_xe1": "ne povas ŝargi malsend-liston el servilo:\n\neraro ",
"fu_xe2": "404: Dosiero ne trovita??",
"fz_tar": "nedensigita dosiero GNU TAR (linux / mac)",
"fz_pax": "nedensigita PAX-formata dosiero TAR (malpli rapide)",
"fz_targz": "GNU TAR, densigita per 3a nivelo de GZip$N$Nkutime tre malrapida, do$Nuzu nedensigitan TARon anstataŭe",
"fz_tarxz": "GNU TAR, densigita per 1a nivelo de XZ$N$Nkutime tre malrapida, do$Nuzu nedensigitan TARon anstataŭe",
"fz_zip8": "Zip kun dosiernomoj laŭ UTF-8 (eble difektiĝis je Windows 7 kaj pli malnovaj)",
"fz_zipd": "Zip kun dosiernomoj laŭ CP437, por tre malnovaj programoj (esperantaj diakritaĵoj ne funkcios)",
"fz_zipc": "Zip, cp437, CRC-kontrolsumoj prekalkulitaj,$Npor MS-DOS PKZIP v2.04g (oktobro 1993)$N(bezonas pli da tempo antaŭ komenco de elŝuto)",
"un_m1": "vi povas forigi viajn lastajn alŝutojn (aŭ ĉesigi nefinigitajn) sube",
"un_upd": "reŝargi",
"un_m4": "aŭ kunhavigi la dosierojn sube:",
"un_ulist": "montri",
"un_ucopy": "kopii",
"un_flt": "nedeviga filtrilo:&nbsp; URL devas enhavi",
"un_fclr": "vakigi filtrilon",
"un_derr": 'malalŝutado malsukcesis:\n',
"un_f5": 'io difektiĝis, bonvolu reŝargi aŭ uzi klavon F5',
"un_uf5": "pardonu, sed vi devas reŝargi la paĝon (F5 aŭ Stir+R) antaŭ ĉesigi ĉi tiun alŝuton",
"un_nou": '<b>averto:</b> servilo estas tro okupara por montri nefinigitajn alŝutojn; klaku la butonon "reŝargi" post kelkaj sekundoj',
"un_noc": '<b>averto:</b> malalŝutado de tute alŝutitaj dosieroj estas malpermesita laŭ agordoj de servilo',
"un_max": "unuaj 2000 dosieroj montritaj (uzi filtrilon por vidi aliajn)",
"un_avail": "{0} lastaj alŝutoj forigeblas<br />{1} nefinigitajn ĉesigeblas",
"un_m2": "ordigita per alŝuto-tempo, plej lastaj unue:",
"un_no1": "neniuj sufiĉe lastaj alŝutoj",
"un_no2": "neniuj sufiĉe lastaj alŝutoj, kongruaj laŭ filtrilo",
"un_next": "forigi la sekvajn {0} dosierojn sube",
"un_abrt": "ĉesigi",
"un_del": "forigi",
"un_m3": "ŝargado de viaj lastaj alŝutoj...",
"un_busy": "forigado de {0} dosieroj...",
"un_clip": "{0} ligiloj kopiitaj al tondujo",
"u_https1": "vi devas",
"u_https2": "ŝalti HTTPS-protokolon",
"u_https3": "por pli bona rendimento",
"u_ancient": 'via retumilo estas vere antikva -- eble vi devus <a href="#" onclick="goto(\'bup\')">uzi alŝutilon bup anstataŭe</a>',
"u_nowork": "Firefox 53+ aŭ Chrome 57+ aŭ iOS 11+ necesas",
"tail_2old": "Firefox 105+ aŭ Chrome 71+ aŭ iOS 14.5+ necesas",
"u_nodrop": 'via retumilo estas tro malnova por ŝova-kaj-demeta alŝutado',
"u_notdir": "tio ne estas dosierujo!\n\nvia retumilo estas tro malnova,\nbonvolu ŝovu kaj demetu anstataŭe",
"u_uri": "por ŝovi-kaj-demeti bildon de aliaj fenestroj de retumiloj,\nbonvolu demeti ĝin sur la grandan alŝut-butonon",
"u_enpot": 'uzi <a href="#">simplan fasadon</a> (povas plirapidigi alŝutojn)',
"u_depot": 'uzi <a href="#">elegantan fasadon</a> (povas plimalrapidigi alŝutojn)',
"u_gotpot": 'ŝaltado de simpla fasado por pli rapidaj alŝutoj,\n\nvi povas malŝalti ĝin, se ĝi ne plaĉas al vi!',
"u_pott": "<p>dosieroj: &nbsp; <b>{0}</b> finitaj, &nbsp; <b>{1}</b> eraroj, &nbsp; <b>{2}</b> alŝutataj, &nbsp; <b>{3}</b> envicigitaj</p>",
"u_ever": "ĉi tiu estas fundamenta alŝutilo; up2k postulas almenaŭ retumilojn<br>Chrome 21 // Firefox 13 // Edge 12 // Opera 12 // Safari 5.1",
"u_su2k": 'ĉi tiu estas fundamenta alŝutilo; <a href="#" id="u2yea">up2k</a> estas pli bona',
"u_uput": 'optimumigi por rapideco (ne kalkuli kontrolsumojn)',
"u_ewrite": 'vi ne havas permeson skribi en ĉi tiun dosierujon',
"u_eread": 'vi ne havas permeson legi ĉi tiun dosierujon',
"u_enoi": 'serĉado de dosieroj estas malŝaltita en servilaj agordoj',
"u_enoow": "anstataŭigo ne funkcios ĉi tie; forigo-permeso necesas",
"u_badf": 'Ĉi tiuj {0} de {1} dosieroj estis preterpasitaj, eble pro permesoj de dosiersistemo:\n\n',
"u_blankf": 'Ĉi tiuj {0} de {1} dosieroj estas blankaj; ĉu alŝuti malgraŭ tio?\n\n',
"u_applef": 'Ĉi tiuj {0} de {1} dosieroj estas eble nedezirataj;\nPremu <code>OK/Enter</code> por PRETERPASI ilin,\nPremu <code>Rezigni/ESK</code> por ignori ĉi tiun mesaĝon kaj ALŜUTI ilin:\n\n',
"u_just1": '\nEble ĝi funkcios pli bone, se vi elektas nur unu dosieron',
"u_ff_many": "se vi uzas operaciumojn <b>Linux / MacOS / Android,</b> ĉi tiu kvanto de dosieroj <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>povas</em> kraŝi retumilon Firefox!</a>\nse ĉi tio okazos, klopodu denove (aŭ uzu Chrome-on).",
"u_up_life": "Ĉi tiu alŝuto estos forigita de servilo\n{0} post kompletado",
"u_asku": 'alŝuti ĉi tiujn {0} dosierojn al <code>{1}</code>',
"u_unpt": "vi povas malalŝuti / forigi ĉi tiun alŝuton per 🧯 supre-maldesktre",
"u_bigtab": '{0} dosieroj montrotaj\n\nĉi tiu povas kraŝi vian retumilon, ĉu daŭrigi?',
"u_scan": 'Skanado de dosieroj...',
"u_dirstuck": 'skanilo haltis dum atingado de sekvaj {0} dosieroj; ili estos preterpasitaj:',
"u_etadone": 'Finita ({0}, {1} dosieroj)',
"u_etaprep": '(preparado por alŝutado)',
"u_hashdone": 'kontrolsumita',
"u_hashing": 'k-sumado',
"u_hs": 'kvitanco...',
"u_started": "la dosieroj estas alŝutataj; rigardu [🚀]",
"u_dupdefer": "duplikatoj; estos traktita post ĉiuj aliaj dosieroj",
"u_actx": "alklaku ĉi tiun tekston por eviti malrapidigon<br />dum uzado de aliaj fenestroj/langetoj",
"u_fixed": "Bone!&nbsp; Riparita 👍",
"u_cuerr": "alŝutado de ero {0} de {1} malsukcesis;\neble malgravas, alŝutado daŭrigas\n\ndosiero: {2}",
"u_cuerr2": "servilo rifuzis alŝutadon (ero {0} de {1});\nprovos denove poste\n\ndosiero: {2}\n\neraro ",
"u_ehstmp": "reprovos poste; rigardu sube-dekstre",
"u_ehsfin": "servilo rifuzis peton por finigi alŝutadon; reprovado...",
"u_ehssrch": "servilo rifuzis peton por ŝerco; reprovado...",
"u_ehsinit": "servilo rifuzis peton por komenco de alŝutado; reprovado...",
"u_eneths": "reta eraro dum alŝutada kvitanco; reprovado...",
"u_enethd": "reta eraro dum kontrolo de ekzistado de cela dosiero; reprovado...",
"u_cbusy": "atendado, por ke la servilo estas atingebla post reta eraro...",
"u_ehsdf": "servilo ne havas sufiĉe da diskospaco!\n\nla alŝutado reprovos daŭre, okaze de iu liberigas\nsufiĉe da diskospaco",
"u_emtleak1": "ŝajnas, ke via retumilo likas memoron; \nbonvolu",
"u_emtleak2": ' <a href="{0}">uzi protokolon HTTPS (rekomendita)</a> aŭ ',
"u_emtleak3": ' ',
"u_emtleakc": 'provu fari tiel:\n<ul><li>reŝargu la paĝon per klavo <code>F5</code></li><li>, do malŝalti la butonon &nbsp;<code>mt</code>&nbsp; en la &nbsp;<code>⚙️ agordoj</code></li><li>kaj reprovu alŝuton</li></ul>Alŝuto estos pli malrapida, sed nenio fareblas.\nPardonon por la ĝenaĵo!\n\nPS: chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">korektis ĉi tion</a>',
"u_emtleakf": 'provu fari tiel:\n<ul><li>reŝargu la paĝon per klavo <code>F5</code></li><li>, do malŝalti la butonon &nbsp;<code>mt</code>&nbsp; en la &nbsp;<code>⚙️ agordoj</code></li><li>kaj reprovu alŝuton</li></ul>\nPS: firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">espereble korektos ĉi tion</a> baldaŭ',
"u_s404": "ne trovita ĉe la servilo",
"u_expl": "klarigi",
"u_maxconn": "plimulto da retumiloj ne permesas uzi pli ol 6, sed Firefox havas agordon <code>connections-per-server</code> en <code>about:config</code>, per kiu la limo ŝanĝeblas",
"u_tu": '<p class="warn">AVERTO: rapidega reĝimo ŝaltita, <span>&nbsp;kliento povas ne detekti kaj daŭrigi nefinigitajn alŝutojn; rigardu la ŝpruchelpilon de rapidega-butono</span></p>',
"u_ts": '<p class="warn">AVERTO: rapidega reĝimo ŝaltita, <span>&nbsp;serĉrezultoj povas esti eraraj; rigardu la ŝpruchelpilon de rapidega-butono</span></p>',
"u_turbo_c": "rapidega reĝimo estas malpermesita laŭ servilaj agordoj",
"u_turbo_g": "rapidega reĝimo estas malpermesita, ĉar vi\nne rajtas listigi dosierujojn en ĉi tiu datumportilo",
"u_life_cfg": 'aŭtoforigado post <input id="lifem" p="60" /> minutoj (aŭ <input id="lifeh" p="3600" /> horoj)',
"u_life_est": 'alŝuto estos forigita je <span id="lifew" tt="local time">---</span>',
"u_life_max": 'ĉi tiu dosierujo postulas \naŭtoforigadon de dosieroj post {0}',
"u_unp_ok": 'malalŝuto permesitas por {0}',
"u_unp_ng": 'malalŝuto NE estos permesita',
"ue_ro": 'via atingo de ĉi tiu dosierujo estas nur-lega\n\n',
"ue_nl": 'vi ne estas ensalutita',
"ue_la": 'vi estas ensalutita kiel "{0}"',
"ue_sr": 'vi estas en serĉo-reĝimo nun\n\nŝanĝi al alŝuto-reĝimo per lupeo-simbolo 🔎 (apude de la grandega SERĈO-butono), kaj provu alŝuti denove\n\npardonon',
"ue_ta": 'provu alŝuti denove, ĝi devus funkcii nun',
"ue_ab": "ĉi tiu dosiero estas jam alŝutata en alian dosierujon, tiu alŝutado devas esti finigita antaŭ alŝutado de la sama dosiero en alian lokon.\n\nVi povas ĉesigi la nunan alŝutadon per butonon 🧯 supre-maldekstre",
"ur_1uo": "OK: Dosiero sukcese alŝutita",
"ur_auo": "OK: Ĉiuj {0} dosieroj sukcese alŝutitaj",
"ur_1so": "OK: Dosiero trovita ĉe la servilo",
"ur_aso": "OK: Ĉiuj {0} dosieroj trovitaj ĉe la serviloj",
"ur_1un": "Alŝutado malsukcesis, pardonon",
"ur_aun": "Ĉiuj {0} alŝutadoj malsukcesis, pardonon",
"ur_1sn": "Dosiero estis NE trovita ĉe la servilo",
"ur_asn": "La {0} dosieroj estis NE trovitaj ĉe la servilo",
"ur_um": "Finita;\n{0} alŝutoj sukcesis,\n{1} alŝutoj malsukcesis, pardonon",
"ur_sm": "Finita;\n{0} dosieroj trovitaj ĉe la servilo,\n{1} dosieroj NE trovitaj ĉe la servilo",
"rc_opn": "malfermi", //m
"rc_ply": "Ludi", //m
"rc_pla": "Ludi kiel sonon", //m
"rc_txt": "malfermi en dosiera vidilo", //m
"rc_md": "malfermi en tekstredaktilo", //m
"rc_dl": "elŝuti", //m
"rc_zip": "elŝuti kiel arkivon", //m
"rc_del": "forigi", //m
"rc_cut": "eltondi", //m
"rc_cpy": "kopii", //m
"rc_pst": "alglui", //m
"rc_nfo": "nova dosierujo", //m
"rc_nfi": "nova dosiero", //m
"rc_sal": "elekti ĉion", //m
"rc_sin": "inversigi elekton", //m
"lang_set": "ĉu reŝargi paĝon por efektivigi lingvo-ŝanĝon?",
"splash": {
"a1": "reŝargi",
"b1": "sal, nekonatulo &nbsp; <small>(vi ne estas ensalutita)</small>",
"c1": "elsaluti",
"d1": "montru stakon",
"d2": "montras la staton de ĉiuj aktivaj fadenoj",
"e1": "reŝargi CFGon",
"e2": "reŝargas la agordo-dosierojn (kontoj/portiloj/portilo-flagoj),$Nkaj reskanas ĉiuj portiloj de ed2s$N$Nnoto: ĉiuj ŝanĝoj de ĝeneralaj agordoj postulas$Npostulas tutan restartigon por efektiviĝi",
"f1": "vi povas vidi:",
"g1": "vi povas alŝuti al:",
"cc1": "aliaĵoj:",
"h1": "malŝalti k304-on",
"i1": "ŝalti k304-on",
"j1": "k304 malkonektas vian klienton je ĉiu HTTP-eraro 304; tio povas eviti paraliziĝon dum uzado de difektitaj retperantoj (paĝoj subite ne ŝargiĝas), <em>sed</em> ĝi ankaŭ plimalrapidigas ĉion",
"k1": "rekomenci agordojn de kliento",
"l1": "ensaluti por pli da opcioj:",
"ls3": "ensaluti",
"lu4": "uzantnomo",
"lp4": "pasvorto",
"lo3": "ensaluti kiel “{0}” ĉie",
"lo2": "ĉi tiu finigos seancon en ĉiuj retumiloj",
"m1": "bonvenon denove,",
"n1": "404 ne trovita &nbsp;┐( ´ -`)┌",
"o1": 'aŭ eble vi ne havas rajton -- provu uzi pasvorton aŭ <a href="' + SR + '/?h">iri hejmen</a>',
"p1": "403 ne permesita &nbsp;~┻━┻",
"q1": 'uzu pasvorton aŭ <a href="' + SR + '/?h">iru hejmen</a>',
"r1": "hejmen",
".s1": "reskani",
"t1": "ago",
"u2": "tempo post lasta skribo (alŝuto / alinomado / ...) je servilo$N( upload / rename / ... )$N$N17d = 17 tagoj$N1h23 = 1 horo 23 minutoj$N4m56 = 4 minutoj 56 sekundoj",
"v1": "konekti",
"v2": "uzi ĉi tiun servilon kiel loka disko",
"w1": "uzi HTTPS-protokolon",
"x1": "ŝanĝi pasvorton",
"y1": "redakti komunaĵojn",
"z1": "malŝlosi ĉi tiun komunaĵon:",
"ta1": "entajpu novan pasvorton unue",
"ta2": "retajpu por konfirmi:",
"ta3": "tajpo-eraro; bonvolu provu denove",
"nop": "ERARO: Pasvorto ne povas esti malplena", //m
"nou": "ERARO: Uzantnomo kaj/aŭ pasvorto ne povas esti malplena", //m
"aa1": "aktivaj alŝutoj:",
"ab1": "malŝalti no304-on",
"ac1": "ŝalti no304-on",
"ad1": "no304 malŝaltas ĉiun kaŝmemoradon; provu ĉi tion, se k304 ne riparis la difektojn. Ĉi tiu agordo malŝparas multon da datumtrafiko!",
"ae1": "aktivaj elŝutoj:",
"af1": "montri lastajn alŝutojn",
"ag1": "montri kaŝmemoron de idp",
}
};

710
copyparty/web/tl/fin.js Normal file
View file

@ -0,0 +1,710 @@
// Rivut, jotka päättyvät //m, ovat varmentamattomia konekäännöksiä
Ls.fin = {
"tt": "Suomi",
"cols": {
"c": "toimintopainikkeet",
"dur": "kesto",
"q": "laatu / bittinopeus",
"Ac": "äänikoodekki",
"Vc": "videokoodekki",
"Fmt": "formaatti / säiliö",
"Ahash": "äänen tarkistussumma",
"Vhash": "videon tarkistussumma",
"Res": "resoluutio",
"T": "tiedostotyyppi",
"aq": "äänenlaatu / bittinopeus",
"vq": "kuvalaatu / bittinopeus",
"pixfmt": "alinäytteistys / pikselirakenne",
"resw": "horisontaalinen resoluutio",
"resh": "vertikaalinen resoluutio",
"chs": "äänikanavat",
"hz": "näytteenottotaajuus",
},
"hks": [
[
"misc",
["ESC", "sulje asioita"],
"file-manager",
["G", "vaihda lista/kuvanäkymään"],
["T", "vaihda pienoiskuviin/kuvakkeisiin"],
["⇧ A/D", "pienoiskuvien koko"],
["ctrl-K", "poista valitut"],
["ctrl-X", "siirrä valitut leikepöydälle"],
["ctrl-C", "kopioi valitut leikepöydälle"],
["ctrl-V", "siirrä tai kopioi tähän"],
["Y", "lataa valitut"],
["F2", "uudelleennimeä valitut"],
"file-list-sel",
["space", "vaihda tiedostonvalintatilaan"],
["↑/↓", "siirrä valintaosoitinta"],
["ctrl ↑/↓", "siirrä osoitinta ja näkymää"],
["⇧ ↑/↓", "valitse edellinen/seuraava tiedosto"],
["ctrl-A", "valitse kaikki tiedostot / hakemistot"],
], [
"navigation",
["B", "näytä linkkipolku"],
["I/K", "siirry edelliseen/seuraavaan hakemistoon"],
["M", "siirry ylähakemistoon/supista nykyinen hakemisto"],
["V", "näytä hakemistot/tekstitiedostot navigointipaneelissa"],
["A/D", "navigointipaneelin koko"],
], [
"audio-player",
["J/L", "edellinen/seuraava kappale"],
["U/O", "kelaa 10s taaksepäin/eteenpäin"],
["0..9", "siirry 0%..90%"],
["P", "toista/pysäytä kappale"],
["S", "valitse toistossa oleva kappale"],
["Y", "lataa kappale"],
], [
"image-viewer",
["J/L, ←/→", "edellinen/seuraava kuva"],
["Home/End", "ensimmäinen/viimeinen kuva"],
["F", "siirry koko näytön tilaan"],
["R", "kierrä myötäpäivään"],
["⇧ R", "kierrä vastapäivään"],
["S", "valitse kuva"],
["Y", "lataa kuva"],
], [
"video-player",
["U/O", "kelaa 10s taaksepäin/eteenpäin"],
["P/K/Space", "toista/pysäytä video"],
["C", "jatka toistoa seuraavaan videoon"],
["V", "toista uudelleen"],
["M", "vaimenna"],
["[ ja ]", "aseta videon uudelleentoistoväli"],
], [
"textfile-viewer",
["I/K", "edellinen/seuraava tiedosto"],
["M", "sulje tekstitiedosto"],
["E", "muokkaa tekstitiedostoa"],
["S", "valitse tiedosto (leikkausta/kopiointia/uudelleennimeämistä varten)"],
["Y", "lataa tekstitiedosto"], //m
["⇧ J", "kaunista json"], //m
]
],
"m_ok": "OK",
"m_ng": "Peruuta",
"enable": "Aktivoi",
"danger": "HUOMIO!",
"clipped": "kopioitu leikepöydälle",
"ht_s1": "sekunti",
"ht_s2": "sekuntia",
"ht_m1": "minuutti",
"ht_m2": "minuuttia",
"ht_h1": "tunti",
"ht_h2": "tuntia",
"ht_d1": "päivä",
"ht_d2": "päivää",
"ht_and": " ja ",
"goh": "hallintapaneeli",
"gop": 'viereinen hakemisto">edell',
"gou": 'ylempi hakemisto">ylös',
"gon": 'seuraava hakemisto">seur',
"logout": "Kirjaudu ulos ",
"login": "Kirjaudu sisään", //m
"access": " -oikeudet",
"ot_close": "sulje alavalikko",
"ot_search": "etsi tiedostoja ominaisuuksien, tiedostopolun tai -nimen, musiikkitägien tai näiden yhdistelmän perusteella$N$N&lt;code&gt;foo bar&lt;/code&gt; = täytyy sisältää sekä «foo» että «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = täytyy sisältää «foo» mutta ei «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = alkaa «yana» ja on «opus»-tiedosto$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = sisältää täsmälleen «try unite»$N$Npäivämäärän muoto on iso-8601, kuten$N&lt;code&gt;2009-12-31&lt;/code&gt; tai &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: poista viimeaikaiset tai keskeytä keskeneräiset lataukset",
"ot_bup": "bup: tiedostojen 'perus'lähetysohjelma, tukee jopa netscape 4.0",
"ot_mkdir": "mkdir: luo uusi hakemisto",
"ot_md": "new-file: luo uusi tekstitiedosto", //m
"ot_msg": "msg: lähetä viesti palvelinlokiin",
"ot_mp": "mediasoittimen asetukset",
"ot_cfg": "asetukset",
"ot_u2i": 'up2k: lähetä tiedostoja (vaatii write-oikeudet) tai vaihda hakutilaan nähdäksesi, ovatko tiedostot jo olemassa jossain päin palvelinta$N$Nlatauksia voi jatkaa, ne ovat monisäikeistettyjä, ja tiedostojen aikaleimat säilytetään; nuijii prosessoria enemmän kuin [🎈]&nbsp; (peruslatausohjelma)<br /><br />tiedostojen lähetyksen aikana tämä kuvake muuttuu kertoo lähetyksen edistymisestilanteen!',
"ot_u2w": 'up2k: lähetä tiedostoja jatkamistoiminnolla (voit sulkea selaimen ja vetää samat tiedostot selainikkunaan myöhemmin)$N$monisäikeistetty, ja tiedostojen aikaleimat säilyvät; nuijii prosessoria enemmän kuin [🎈]&nbsp; (peruslatausohjelma)<br /><br />tiedostojen lähetyksen aikana tämä kuvake muuttuu kertoo lähetyksen edistymisestilanteen!',
"ot_noie": 'Suosittelemme käyttämään uudempaa selainta.',
"ab_mkdir": "luo hakemisto",
"ab_mkdoc": "luo tekstitiedosto", //m
"ab_msg": "lähetä viesti palvelinlokiin",
"ay_path": "siirry hakemistoihin",
"ay_files": "siirry tiedostoihin",
"wt_ren": "uudelleennimeä valitut kohteet$NPikanäppäin: F2",
"wt_del": "poista valitut kohteet$NPikanäppäin: ctrl-K",
"wt_cut": "siirrä valitut kohteet leikepöydälle &lt;small&gt;(siirtääksesi ne muualle)&lt;/small&gt;$NPikanäppäin: ctrl-X",
"wt_cpy": "kopioi valitut kohteet leikepöydälle$N(liittääksesi ne muualle)$NPikanäppäin: ctrl-C",
"wt_pst": "liitä aiemmin leikatut / kopioidut valinnat$NPikanäppäin: ctrl-V",
"wt_selall": "valitse kaikki tiedostot$NPikanäppäin: ctrl-A (kun tiedosto on kohdistettu)",
"wt_selinv": "valitse vastakkaiset tiedostot",
"wt_zip1": "lataa tämä hakemisto pakattuna",
"wt_selzip": "lataa valitut kohteet pakattuna",
"wt_seldl": "lataa valitut kohteet paketoimatta$NPikanäppäin: Y",
"wt_npirc": "kopioi kappaletiedot IRC-muotoilulla",
"wt_nptxt": "kopioi kappaletiedot ilman muotoilua",
"wt_m3ua": "lisää m3u-soittolistaan (klikkaa <code>📻kopioi</code> myöhemmin)",
"wt_m3uc": "kopioi m3u-soittolista leikepöydälle",
"wt_grid": "vaihda kuva- ja listanäkymän välillä$NPikanäppäin: G",
"wt_prev": "edellinen kappale$NPikanäppäin: J",
"wt_play": "toista / pysäytä$NPikanäppäin: P",
"wt_next": "seuraava kappale$NPikanäppäin: L",
"ul_par": "rinnakkaislatausten lkm:",
"ut_rand": "satunnaisgeneroidut tiedostonimet",
"ut_u2ts": "kopioi viimeksi muokattu aikaleima$Ntiedostojärjestelmästäsi palvelimelle\">📅",
"ut_ow": "korvaa olemassa olevat tiedostot palvelimella?$N🛡: ei koskaan (luo sen sijaan uuden tiedostonimen)$N🕒: korvaa jos palvelintiedosto on vanhempi kuin omasi$N♻: korvaa aina jos tiedostot ovat erilaisia$N⏭: ohita kaikki olemassa olevat tiedostot ehdottomasti", //m
"ut_mt": "jatka muiden tiedostojen tiivisteiden laskemista latauksen aikana$N$Nkannattanee poistaa käytöstä, mikäli prosessori tai kovalevy on vanhempaa mallia",
"ut_ask": 'kysy vahvistusta ennen latauksen aloittamista">💭',
"ut_pot": "paranna latausnopeutta hitailla laitteilla$Nvähentämällä käyttöliittymän monimutkaisuutta",
"ut_srch": "lataamisen sijaan tarkista, ovatko tiedostot jo $N olemassa palvelimella (käy läpi kaikki hakemistot, joihin sinulla on read-oikeudet)",
"ut_par": "keskeytä lataukset asettamalla se nollaan$N$Nnosta, jos yhteytesi on hidas tai viive on suuri$N$Npidä se 1:ssä lähiverkossa tai jos palvelimen kovalevy on pullonkaula",
"ul_btn": "vedä tiedostoja / hakemistoja tähän<br>(tai klikkaa minua)",
"ul_btnu": "L Ä H E T Ä",
"ul_btns": "E T S I",
"ul_hash": "tiiviste",
"ul_send": "lähetä",
"ul_done": "valmis",
"ul_idle1": "ei latauksia jonossa",
"ut_etah": "keskimääräinen &lt;em&gt;tiivisteiden lasku&lt;/em&gt;nopeus ja arvioitu aika valmistumiseen",
"ut_etau": "keskimääräinen &lt;em&gt;lataus&lt;/em&gt;nopeus ja arvioitu aika valmistumiseen",
"ut_etat": "keskimääräinen &lt;em&gt;kokonais&lt;/em&gt;nopeus ja arvioitu aika valmistumiseen",
"uct_ok": "onnistui",
"uct_ng": "ei-hyvä: epäonnistui / hylätty / ei löydy",
"uct_done": "ok ja ng yhdistettynä",
"uct_bz": "laskee tiivisteitä tai lataa",
"uct_q": "tyhjäkäynnillä, odottaa",
"utl_name": "tiedostonimi",
"utl_ulist": "lista",
"utl_ucopy": "kopioi",
"utl_links": "linkit",
"utl_stat": "tila",
"utl_prog": "edistyminen",
// keep short:
"utl_404": "404",
"utl_err": "VIRHE",
"utl_oserr": "Käyttöjärjestelmävirhe",
"utl_found": "löytyi",
"utl_defer": "lykkää",
"utl_yolo": "YOLO",
"utl_done": "valmis",
"ul_flagblk": "tiedostot lisättiin jonoon</b><br>mutta toisen selainvälilehden up2k on kiireinen,<br>joten odotetaan sen valmistumista ensin",
"ul_btnlk": "palvelinkonfiguraatio on lukinnut tämän kytkimen tähän tilaan",
"udt_up": "Lataa",
"udt_srch": "Etsi",
"udt_drop": "pudota se tähän",
"u_nav_m": '<h6>selvä, mitäs sulla on?</h6><code>Enter</code> = Tiedostoja (yksi tai useampi)\n<code>ESC</code> = Yksi hakemisto (mukaan lukien alihakemistot)',
"u_nav_b": '<a href="#" id="modal-ok">Tiedostoja</a><a href="#" id="modal-ng">Yksi hakemisto</a>',
"cl_opts": "asetukset",
"cl_hfsz": "tiedostokoko", //m
"cl_themes": "teema",
"cl_langs": "kieli",
"cl_ziptype": "hakemiston pakkaustyyppi",
"cl_uopts": "up2k-kytkimet",
"cl_favico": "favicon",
"cl_bigdir": "suuret hakemistot",
"cl_hsort": "#sort",
"cl_keytype": "sävellajin notaatiotyyppi",
"cl_hiddenc": "piilotetut sarakkeet",
"cl_hidec": "piilota",
"cl_reset": "palauta",
"cl_hpick": "napauta sarakeotsikoita piilottaaksesi alla olevassa taulukossa",
"cl_hcancel": "sarakkeiden piilotus peruttu",
"cl_rcm": "hiiren oikean painikkeen valikko", //m
"ct_grid": '田 kuvanäkymä',
"ct_ttips": '◔ ◡ ◔"> vihjelaatikot',
"ct_thumb": 'valitse kuvakkeiden / pienoiskuvien välillä kuvanäkymässä $NPikanäppäin: T">🖼️ pienoiskuvat',
"ct_csel": 'käytä CTRL ja SHIFT tiedostojen valintaan kuvanäkymässä">valitse',
"ct_dl": 'pakota lataus (älä näytä upotettuna), kun tiedostoa napsautetaan">dl', //m
"ct_ihop": 'kun kuvakatselin suljetaan, vieritä alas viimeksi katsottuun tiedostoon">g⮯',
"ct_dots": 'näytä piilotetut tiedostot (jos palvelin sallii)">piilotiedostot',
"ct_qdel": 'kysy vahvistusta vain kerran tiedostoja poistaessa">qdel',
"ct_dir1st": 'lajittele hakemistot ennen tiedostoja">📁 ensin',
"ct_nsort": 'luonnollinen lajittelu (tiedostonimille jotka ovat numeroalkuisia)">nsort',
"ct_utc": 'näytä kaikki aikaleimat UTC-ajassa">UTC',
"ct_readme": 'näytä README.md hakemistolistauksissa">📜 readme',
"ct_idxh": 'näytä index.html hakemistolistan sijasta">htm',
"ct_sbars": 'näytä vierityspalkit">⟊',
"cut_umod": "jos tiedosto on jo olemassa palvelimella, päivitä palvelimen viimeksi muokattu aikaleima vastaamaan paikallista tiedostoasi (vaatii write- ja delete-oikeudet)\">re📅",
"cut_turbo": "yolo-painike -- et todennäköisesti halua ottaa tätä käyttöön:$N$Nkäytä tätä jos latasit valtavan määrän tiedostoja ja jouduit käynnistämään uudelleen jostain syystä, ja haluat jatkaa latausta välittömästi$N$Ntämä korvaa tiivistetarkistuksen yksinkertaisella <em>&quot;onko tällä sama tiedostokoko palvelimella?&quot;</em> joten jos tiedoston sisältö on erilainen sitä EI ladata$N$Nsinun pitäisi poistaa tämä käytöstä kun lataus on valmis, ja sitten &quot;ladata&quot; samat tiedostot uudelleen antaaksesi selaimesi varmistaa ne\">turbo",
"cut_datechk": "ei vaikutusta ellei turbo-painike ole käytössä$N$Nvähentää yolo-tekijää hieman; tarkistaa vastaavatko tiedostojen aikaleimat palvelimella omia$N$Npitäisi <em>teoriassa</em> napata useimmat keskeneräiset / vioittuneet lataukset, mutta ei ole korvike varmistuskierrokselle turbo poistettuna käytöstä jälkeenpäin\">päiväysvarmistin",
"cut_u2sz": "kunkin lähetyspalan koko (MiB:ssä); suuret arvot lentävät paremmin atlantin yli. kokeile pieniä arvoja erittäin heikoilla yhteyksillä",
"cut_flag": "varmista että vain yksi välilehti lataa kerrallaan $N -- muissa välilehdissä täytyy olla tämä käytössä myös $N -- vaikuttaa vain saman verkkotunnuksen välilehtiin",
"cut_az": "lähetä tiedostot aakkosjärjestyksessä, eikä pienin-tiedosto-ensiksi$N$Naakkosjärjestys voi tehdä helpommaksi silmäillä jos jokin meni vikaan palvelimella, mutta se tekee latauksesta hieman hitaamman kuitu- ja lähiverkossa",
"cut_nag": "käyttöjärjestelmäilmoitus kun lataus valmistuu$N(vain jos selain tai välilehti ei ole aktiivinen)",
"cut_sfx": "äänivaroitus kun lataus valmistuu$N(vain jos selain tai välilehti ei ole aktiivinen)",
"cut_mt": "monisäikeistä tiedostojen tiivistysarvojen laskeminen$N$Ntämä käyttää web-workereitä ja vaatii$Nenemmän RAM-muistia (jopa 512 MiB ekstraa)$N$Ntekee https:n 30% nopeammaksi, http:n 4.5x nopeammaksi\">mt",
"cut_wasm": "käytä wasm:ia selaimen sisäänrakennetun tiivistäjän sijaan; parantaa nopeutta chrome-pohjaisissa selaimissa mutta lisää prosessorikuormaa, ja monissa vanhemmissa chrome-versioissa on bugeja jotka saavat selaimen kuluttamaan kaiken RAM-muistin ja kaatumaan jos tämä on käytössä\">wasm",
"cft_text": "favicon-teksti (tyhjennä ja päivitä poistaaksesi käytöstä)",
"cft_fg": "edustaväri",
"cft_bg": "taustaväri",
"cdt_lim": "tiedostojen enimmäismäärä näytettäväksi hakemistossa",
"cdt_ask": "sivun lopussa, sen sijaan että lataa $Nautomaattisesti lisää tiedostoja, kysy mitä tehdä",
"cdt_hsort": "kuinka monta lajittelusääntöä (&lt;code&gt;,sorthref&lt;/code&gt;) sisällyttää media-URL:eihin. Tämän asettaminen nollaan jättää myös huomioimatta media-linkeissä sisällytetyt lajittelusäännöt kun napsautat niitä",
"cdt_ren": "ota käyttöön mukautettu valikko, tavallinen valikko on käytettävissä painamalla shift ja napsauttamalla oikealla", //m
"tt_entree": "näytä navigointipaneeli$NPikanäppäin: B",
"tt_detree": "näytä linkkipolku$NPikanäppäin: B",
"tt_visdir": "näytä valittu hakemisto",
"tt_ftree": "vaihda linkkipolku- / tekstitiedostonäkymään$NPikanäppäin: V",
"tt_pdock": "näytä ylähakemistot telakoitussa paneelissa ylhäällä",
"tt_dynt": "kasvata automaattisesti hakemistosyvyyden kasvaessa",
"tt_wrap": "rivitys",
"tt_hover": "paljasta ylivuotavat rivit leijutettaessa$N( rikkoo vierityksen ellei hiiri $N&nbsp; ole vasemmassa marginaalissa )",
"ml_pmode": "hakemiston lopussa...",
"ml_btns": "komennot",
"ml_tcode": "muunna nämä",
"ml_tcode2": "tähän muotoon",
"ml_tint": "sävy",
"ml_eq": "taajuuskorjain",
"ml_drc": "dynaaminen alueen kompressori",
"mt_loop": "toista samaa kappaletta\">🔁",
"mt_one": "lopeta yhden toiston jälkeen\">1⃣",
"mt_shuf": "aktivoi satunnaistoisto\">🔀",
"mt_aplay": "automaattitoisto jos linkissä jolla pääsit palvelimelle oli kappale-ID$N$Ntämän poistaminen käytöstä pysäyttää myös sivun URL:n päivittämisen kappale-ID:lla musiikkia toistettaessa, estääksesi automaattitoiston jos nämä asetukset menetetään mutta URL säilyy\">a▶",
"mt_preload": "aloita seuraavan kappaleen lataaminen lähellä loppua, mahdollistaen saumattoman toiston\">esilataus",
"mt_prescan": "siirry seuraavaan hakemistoon ennen viimeisen kappaleen$Nloppumista, pitäen verkkoselaimen tyytyväisenä$Njotta se ei pysäytä toistoa\">nav",
"mt_fullpre": "yritä esiladata koko kappale;$N✅ ota käyttöön <b>heikoilla</b> yhteyksillä,$N❌ <b>poista käytöstä</b> hitailla yhteyksillä\">esi+",
"mt_fau": "puhelimissa: estä musiikin pysähtyminen jos seuraava kappale ei esilataudu tarpeeksi nopeasti (voi aiheuttaa ongelmia kappaletietojen näyttämisessä)\">☕️",
"mt_waves": "aaltomuoto-hakupalkki:$Nnäytä äänenvahvuus selaimessa\">~s",
"mt_npclip": "näytä painikkeet parhaillaan soivan kappaleen leikepöydälle kopioimiseen\">/np",
"mt_m3u_c": "näytä painikkeet valittujen$Nkappaleiden kopioimiseen m3u8-soittolistana leikepöydälle\">📻",
"mt_octl": "käyttöjärjestelmäintegraatio (medianäppäimet / osd)\">os-ctl",
"mt_oseek": "salli haku käyttöjärjestelmäintegraation kautta$N$Nhuom: joissakin laitteissa (iPhonet),$Ntämä korvaa 'seuraava kappale' -painikkeen\">kelaus",
"mt_oscv": "näytä albumin kansi osd:ssä\">kansikuvat",
"mt_follow": "pidä soiva kappale näkyvissä\">🎯",
"mt_compact": "kompaktit säätimet\">⟎",
"mt_uncache": "tyhjennä välimuisti &nbsp;(kokeile tätä jos selaimesi välimuistissa on$Nrikkinäinen kopio kappaleesta)\">uncache",
"mt_mloop": "toista avoinna olevaa hakemistoa loputtomasti\">🔁 alkuun",
"mt_mnext": "lataa seuraava hakemisto ja jatka\">📂 seuraava",
"mt_mstop": "pysäytä toisto\">⏸ pysäytä",
"mt_cflac": "muunna flac / wav {0}-muotoon\">flac",
"mt_caac": "muunna aac / m4a {0}-muotoon\">aac",
"mt_coth": "muunna kaikki muut paitsi mp3 {0}-muotoon\">muut",
"mt_c2opus": "paras valinta pöytäkoneille, kannettaville, androidille\">opus",
"mt_c2owa": "opus-weba, iOS 17.5:lle ja uudemmille\">owa",
"mt_c2caf": "opus-caf, iOS 11:lle - 17:lle\">caf",
"mt_c2mp3": "käytä tätä erittäin vanhoissa laitteissa\">mp3",
"mt_c2flac": "paras äänenlaatu, mutta isot lataukset\">flac", //m
"mt_c2wav": "pakkaamaton toisto (vielä suurempi tiedosto)\">wav", //m
"mt_c2ok": "hienoa, hyvä valinta",
"mt_c2nd": "tuo ei ole suositeltu formaatti laitteellesi, mutta tee miten lystäät",
"mt_c2ng": "laitteesi ei näytä tukevan tätä formaattia, mutta yritetään nyt silti",
"mt_xowa": "iOS:ssä on bugeja jotka estävät taustatoiston tällä formaatilla; käytä caf:ia tai mp3:a sen sijaan",
"mt_tint": "taustan taso (0-100) liukupalkissa$Ntehden puskuroinnista vähemmän häiritsevän",
"mt_eq": "aktivoi taajuuskorjaimen ja vahvistussäätimen;$N$Nvahvistus &lt;code&gt;0&lt;/code&gt; = normaali 100% äänenvoimakkuus (muokkaamaton)$N$Nleveys &lt;code&gt;1 &nbsp;&lt;/code&gt; = normaali stereo (muokkaamaton)$Nleveys &lt;code&gt;0.5&lt;/code&gt; = 50% vasen-oikea ristisyöttö$Nleveys &lt;code&gt;0 &nbsp;&lt;/code&gt; = mono$N$Nvahvistus &lt;code&gt;-0.8&lt;/code&gt; &amp; leveys &lt;code&gt;10&lt;/code&gt; = laulun poisto :^)$N$Nequalizerin käyttöönotto tekee saumattomista albumeista täysin saumattomia, joten jätä se päälle kaikilla arvoilla nollassa (paitsi leveys = 1) jos välität siitä",
"mt_drc": "aktivoi dynaamisen alueen kompressorin; ottaa myös käyttöön taajuuskorjaimen tasapainottamaan spagettia, joten aseta kaikki EQ-kentät paitsi 'leveys' nollaan jos et halua sitä$N$Nalentaa äänenvoimakkuutta KYNNYS dB:n yläpuolella; jokaisesta SUHDE dB:stä KYNNYKSEN yli tulee 1 dB ulos, joten oletusarvot kynnys -24 ja suhde 12 tarkoittaa ettei sen pitäisi koskaan tulla kovempaa kuin -22 dB ja on turvallista nostaa equalizerin vahvistus 0.8:aan, tai jopa 1.8:aan ATK 0:lla ja valtavalla RLS:llä kuten 90 (toimii vain firefoxissa; RLS on max 1 muissa selaimissa)$N$N(katso wikipedia, he selittävät sen paljon paremmin)",
"mb_play": "toista",
"mm_hashplay": "soita tämä äänitiedosto?",
"mm_m3u": "paina <code>Enter/OK</code> Toistaaksesi\npaina <code>ESC/Peruuta</code> Muokataksesi",
"mp_breq": "tarvitset firefox 82+ tai chrome 73+ tai iOS 15+",
"mm_bload": "ladataan...",
"mm_bconv": "muunnetaan muotoon {0}, odota...",
"mm_opusen": "selaimesi ei voi toistaa aac / m4a -tiedostoja;\ntranskoodaus opukseen on nyt käytössä",
"mm_playerr": "toisto epäonnistui: ",
"mm_eabrt": "Toistoyritys peruttiin",
"mm_enet": "Internet-yhteytesi on epävakaa",
"mm_edec": "Tämä tiedosto on väitetysti vioittunut??",
"mm_esupp": "Selaimesi ei ymmärrä tätä äänimuotoa",
"mm_eunk": "Tuntematon virhe",
"mm_e404": "Kappaletta ei voitu toistaa; virhe 404: Tiedostoa ei löydy.",
"mm_e403": "Kappaletta ei voitu toistaa; virhe 403: Pääsy kielletty.\n\nKokeile painaa F5 päivittääksesi, ehkä kirjauduit ulos",
"mm_e500": "Kappaletta ei voitu toistaa; virhe 500: Tarkista palvelinlokit.",
"mm_e5xx": "Kappaletta ei voitu toistaa; palvelinvirhe ",
"mm_nof": "ei löydy enempää äänitiedostoja lähistöltä",
"mm_prescan": "Etsitään musiikkia toistettavaksi seuraavaksi...",
"mm_scank": "Löytyi seuraava kappale:",
"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",
"f_empty": 'tämä hakemisto on tyhjä',
"f_chide": 'tämä piilottaa sarakkeen «{0}»\n\nvoit palauttaa sarakkeet asetuksista',
"f_bigtxt": "tämä tiedosto on {0} Mt kokoinen -- näytetäänkö silti tekstinä?",
"f_bigtxt2": "näytetäänkö vain tiedoston loppu? tämä myös mahdollistaa seuraamisen/tailing, näyttäen uudet tekstirivit reaaliaikaisesti",
"fbd_more": '<div id="blazy">näytetään <code>{0}</code> / <code>{1}</code> tiedostoa; <a href="#" id="bd_more">näytä {2}</a> tai <a href="#" id="bd_all">näytä kaikki</a></div>',
"fbd_all": '<div id="blazy">näytetään <code>{0}</code> / <code>{1}</code> tiedostoa; <a href="#" id="bd_all">näytä kaikki</a></div>',
"f_anota": "vain {0} / {1} kohdetta valittiin;\nvalitaksesi koko hakemiston, vieritä ensin loppuun",
"f_dls": 'nykyisen hakemiston tiedostolinkit on\nvaihdettu latauslinkeiksi',
"f_partial": "Ladataksesi turvallisesti tiedoston joka on parhaillaan latautumassa, klikkaa tiedostoa jolla on sama nimi mutta ilman <code>.PARTIAL</code> päätettä. Paina PERUUTA tai Escape tehdäksesi tämän.\n\nOK / Enter painaminen sivuuttaa tämän varoituksen ja jatkaa <code>.PARTIAL</code> väliaikaistiedoston lataamista, mikä todennäköisesti antaa sinulle vioittunutta dataa.",
"ft_paste": "liitä {0} kohdetta$NPikanäppäin: ctrl-V",
"fr_eperm": 'ei voida nimetä uudelleen:\nsinulla ei ole “move”-oikeutta tässä hakemistossa',
"fd_eperm": 'ei voida poistaa:\nsinulla ei ole “delete” oikeutta tässä hakemistossa',
"fc_eperm": 'ei voida leikata:\nsinulla ei ole “move” oikeutta tässä hakemistossa',
"fp_eperm": 'ei voida liittää:\nsinulla ei ole “write” oikeutta tässä hakemistossa',
"fr_emore": "valitse vähintään yksi kohde uudelleennimettäväksi",
"fd_emore": "valitse vähintään yksi kohde poistettavaksi",
"fc_emore": "valitse vähintään yksi kohde leikattavaksi",
"fcp_emore": "valitse vähintään yksi kohde kopioitavaksi leikepöydälle",
"fs_sc": "jaa hakemisto jossa olet",
"fs_ss": "jaa valitut tiedostot",
"fs_just1d": "et voi valita useampaa kuin yhtä,\ntai sekoittaa tiedostoja ja hakemistoja yhdessä valinnassa",
"fs_abrt": "❌ keskeytä",
"fs_rand": "🎲 joku.nimi",
"fs_go": "✅ luo share",
"fs_name": "nimi",
"fs_src": "lähde",
"fs_pwd": "salasana",
"fs_exp": "vanheneminen",
"fs_tmin": "min",
"fs_thrs": "tuntia",
"fs_tdays": "päivää",
"fs_never": "ikuinen",
"fs_pname": "valinnainen linkin nimi; on satunnainen jos tyhjä",
"fs_tsrc": "jaettava tiedosto tai hakemisto",
"fs_ppwd": "valinnainen salasana",
"fs_w8": "luodaan sharea...",
"fs_ok": "paina <code>Enter/OK</code> lisätäksesi leikepöydälle\npaina <code>ESC/Peruuta</code> sulkeaksesi",
"frt_dec": "saattaa korjata joitakin rikkinäisiä tiedostonimiä\">url-decode",
"frt_rst": "palauta muokatut tiedostonimet takaisin alkuperäisiksi\">↺ palauta",
"frt_abrt": "keskeytä ja sulje tämä ikkuna\">❌ peruuta",
"frb_apply": "UUDELLEENNIMEÄ",
"fr_adv": "erä / liitännäistiedot / kaava uudelleennimeäminen\">lisäasetukset",
"fr_case": "isot ja pienet kirjaimet erottava regex\">kirjainkoko",
"fr_win": "windows-yhteensopivat nimet; korvaa <code>&lt;&gt;:&quot;\\|?*</code> japanilaisilla leveillä merkeillä\">win",
"fr_slash": "korvaa <code>/</code> merkillä joka ei aiheuta uusien hakemistoiden luomista\">ei /",
"fr_re": "regex hakukuvio jota käytetään alkuperäisiin tiedostonimiin; kaappausryhmiin voi viitata alla olevassa muotoilukentässä kuten &lt;code&gt;(1)&lt;/code&gt; ja &lt;code&gt;(2)&lt;/code&gt; ja niin edelleen",
"fr_fmt": "foobar2000 innoittama:$N&lt;code&gt;(title)&lt;/code&gt; korvataan kappaleen nimellä,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; sivuuttaa [tämän] osan jos artisti on tyhjä$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; ",
"fr_pdel": "poista",
"fr_pnew": "tallenna nimellä",
"fr_pname": "anna nimi uudelle esiasetuksellesi",
"fr_aborted": "keskeytetty",
"fr_lold": "vanha nimi",
"fr_lnew": "uusi nimi",
"fr_tags": "valittujen tiedostojen tagit (vain luku, viitetarkoituksiin):",
"fr_busy": "nimetään uudelleen {0} kohdetta...\n\n{1}",
"fr_efail": "uudelleennimeäminen epäonnistui:\n",
"fr_nchg": "{0} uusista nimistä muutettiin <code>win</code> ja/tai <code>ei /</code> vuoksi\n\nJatketaanko näillä muutetuilla uusilla nimillä?",
"fd_ok": "poisto OK",
"fd_err": "poisto epäonnistui:\n",
"fd_none": "mitään ei poistettu; ehkä palvelimen asetukset estivät (xbd)?",
"fd_busy": "poistetaan {0} kohdetta...\n\n{1}",
"fd_warn1": "POISTA nämä {0} kohdetta?",
"fd_warn2": "<b>Viimeinen varoitus!</b> Haluatko varmasti poistaa?",
"fc_ok": "siirettiin {0} kohdetta leikepöydälle",
"fc_warn": 'siirettiin {0} kohdetta leikepöydälle\n\nmutta: vain <b>tämä</b> selain-välilehti voi liittää ne\n(koska valinta on niin valtavan suuri)',
"fcc_ok": "kopioitiin {0} kohdetta leikepöydälle",
"fcc_warn": 'kopioitiin {0} kohdetta leikepöydälle\n\nmutta: vain <b>tämä</b> selain-välilehti voi liittää ne\n(koska valinta on niin valtavan suuri)',
"fp_apply": "käytä näitä nimiä",
"fp_skip": "ohita ristiriidat", //m
"fp_ecut": "leikkaa tai kopioi ensin joitakin tiedostoja / hakemistoja liitettäväksi / siirrettäväksi\n\nhuom: voit leikata / liittää eri selain-välilehtien välillä",
"fp_ename": "{0} kohdetta ei voida siirtää tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriidat\") ohittaaksesi ne:", //m
"fcp_ename": "{0} kohdetta ei voida kopioida tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriidat\") ohittaaksesi ne:", //m
"fp_emore": "tiedostonimien törmäyksiä on vielä korjaamatta",
"fp_ok": "siirto OK",
"fcp_ok": "kopiointi OK",
"fp_busy": "siirretään {0} kohdetta...\n\n{1}",
"fcp_busy": "kopioidaan {0} kohdetta...\n\n{1}",
"fp_abrt": "keskeytetään...", //m
"fp_err": "siirto epäonnistui:\n",
"fcp_err": "kopiointi epäonnistui:\n",
"fp_confirm": "siirrä nämä {0} kohdetta tänne?",
"fcp_confirm": "kopioi nämä {0} kohdetta tänne?",
"fp_etab": 'leikepöydän lukeminen toisesta selain-välilehdestä epäonnistui',
"fp_name": "ladataan tiedostoa laitteeltasi. Anna sille nimi:",
"fp_both_m": '<h6>valitse mitä liittää</h6><code>Enter</code> = Siirrä {0} tiedostoa kohteesta «{1}»\n<code>ESC</code> = Lataa {2} tiedostoa laitteeltasi',
"fcp_both_m": '<h6>valitse mitä liittää</h6><code>Enter</code> = Kopioi {0} tiedostoa kohteesta «{1}»\n<code>ESC</code> = Lataa {2} tiedostoa laitteeltasi',
"fp_both_b": '<a href="#" id="modal-ok">Siirrä</a><a href="#" id="modal-ng">Lähetä</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Kopioi</a><a href="#" id="modal-ng">Lähetä</a>',
"mk_noname": "kirjoita nimi vasemmalla olevaan tekstikenttään ennen kuin teet tuon :p",
"nmd_i1": "voit myös lisätä haluamasi tiedostopäätteen, esimerkiksi <code>.md</code>", //m
"nmd_i2": "voit luoda vain <code>.md</code>-tiedostoja, koska sinulla ei ole poistolupaa", //m
"tv_load": "Ladataan tekstidokumenttia:\n\n{0}\n\n{1}% ({2} / {3} Mt ladattu)",
"tv_xe1": "tekstitiedoston lataaminen epäonnistui:\n\nvirhe ",
"tv_xe2": "404, tiedostoa ei löydy",
"tv_lst": "tekstitiedostojen lista hakemistossa",
"tvt_close": "palaa hakemistonäkymään$NPikanäppäin: M (tai Esc)\">❌ sulje",
"tvt_dl": "lataa tämä tiedosto$NPikanäppäin: Y\">💾 lataa",
"tvt_prev": "näytä edellinen dokumentti$NPikanäppäin: i\">⬆ edell",
"tvt_next": "näytä seuraava dokumentti$NPikanäppäin: K\">⬇ seur",
"tvt_sel": "valitse tiedosto &nbsp; ( leikkausta / kopiointia / poistoa / ... varten )$NPikanäppäin: S\">val",
"tvt_j": "kaunista json$NPikanäppäin: shift-J\">j", //m
"tvt_edit": "avaa tiedosto tekstieditorissa$NPikanäppäin: E\">✏️ muokkaa",
"tvt_tail": "seuraa tiedoston muutoksia; näytä uudet rivit reaaliaikaisesti\">📡 seuraa",
"tvt_wrap": "rivitys\">↵",
"tvt_atail": "lukitse vieritys sivun alaosaan\">⚓",
"tvt_ctail": "dekoodaa terminaalin värit (ansi escape koodit)\">🌈",
"tvt_ntail": "vieritysbufferin raja (kuinka monta tavua tekstiä pidetään ladattuna)",
"m3u_add1": "kappale lisätty m3u soittolistaan",
"m3u_addn": "{0} kappaletta lisätty m3u soittolistaan",
"m3u_clip": "m3u soittolista nyt kopioitu leikepöydälle\n\nsinun tulisi luoda uusi tekstitiedosto nimeltä jotain.m3u ja liittää soittolista siihen dokumenttiin; tämä tekee siitä soitettavan",
"gt_vau": "älä näytä videoita, toista vain ääni\">🎧",
"gt_msel": "aktivoi tiedostonvalintatila; ctrl-klikkaa ohittaaksesi valitsemisen väliaikaisesti$N$N&lt;em&gt;tuplaklikkaa tiedostoa / hakemistoa avataksesi sen&lt;/em&gt;$N$NPikanäppäin: S\">valitsin",
"gt_crop": "rajaa pienoiskuvat keskeltä\">rajaa",
"gt_3x": "korkearesoluutioiset pienoiskuvat\">3x",
"gt_zoom": "zoomaa",
"gt_chop": "pilko",
"gt_sort": "järjestä",
"gt_name": "nimi",
"gt_sz": "koko",
"gt_ts": "päiväys",
"gt_ext": "tyyppi",
"gt_c1": "rajaa tiedostonimiä enemmän (näytä vähemmän)",
"gt_c2": "rajaa tiedostonimiä vähemmän (näytä enemmän)",
"sm_w8": "haetaan...",
"sm_prev": "alla olevat hakutulokset ovat edellisestä hausta:\n ",
"sl_close": "sulje hakutulokset",
"sl_hits": "näytetään {0} osumaa",
"sl_moar": "lataa lisää",
"s_sz": "koko",
"s_dt": "päiväys",
"s_rd": "polku",
"s_fn": "nimi",
"s_ta": "tagit",
"s_ua": "ylös@",
"s_ad": "edist.",
"s_s1": "minimi Mt",
"s_s2": "maksimi Mt",
"s_d1": "min. iso8601",
"s_d2": "maks. iso8601",
"s_u1": "ladattu jälkeen",
"s_u2": "ja/tai ennen",
"s_r1": "polku sisältää &nbsp; (välilyönnillä erotetuttuina)",
"s_f1": "nimi sisältää &nbsp; (negatoi käyttämällä -nope)",
"s_t1": "tagit sisältää &nbsp; (^=alku, loppu=$)",
"s_a1": "tietyt metadatan ominaisuudet",
"md_eshow": "ei voida renderoida ",
"md_off": "[📜<em>readme</em>] poistettu käytöstä [⚙️] -- dokumentti piilotettu",
"badreply": "Palvelimen vastauksen jäsentäminen epäonnistui.",
"xhr403": "403: Pääsy kielletty\n\nkokeile painaa F5, ehkä sinut kirjattiin ulos",
"xhr0": "tuntematon (todennäköisesti yhteys palvelimeen katosi, tai palvelin on pois päältä)",
"cf_ok": "sori siitä -- DD" + wah + "oS suojaus aktivoitui\n\nasioiden pitäisi jatkua noin 30 sekunnissa\n\njos mitään ei tapahdu, paina F5 ladataksesi sivun uudelleen",
"tl_xe1": "alihakemistojen listaaminen epäonnistui:\n\nvirhe ",
"tl_xe2": "404: hakemistoa ei löydy",
"fl_xe1": "hakemiston tiedostojen listaaminen epäonnistui:\n\nvirhe ",
"fl_xe2": "404: hakemistoa ei löydy",
"fd_xe1": "alihakemiston luominen epäonnistui:\n\nvirhe ",
"fd_xe2": "404: Ylähakemistoa ei löydy",
"fsm_xe1": "viestin lähettäminen epäonnistui:\n\nvirhe ",
"fsm_xe2": "404: Ylähakemistoa ei löydy",
"fu_xe1": "unpost-listan lataaminen palvelimelta epäonnistui:\n\nvirhe ",
"fu_xe2": "404: Tiedostoa ei löydy??",
"fz_tar": "pakkaamaton gnu-tar tiedosto (linux / mac)",
"fz_pax": "pakkaamaton pax-formaatin tar (hitaampi)",
"fz_targz": "gnu-tar gzip tason 3 pakkauksella$N$Nyleensä hyvin hidas, $Nkäytä pakkamatonta tar:ia tämän sijasta",
"fz_tarxz": "gnu-tar xz tason 1 pakkauksella$N$Nyleensä hyvin hidas, $Nkäytä pakkamatonta tar:ia tämän sijasta",
"fz_zip8": "zip utf8-tiedostonimillä (suattaapi olla epävakaa windows 7:ssa ja vanhemmissa)",
"fz_zipd": "zip perinteisillä cp437 tiedostonimillä esihistoriallisille ohjelmistoille",
"fz_zipc": "cp437, jossa crc32 laskettu aikaisin,$NMS-DOS PKZIP v2.04g:lle (lokakuu 1993)$N(kestää kauemmin käsitellä ennen latauksen alkua)",
"un_m1": "voit poistaa tuoreet tai keskeyttää keskeneräiset latauksesi alta",
"un_upd": "päivitä",
"un_m4": "tai jakaa alla näkyvät tiedostot:",
"un_ulist": "näytä",
"un_ucopy": "kopioi",
"un_flt": "valinnainen suodatin:&nbsp; URL:n täytyy sisältää",
"un_fclr": "tyhjennä suodatin",
"un_derr": 'unpost-poisto epäonnistui:\n',
"un_f5": 'jotain hajosi, kokeile päivitystä tai paina F5',
"un_uf5": "pahoittelen mutta sinun täytyy päivittää sivu (esimerkiksi painamalla F5 tai CTRL-R) ennen kuin tämä lataus voidaan keskeyttää",
"un_nou": '<b>huom!</b> palvelin liian kiireinen näyttääkseen keskeneräiset lataukset; klikkaa "päivitä" linkkiä hetken kuluttua',
"un_noc": '<b>huom!</b> täysin ladattujen tiedostojen unpost ei ole käytössä/sallittu palvelimen asetuksissa',
"un_max": "näytetään ensimmäiset 2000 tiedostoa (käytä suodatinta)",
"un_avail": "{0} viimeaikaista latausta voidaan poistaa<br />{1} keskeneräistä voidaan keskeyttää",
"un_m2": "järjestetty latausajan mukaan; viimeisimmät ensin:",
"un_no1": "hupsis! yksikään lataus ei ole riittävän tuore",
"un_no2": "hupsis! yksikään tuota suodatinta vastaava lataus ei ole riittävän tuore",
"un_next": "poista seuraavat {0} tiedostoa alla",
"un_abrt": "keskeytä",
"un_del": "poista",
"un_m3": "ladataan viimeaikana lähettämiäsi tiedostoja...",
"un_busy": "poistetaan {0} tiedostoa...",
"un_clip": "{0} linkkiä kopioitu leikepöydälle",
"u_https1": "sinun kannattaisi",
"u_https2": "vaihtaa https:ään",
"u_https3": "paremman suorituskyvyn vuoksi",
"u_ancient": 'selaimesi on ns. vaikuttavan ikivanha -- kannattais varmaan <a href="#" onclick="goto(\'bup\')">käyttää bup:ia tän sijaan</a>',
"u_nowork": "tarvitaan firefox 53+ tai chrome 57+ tai iOS 11+",
"tail_2old": "tarvitaan firefox 105+ tai chrome 71+ tai iOS 14.5+",
"u_nodrop": 'selaimesi on liian vanha vedä-ja-pudota lataamiseen',
"u_notdir": "tuo ei ole hakemisto!\n\nselaimesi on liian vanha,\nkokeile sen sijaan 'vedä-pudota'-tekniikkaa.",
"u_uri": "'vedä-pudottaaksesi' kuvia muista selainikkunoista,\npudota se isoon latausnapppiin",
"u_enpot": 'vaihda <a href="#">peruna UI:hin</a> (voi parantaa latausnopeutta)',
"u_depot": 'vaihda <a href="#">ylelliseen UI:hin</a> (voi vähentää latausnopeutta)',
"u_gotpot": 'vaihdetaan peruna UI:hin paremman latausnopeuden vuoksi,\n\ntee miten lystäät, jos ei kelpaa!',
"u_pott": "<p>tiedostot: &nbsp; <b>{0}</b> valmis, &nbsp; <b>{1}</b> epäonnistui, &nbsp; <b>{2}</b> kiireinen, &nbsp; <b>{3}</b> jonossa</p>",
"u_ever": "tämä on peruslatain; up2k tarvitsee vähintään<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
"u_su2k": 'peruslatain; <a href="#" id="u2yea">up2k</a> on parempi',
"u_uput": 'optimoi latausnopeus (älä laske tarkistussummia)',
"u_ewrite": 'sinulla ei ole move-oikeutta tähän hakemistoon',
"u_eread": 'sinulla ei ole read-oikeutta tähän hakemistoon',
"u_enoi": 'tiedostohaku ei ole käytössä palvelimen asetuksissa',
"u_enoow": "ylikirjoitus ei toimi täällä; tarvitaan “Delete”-oikeus",
"u_badf": 'Nämä {0} tiedostoa ({1} yhteensä) ohitettiin, mahdollisesti tiedostojärjestelmän oikeuksien vuoksi:\n\n',
"u_blankf": 'Nämä {0} tiedostoa ({1} yhteensä) ovat tyhjiä; ladataanko ne silti?\n\n',
"u_applef": 'Nämä {0} tiedostoa ({1} yhteensä) ovat todennäköisesti ei-toivottuja;\nPaina <code>OK/Enter</code> OHITTAAKSESI seuraavat tiedostot,\nPaina <code>Peruuta/ESC</code> jos ET halua sulkea pois, ja LATAA nekin:\n\n',
"u_just1": '\nEhkä toimii paremmin jos valitset vain yhden tiedoston',
"u_ff_many": "jos käytät <b>Linux / MacOS / Android,</b> niin tämä määrä tiedostoja <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>saattaa</em> kaataa Firefoxin!</a>\njos niin käy, kokeile uudelleen (tai käytä Chromea).",
"u_up_life": "Tämä lataus poistetaan palvelimelta\n{0} sen valmistumisen jälkeen",
"u_asku": 'lataa nämä {0} tiedostoa kohteeseen <code>{1}</code>',
"u_unpt": "voit perua / poistaa tämän latauksen käyttämällä vasemmalla ylhäällä olevaa 🧯",
"u_bigtab": 'näytetään {0} tiedostoa\n\ntämä voi kaataa selaimesi, oletko varma?',
"u_scan": 'Skannataan tiedostoja...',
"u_dirstuck": 'hakemistoiteraattori jumittui yrittäessään käyttää seuraavia {0} kohdetta; ohitetaan:',
"u_etadone": 'Valmis ({0}, {1} tiedostoa)',
"u_etaprep": '(valmistellaan latausta)',
"u_hashdone": 'hajautus valmis',
"u_hashing": 'hajautus',
"u_hs": 'kätellään...',
"u_started": "tiedostoja ladataan nyt; tsekkaa [🚀]",
"u_dupdefer": "duplikaatti; käsitellään kaikkien muiden tiedostojen jälkeen",
"u_actx": "klikkaa tätä tekstiä estääksesi suorituskyvyn<br />heikkenemisen vaihtaessasi muihin ikkunoihin/välilehtiin",
"u_fixed": "OK!&nbsp; Hommat hoidossa 👍",
"u_cuerr": "chunk {0} / {1} lataus epäonnistui;\ntuskin haittaa, jatketaan\n\ntiedosto: {2}",
"u_cuerr2": "palvelin hylkäsi latauksen (chunk {0} / {1});\nyritetään myöhemmin uudelleen\n\ntiedosto: {2}\n\nvirhe ",
"u_ehstmp": "yritetään uudelleen; katso oikealta alhaalta",
"u_ehsfin": "palvelin hylkäsi pyynnön viimeistellä lataus; yritetään uudelleen...",
"u_ehssrch": "palvelin hylkäsi pyynnön suorittaa haku; yritetään uudelleen...",
"u_ehsinit": "palvelin hylkäsi pyynnön aloittaa lataus; yritetään uudelleen...",
"u_eneths": "verkkovirhe latauksen kättelyssä; yritetään uudelleen...",
"u_enethd": "verkkovirhe kohteen olemassaolon testauksessa; yritetään uudelleen...",
"u_cbusy": "odotetaan palvelimen luottavan meihin taas verkko-ongelman jälkeen...",
"u_ehsdf": "palvelimen levytila loppui!\n\nyritetään jatkuvasti, siinä tapauksessa että joku\nvapauttaa tarpeeksi tilaa jatkamiseen",
"u_emtleak1": "näyttää siltä että selaimessasi saattaa olla muistivuoto;\nole hyvä ja",
"u_emtleak2": ' <a href="{0}">vaihda https:ään (suositeltu)</a> tai ',
"u_emtleak3": ' ',
"u_emtleakc": 'kokeile seuraavaa:\n<ul><li>paina <code>F5</code> päivittääksesi sivun</li><li>sitten poista käytöstä &nbsp;<code>mt</code>&nbsp; nappi &nbsp;<code>⚙️ asetuksissa</code></li><li>ja kokeile latausta uudelleen</li></ul>Lataukset ovat hieman hitaampia, minkäs teet.\nSori siitä!\n\nPS: chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">sisältää bugfixin tätä varten</a>',
"u_emtleakf": 'kokeile seuraavaa:\n<ul><li>paina <code>F5</code> päivittääksesi sivun</li><li>sitten ota käyttöön <code>🥔</code> (peruna) lataus UI:ssa<li>ja kokeile latausta uudelleen</li></ul>\nPS: firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">toivottavasti saa kerättyä itsensä kasaan</a> jossain vaiheessa',
"u_s404": "ei löydy palvelimelta",
"u_expl": "selitä",
"u_maxconn": "useimmat selaimet rajoittavat tämän 6:een, mutta firefox antaa nostaa sitä <code>connections-per-server</code> asetuksella <code>about:config</code>:issa",
"u_tu": '<p class="warn">VAROITUS: turbo päällä, <span>&nbsp;asiakasohjelma ei välttämättä huomaa jatkaa keskeneräisiä latauksia; katso turbo-napin vihje</span></p>',
"u_ts": '<p class="warn">VAROITUS: turbo päällä, <span>&nbsp;hakutulokset voivat olla vääriä; katso turbo-napin vihje</span></p>',
"u_turbo_c": "turbo on poistettu käytöstä palvelimen asetuksissa",
"u_turbo_g": "poistetaan turbo käytöstä koska sinulla ei ole\nhakemistolistausoikeuksia tässä asemassa",
"u_life_cfg": 'automaattinen poisto <input id="lifem" p="60" /> min kuluttua (tai <input id="lifeh" p="3600" /> tuntia)',
"u_life_est": 'lataus poistetaan <span id="lifew" tt="paikallinen aika">---</span>',
"u_life_max": 'tämä hakemisto pakottaa\nmaksimi elinajan {0}',
"u_unp_ok": 'unpost on sallittu {0}',
"u_unp_ng": 'unpost EI ole sallittu',
"ue_ro": 'sinulla on vain read-oikeus tähän hakemistoon\n\n',
"ue_nl": 'et ole tällä hetkellä kirjautunut sisään',
"ue_la": 'olet tällä hetkellä kirjautunut sisään nimellä "{0}"',
"ue_sr": 'olet tällä hetkellä tiedostohaku-tilassa\n\nvaihda lataus-tilaan klikkaamalla suurennuslasia 🔎 (suuren HAKU napin vieressä), ja yritä latausta uudelleen\n\npahoittelen',
"ue_ta": 'yritä latausta uudelleen, sen pitäisi toimia nyt',
"ue_ab": "tätä tiedostoa ladataan jo toiseen hakemistoon, ja se lataus täytyy suorittaa loppuun ennen kuin tiedostoa voidaan ladata muualle.\n\nVoit keskeyttää ja unohtaa alkuperäisen latauksen käyttämällä vasemmalla ylhäällä olevaa 🧯",
"ur_1uo": "OK: Tiedosto ladattu onnistuneesti",
"ur_auo": "OK: Kaikki {0} tiedostoa ladattu onnistuneesti",
"ur_1so": "OK: Tiedosto löytyi palvelimelta",
"ur_aso": "OK: Kaikki {0} tiedostoa löytyi palvelimelta",
"ur_1un": "Lataus epäonnistui, pahoittelen",
"ur_aun": "Kaikki {0} latausta epäonnistui, pahoittelen",
"ur_1sn": "Tiedostoa EI löytynyt palvelimelta",
"ur_asn": "{0} tiedostoa EI löytynyt palvelimelta",
"ur_um": "Valmis;\n{0} latausta OK,\n{1} latausta epäonnistui, pahoittelen",
"ur_sm": "Valmis;\n{0} tiedostoa löytyi palvelimelta,\n{1} tiedostoa EI löytynyt palvelimelta",
"rc_opn": "avaa", //m
"rc_ply": "toista", //m
"rc_pla": "toista äänenä", //m
"rc_txt": "avaa tiedostoselaimessa", //m
"rc_md": "avaa tekstieditorissa", //m
"rc_dl": "Lataa", //m
"rc_zip": "Lataa arkistona", //m
"rc_del": "poista", //m
"rc_cut": "Leikkaa", //m
"rc_cpy": "kopioi", //m
"rc_pst": "Liitä", //m
"rc_nfo": "uusi kansio", //m
"rc_nfi": "uusi tiedosto", //m
"rc_sal": "valitse kaikki", //m
"rc_sin": "käännä valinta", //m
"lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?",
"splash": {
"a1": "päivitä",
"b1": "hei sie muukalainen &nbsp; <small>(et ole kirjautunut sisään)</small>",
"c1": "kirjaudu ulos",
"d1": "tulosta pinojälki",
"d2": "näytä kaikkien aktiivisten säikeiden tila",
"e1": "päivitä konffit",
"e2": "lataa konfiguraatiotiedostot uudelleen (käyttäjätilit/asemat/asemaflagit),$Nja skannaa kaikki e2ds asemat uudelleen$N$Nhuom: kaikki global-asetuksiin$Ntehdyt muutokset vaativat täyden$Nuudelleenkäynnistyksen",
"f1": "voit selata näitä:",
"g1": "voit ladata näihin:",
"cc1": "muuta:",
"h1": "poista k304 käytöstä",
"i1": "ota k304 käyttöön",
"j1": "k304 katkaisee yhteytesi jokaisella HTTP 304:llä, mikä voi estää joitain bugisia välityspalvelimia jumittumasta/lopettamasta sivujen lataamista, <em>mutta</em> se myös vähentää suorituskykyä",
"k1": "nollaa asetukset",
"l1": "kirjaudu sisään:",
"ls3": "kirjaudu sisään", //m
"lu4": "käyttäjätunnus", //m
"lp4": "salasana", //m
"lo3": "kirjaa “{0}” ulos kaikkialta", //m
"lo2": "tämä lopettaa istunnon kaikissa selaimissa", //m
"m1": "tervetuloa takaisin,",
"n1": "404: ei löytynyt mitään &nbsp;┐( ´ -`)┌",
"o1": 'tai ehkä sinulla ei vain ole käyttöoikeuksia? kokeile salasanaa tai <a href="' + SR + '/?h">mene kotiin</a>',
"p1": "403: pääsy kielletty &nbsp;~┻━┻",
"q1": 'kokeile salasanaa tai <a href="' + SR + '/?h">mene kotiin</a>',
"r1": "mene kotiin",
".s1": "uudelleenkartoita",
"t1": "toiminto",
"u2": "aika viimeisestä palvelimen kirjoituksesta$N( lataus / uudelleennimeäminen / tms. )$N$N17d = 17 päivää$N1h23 = 1 tunti 23 minuuttia$N4m56 = 4 minuuttia 56 sekuntia",
"v1": "yhdistä",
"v2": "käytä tätä palvelinta paikallisena kiintolevynä",
"w1": "vaihda https:ään",
"x1": "vaihda salasana",
"y1": "muokkaa jakoja",
"z1": "avaa tämä jako:",
"ta1": "täytä ensin uusi salasana",
"ta2": "toista vahvistaaksesi uuden salasanan:",
"ta3": "löytyi kirjoitusvirhe; yritä uudelleen",
"nop": "VIRHE: Salasana ei voi olla tyhjä", //m
"nou": "VIRHE: Käyttäjänimi ja/tai salasana ei voi olla tyhjä", //m
"aa1": "saapuvat:",
"ab1": "poista no304 käytöstä",
"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",
"ag1": "näytä tunnetut IdP-käyttäjät",
}
};

710
copyparty/web/tl/fra.js Normal file
View file

@ -0,0 +1,710 @@
// Les lignes se terminant par //m sont des traductions automatiques non vérifiées
Ls.fra = {
"tt": "français",
"cols": {
"c": "bouton d'action",
"dur": "durée",
"q": "qualité / débit binaire",
"Ac": "codec audio",
"Vc": "codec vidéo",
"Fmt": "format / conteneur",
"Ahash": "somme de contrôle audio",
"Vhash": "somme de contrôle vidéo",
"Res": "résolution",
"T": "type de fichier",
"aq": "qualité audio / débit binaire",
"vq": "qualité vidéo / débit binaire",
"pixfmt": "sous-échantillonnage / structure de pixel",
"resw": "résolution horizontale",
"resh": "résolution verticale",
"chs": "canaux audio",
"hz": "fréquence",
},
"hks": [
[
"misc",
["Échap", "ferme divers menus"],
"gestionaire de fichiers",
["G", "activer vue en liste / vue en grille"],
["T", "activer les miniatures / icônes"],
["⇧ A/D", "taille des miniatures"],
["ctrl-K", "suprimer la sélection"],
["ctrl-X", "couper la sélection au presse-papier"],
["ctrl-C", "copier la sélection au presse-papier"],
["ctrl-V", "coller (déplacer/copier) ici"],
["Y", "télécharger la sélection"],
["F2", "renomer la sélection"],
"file-list-sel",
["Espace", "activer la sélection de fichiers"],
["↑/↓", "déplacer le selecteur"],
["ctrl ↑/↓", "déplacer le curseur et la zone d'affichage"],
["⇧ ↑/↓", "sélectioner le fichier précédent/suivant"],
["ctrl-A", "sélectionner tout les fichiers / dossiers"],
], [
"navigation",
["B", "basculer la vue en fil d'Ariane / panneau de navigation"],
["I/K", "dossier précédent/suivant"],
["M", "dossier parent (ou réduire le dossier actuel)"],
["V", "activer les dossiers / fichiers texte dans le volet de navigation"],
["A/D", "taille du volet de navigation"],
], [
"lecteur-audio",
["J/L", "chanson précédente/suivante"],
["U/O", "sauter 10s en arrière/avant"],
["0..9", "sauter à 0%..90%"],
["P", "lecture/pause (démarre également la lecture)"],
["S", "sélectionner la chanson en cours"],
["Y", "télécharger le morceau"],
], [
"visionneuse d'image",
["J/L, ←/→", "image précédente/suivante"],
["Début/Fin, ⭦/Fin", "première/dernière image"],
["F", "plein écran"],
["R", "rotation horaire"],
["⇧ R", "rotation antihoraire"],
["S", "sélectionner l'image"],
["Y", "télécharger l'image"],
], [
"lecteur vidéo",
["U/O", "sauter 10s en arrière/avant"],
["P/K/Espace", "lecture/pause"],
["C", "continuer de lire la suivante"],
["V", "lire en boucle"],
["M", "couper le son"],
["[ and ]", "définir l'intervalle de boucle"],
], [
"visionneuse de texte",
["I/K", "fichier précédent/suivant"],
["M", "fermer le fichier texte"],
["E", "modifier le fichier texte"],
["S", "sélectioner le fichier (pour le couper/copier/renommer)"],
["Y", "télécharger le fichier texte"], //m
["⇧ J", "embellir json"], //m
]
],
"m_ok": "OK",
"m_ng": "Annuler",
"enable": "Activer",
"danger": "DANGER",
"clipped": "copié dans le presse-papier",
"ht_s1": "seconde",
"ht_s2": "secondes",
"ht_m1": "minute",
"ht_m2": "minutes",
"ht_h1": "heure",
"ht_h2": "heures",
"ht_d1": "jour",
"ht_d2": "jours",
"ht_and": " et ",
"goh": "panneau-de-commande",
"gop": 'élément "frère" précédent">précédent',
"gou": 'dossier parent">haut',
"gon": 'dossier suivant">suivant',
"logout": "Déconnexion ",
"login": "Se connecter", //m
"access": " accès",
"ot_close": "fermer le sous-menu",
"ot_search": "chercher des fichiers par leurs attributs, chemin / nom, tag musicaux, ou nimporte quelle combinaison de ces options$N$N&lt;code&gt;foo bar&lt;/code&gt; = doit contenir à la fois «foo» et «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = doit contenir «foo» mais pas «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = commence par «yana» et est un fichier «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contient exactement «try unite»$N$Nle format de date est iso-8601, comme$N&lt;code&gt;2009-12-31&lt;/code&gt; ou &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: supprimer vos téléchargements récents, ou annuler ceux en cours",
"ot_bup": "bup: téléverseur de base, prend même en charge netscape 4.0",
"ot_mkdir": "mkdir: créer un nouveau répertoire",
"ot_md": "new-file: créer un nouveau fichier texte", //m
"ot_msg": "msg: envoyer un message au journal du serveur",
"ot_mp": "options du lecteur multimedia",
"ot_cfg": "options de configuration",
"ot_u2i": 'up2k : téléverser des fichiers (si vous avez un accès en écriture) ou basculer en mode recherche pour voir s\'ils existent quelque part sur le serveur$N$Nles téléversements peuvent être repris, ils sont multithreadé, et les horodatages des fichiers sont préservés, mais cela utilise plus de CPU que [🎈]&nbsp; (le téléverseur de base)<br /><br />pendant les téléversements, cette icône devient un indicateur de progression!',
"ot_u2w": 'up2k : téléverser des fichiers avec prise en charge de la reprise (fermez votre navigateur et déposez les mêmes fichiers plus tard)$N$multithreadé, et les horodatages des fichiers sont préservés, mais cela utilise plus de CPU que [🎈]&nbsp; (le téléverseur de base)<br /><br />pendant les téléversements, cette icône devient un indicateur de progression!',
"ot_noie": 'Utilisez Chrome / Firefox / Edge',
"ab_mkdir": "créer un nouveau répertoire",
"ab_mkdoc": "nouveau fichier texte", //m
"ab_msg": "envoyer un message au journal du serveur",
"ay_path": "passer aux dossiers",
"ay_files": "passer aux fichiers",
"wt_ren": "renommer les éléments sélectionnés$NHotkey: F2",
"wt_del": "supprimer les éléments sélectionnés$NHotkey: ctrl-K",
"wt_cut": "couper les éléments sélectionnés &lt;small&gt;(puis coller ailleurs)&lt;/small&gt;$NHotkey: ctrl-X",
"wt_cpy": "copier les éléments sélectionnés dans le presse-papiers$N(pour les coller ailleurs)$NHotkey: ctrl-C",
"wt_pst": "coller une sélection précédemment coupée / copiée$NHotkey: ctrl-V",
"wt_selall": "sélectionner tous les fichiers$NHotkey: ctrl-A (lorsque le fichier est sélectionné)",
"wt_selinv": "inverser la sélection",
"wt_zip1": "télécharger ce dossier en tant qu'archive",
"wt_selzip": "télécharger la sélection en tant qu'archive",
"wt_seldl": "télécharger la sélection en tant que fichiers séparés$NHotkey: Y",
"wt_npirc": "copier les informations de la musique au format irc",
"wt_nptxt": "copier les informations de la musique en texte brut",
"wt_m3ua": "ajouter à la playlist m3u (cliquez sur <code>📻copier</code> plus tard)",
"wt_m3uc": "copier la playlist m3u dans le presse-papiers",
"wt_grid": "basculer entre la vue en grille / liste$NHotkey: G",
"wt_prev": "musique précédente$NHotkey: J",
"wt_play": "lecture / pause$NHotkey: P",
"wt_next": "musique suivante$NHotkey: L",
"ul_par": "téléversements parallèles:",
"ut_rand": "attribution de noms de fichiers aléatoires",
"ut_u2ts": "copier l'horodatage de dernière modification$Nde votre système de fichiers vers le serveur\">📅",
"ut_ow": "écraser les fichiers existants sur le serveur?$N🛡: jamais (générera un nouveau nom de fichier à la place)$N🕒: écraser si le fichier sur le serveur est plus ancien que le vôtre$N♻: toujours écraser si les fichiers sont différents$N⏭: ignorer systématiquement tous les fichiers existants", //m
"ut_mt": "continuer à calculer la somme de contrôle d'autres fichiers pendant le téléversement$N$Npeut-être désactiver si votre CPU ou HDD est la cause de perte de performances",
"ut_ask": 'demander confirmation avant le début du téléversement">💭',
"ut_pot": "améliorer la vitesse de téléversement sur les appareils lents$Nen simplifiant l'interface utilisateur",
"ut_srch": "ne pas réellement téléverser, mais vérifier si les fichiers existent déjà$N sur le serveur (scannera tous les dossiers que vous pouvez lire)",
"ut_par": "mettre en pause les téléversements en le réglant sur 0$N$Naugmenter si votre connexion est lente / à forte latence$N$Nle garder à 1 sur le LAN ou si le HDD du serveur est un goulot d'étranglement",
"ul_btn": "déposer des fichiers / dossiers<br>ici (ou cliquez sur moi)",
"ul_btnu": "T É L É V E R S E R",
"ul_btns": "C H E R C H E R",
"ul_hash": "somme de contrôle",
"ul_send": "envoyer",
"ul_done": "terminé",
"ul_idle1": "aucun téléversement n'est encore dans la file d'attente",
"ut_etah": "moyenne &lt;em&gt;hashing&lt;/em&gt; vitesse, et temps estimé jusqu'à la fin",
"ut_etau": "moyenne &lt;em&gt;upload&lt;/em&gt; vitesse et temps estimé jusqu'à la fin",
"ut_etat": "moyenne &lt;em&gt;total&lt;/em&gt; vitesse et temps estimé jusqu'à la fin",
"uct_ok": "terminé avec succès",
"uct_ng": "non réussi : échoué / rejeté / non trouvé",
"uct_done": "terminés et échoué combinés",
"uct_bz": "hachage ou téléversement",
"uct_q": "inactif, en attente",
"utl_name": "nom de fichier",
"utl_ulist": "liste",
"utl_ucopy": "copie",
"utl_links": "liens",
"utl_stat": "état",
"utl_prog": "progrès",
// keep short:
"utl_404": "404",
"utl_err": "ERREUR",
"utl_oserr": "OS-ERREUR",
"utl_found": "trouvé",
"utl_defer": "état",
"utl_yolo": "YOLO",
"utl_done": "terminé",
"ul_flagblk": "les fichiers ont été ajoutés à la file d'attente</b><br>cependant, il y a un processus up2k actif dans un autre onglet du navigateur,<br>en attente qu'il finisse d'abord",
"ul_btnlk": "la configuration du serveur a verrouillé cette options dans cet état",
"udt_up": "Téléverser",
"udt_srch": "Chercher",
"udt_drop": "déposer ici",
"u_nav_m": '<h6>aight, ques-que tu à ?</h6><code>Enter</code> = Fichiers (un ou plus)\n<code>ESC</code> = Un dossier (sous-dossiers inclus)',
"u_nav_b": '<a href="#" id="modal-ok">Fichiers</a><a href="#" id="modal-ng">Un dossier</a>',
"cl_opts": "options",
"cl_hfsz": "taille du fichier", //m
"cl_themes": "thème",
"cl_langs": "langue",
"cl_ziptype": "téléchargement de dossier",
"cl_uopts": "up2k",
"cl_favico": "favicon",
"cl_bigdir": "gros dossiers",
"cl_hsort": "#sort",
"cl_keytype": "notation des touches",
"cl_hiddenc": "colonnes masquées",
"cl_hidec": "masquer",
"cl_reset": "réinitialiser",
"cl_hpick": "cliquez sur les en-têtes de colonnes pour les masquer dans le tableau ci-dessous",
"cl_hcancel": "masquage des colonnes annulé",
"cl_rcm": "menu contextuel", //m
"ct_grid": '田 grille',
"ct_ttips": '◔ ◡ ◔"> infobulles',
"ct_thumb": 'vue en grille, activer les icônes ou les miniatures$NHotkey: T">🖼️ minia',
"ct_csel": 'utiliser CTRL et MAJ pour selectioner des fichiers en vue en grille">sel',
"ct_dl": 'forcer le téléchargement (ne pas afficher en ligne) lorsquun fichier est cliqué">dl', //m
"ct_ihop": 'quand le visionneuse d\'image est fermé, faire defiller vers le bas jusqu\'au dernier fichier">g⮯',
"ct_dots": 'voir les fichiers caché (si le serveur le permet)">dotfiles',
"ct_qdel": 'ne demander qu\'une confirmation lors de la suppression de fichiers>qdel',
"ct_dir1st": 'trier les dossiers avant les fichiers">📁 first',
"ct_nsort": 'triage par numérotation (pour les nom de fichiers qui sont numérotés)">nsort',
"ct_utc": 'voir tout les horodatage en format UTC">UTC',
"ct_readme": 'voir le fichier README.md dans le listage des dossiers">📜 readme',
"ct_idxh": 'voir une version html (index.html) au-lieu du listage des dossiers normal">htm',
"ct_sbars": 'montrer la barre de defilement">⟊',
"cut_umod": "si un fichier existe déjà sur le server, mettre à jour l'horodatage de dernière modification du serveur pour qu'il corresponde à votre fichier local (nécessite des autorisations d'écriture et de suppression)\">re📅",
"cut_turbo": "le bouton yolo, vous ne voulez probablement PAS activer ceci:$N$Nutilisez ceci si vous téléchargez une grande quantité de fichiers et que vous devez redémarrer pour une raison quelconque, et que vous souhaitez continuer le téléchargement dès que possible$N$Ncela remplace la vérification de hachage par une simple <em>&quot;est-ce que cela a la même taille de fichier sur le serveur?&quot;</em> donc si le contenu du fichier est différent, il ne sera PAS téléchargé$N$Nvous devriez désactiver cela lorsque le téléchargement est terminé, puis &quot;télécharger&quot; les mêmes fichiers à nouveau pour laisser le client les vérifier\">turbo",
"cut_datechk": "n'a aucun effet à moins que le bouton turbo ne soit activé$N$Nréduit le facteur yolo d'un tout petit peu ; vérifie si les horodatages des fichiers sur le serveur correspondent aux vôtres$N$Ndevrait <em>théoriquement</em> attraper la plupart des téléchargements inachevés / corrompus, mais n'est pas un substitut à un passage de vérification avec turbo désactivé par la suite\">date-chk",
"cut_u2sz": "taille (en MiB) de chaque morceau de téléversement; des grosse valeurs vont mieux passer si la distance entre le serveur et vous est trés grande. Si vous avez une connection trés instable, essayer de plus petites valeurs",
"cut_flag": "s'assurer qu'un seul onglet est entrain de mettre un fichier en ligne a la fois $N -- les autres onglets doivent avoir cette option activé aussi $N -- affecte seulement les onglets qui sont sur le même domaine",
"cut_az": "mettre en ligne les fichiers dans l'ordre alphabétique, plutôt que le plus petit fichier en premier$N$Nl'ordre alphabétique peut rendre la lecture plus douce sur pour les yeux si quelque chose s'est mal passé sur le serveur, mais cela rend le téléversement légèrement plus lent sur fibre / LAN",
"cut_nag": "recevoir une notification via l'OS quand un téléversement finit$N(seulement si le navigateur ou l'onglet n'est pas actif)",
"cut_sfx": "alerte audible quand le téléversement finit$N(seulement si le navigateur ou l'onglet n'est pas actif)",
"cut_mt": "utiliser le calcul de somme de contrôle multithreadé pour accelerer le processus$N$Ncela utilise des web-workers et nécessite$Nplus de RAM (jusqu'à 512 MiB supplémentaires)$N$NCela rend https 30% plus rapide, http 4.5x plus rapide\">mt",
"cut_wasm": "utiliser wasm au lieu du hachage intégré du navigateur; améliore la vitesse sur les navigateurs basés sur chrome mais augmente la charge CPU, et de nombreuses anciennes versions de chrome ont des bugs qui font que le navigateur consomme toute la RAM et plante si cela est activé\">wasm",
"cft_text": "text favicon (laisser vide et rafraîchir pour désactiver)",
"cft_fg": "couleur de premier plan",
"cft_bg": "couleur d'arrière-plan",
"cdt_lim": "nombre maximum de fichiers à afficher dans un dossier",
"cdt_ask": "lorsque vous faites défiler vers le bas,$Nau lieu de charger plus de fichiers,$Ndemander quoi faire",
"cdt_hsort": "combien de règles de tri (&lt;code&gt;,sorthref&lt;/code&gt;) à inclure dans les media-URLs. Définir cette valeur à 0 ignorera également les règles de tri incluses dans les liens média lorsque vous cliquez dessus.",
"cdt_ren": "activer le menu contextuel personnalisé, le menu normal reste accessible avec shift + clic droit", //m
"tt_entree": "afficher le panneau de navigation (arborescence des dossiers)$NHotkey: B",
"tt_detree": "afficher le fil dAriane$NHotkey: B",
"tt_visdir": "faire défiler jusqu'au dossier sélectionné",
"tt_ftree": "basculer l'arborescence des dossiers / fichiers texte$NHotkey: V",
"tt_pdock": "afficher les dossiers parents dans un panneau ancré en haut",
"tt_dynt": "croissance automatique à mesure que l'arborescence s'étend",
"tt_wrap": "retour à la ligne",
"tt_hover": "révéler les lignes débordantes au survol$N( interrompt le défilement à moins que le curseur de la souris ne soit dans la gouttière gauche )",
"ml_pmode": "à la fin du dossier…",
"ml_btns": "cmds",
"ml_tcode": "transcoder",
"ml_tcode2": "transcoder vers",
"ml_tint": "teinte",
"ml_eq": "égaliseur audio",
"ml_drc": "compresseur de plage dynamique",
"mt_loop": "répéter en boucle une musique\">🔁",
"mt_one": "stopper après une musique\">1⃣",
"mt_shuf": "mélanger les musiques dans chaque dossiers\">🔀",
"mt_aplay": "jouer automatiquement si le lien utilisé pour accéder au serveur a un song-ID $N$N, désactiver cela arrêtera également la mise à jour de l'URL de la page avec les song-IDs lors de la lecture de la musique, pour éviter la lecture automatique si ces paramètres sont perdus mais que l'URL reste\">a▶",
"mt_preload": "commencer à charger la prochaine chanson près de la fin pour une lecture sans interruption\">preload",
"mt_prescan": "explorer le dossier suivant avant la dernière musique$Nne finisse, pour garder le navigateur content$Npour qu'il n'arrête pas la lecture\">nav",
"mt_fullpre": "essayer de pré-charger la musique entière;$N✅ activer en cas de connection instable,$N❌ désactiver en revanche sur une connection lente va probablement être mieux\">full",
"mt_fau": "sur téléphone, empêche la musique de s'arrêter de jouer si la prochaine n'est pas pré-chargée assez rapidement (peut rendre l'affichage des tags buggé)\">☕️",
"mt_waves": "barre de progression en spectrograme:$Nmontrer l'amplitude audio dans la miniature\">~s",
"mt_npclip": "montrer les boutons pour copier le morceau en cours de lecture\">/np",
"mt_m3u_c": "montrer les boutons pour copier les$morceaux sélectionnées en tant qu'entrées de playlist m3u8\">📻",
"mt_octl": "intégration os (touches de raccourci multimédia / osd)\">os-ctl",
"mt_oseek": "permettre la recherche via l'intégration os$N$Nremarque : sur certains appareils (iPhones),$Ncela remplace le bouton de la chanson suivante\">seek",
"mt_oscv": "montrer la couverture de l'album dans l'osd\">art",
"mt_follow": "garder la piste en cours défilée dans la vue\">🎯",
"mt_compact": "contrôles compacts\">⟎",
"mt_uncache": "effacer le cache &nbsp;(essayez ceci si votre navigateur a mis en cache$Nun copie défectueuse d'une chanson, ce qui empêche sa lecture)\">uncache",
"mt_mloop": "lire en boucle le dossier ouvert\">🔁 loop",
"mt_mnext": "charger le dossier suivant et continuer\">📂 next",
"mt_mstop": "arrêter la lecture\">⏸ stop",
"mt_cflac": "convertir flac / wav en {0}\">flac",
"mt_caac": "convertir aac / m4a en {0}\">aac",
"mt_coth": "convertir tout les autres (pas mp3) en {0}\">oth",
"mt_c2opus": "meilleur choix pour PC fixe, PC portable, android\">opus",
"mt_c2owa": "opus-weba, pour iOS 17.5 et supérieur\">owa",
"mt_c2caf": "opus-caf, pour iOS 11 à 17\">caf",
"mt_c2mp3": "utilisez ceci sur des appareils très anciens\">mp3",
"mt_c2flac": "meilleure qualité sonore, mais téléchargements énormes\">flac",
"mt_c2wav": "lecture non compressée (encore plus gros)\">wav",
"mt_c2ok": "bien, bon choix",
"mt_c2nd": "ce n'est pas le format de sortie recommandé pour votre appareil, mais ça devrait aller",
"mt_c2ng": "votre appareil ne semble pas prendre en charge ce format de sortie, mais essayons quand même",
"mt_xowa": "il y a des bugs dans iOS qui empeche d'avoir une lecture en ariere plan en utilisant ce format; utilisez caf ou mp3 à la place",
"mt_tint": "niveau darrière-plan (0100) de la barre de progression$Npour rendre la mise en mémoire tampon moins gênante",
"mt_eq": "active l'égaliseur et le contrôle de gain;$N$Nboost &lt;code&gt;0&lt;/code&gt; = volume standard 100% (non modifié)$N$Nwidth &lt;code&gt;1 &nbsp;&lt;/code&gt; = stéréo standard (non modifié)$Nwidth &lt;code&gt;0.5&lt;/code&gt; = 50% de crossfeed gauche-droite$Nwidth &lt;code&gt;0 &nbsp;&lt;/code&gt; = mono$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = suppression vocale :^)$N$Nl'activation de l'égaliseur rend les albums gapless entièrement gapless, alors laissez-le activé avec toutes les valeurs à zéro (sauf largeur = 1) si vous vous en souciez",
"mt_drc": "active le compresseur de plage dynamique (aplanisseur de volume / brickwaller); activera également l'EQ pour équilibrer les choses, donc définissez tous les champs EQ sauf 'width' sur 0 si vous ne le voulez pas$N$Ndiminue le volume de l'audio au-dessus de THRESHOLD dB; pour chaque RATIO dB au-delà de THRESHOLD, il y a 1 dB de sortie, donc des valeurs par défaut de tresh -24 et ratio 12 signifient qu'il ne devrait jamais être plus fort que -22 dB et qu'il est sûr d'augmenter le boost de l'égaliseur à 0.8, ou même 1.8 avec ATK 0 et un énorme RLS comme 90 (ne fonctionne que dans firefox; RLS est max 1 dans les autres navigateurs)$N$N(voir wikipedia, ils expliquent cela beaucoup mieux)",
"mb_play": "lecture",
"mm_hashplay": "lire ce fichier audio ?",
"mm_m3u": "appuyez sur <code>Entrée/OK</code> pour lire\nappuyez sur <code>Échap/Annuler</code> pour modifier",
"mp_breq": "nécessite firefox 82+ ou chrome 73+ ou iOS 15+",
"mm_bload": "chargement en cours…",
"mm_bconv": "conversion en {0}, veuillez patienter…",
"mm_opusen": "votre navigateur ne peut pas lire les fichiers aac / m4a ;\nle transcodage en opus est maintenant activé",
"mm_playerr": "échec de la lecture : ",
"mm_eabrt": "La tentative de lecture a été annulée",
"mm_enet": "Votre connexion internet est instable ou inexistante",
"mm_edec": "Ce fichier est supposément corrompu??",
"mm_esupp": "Votre navigateur ne comprend pas ce format audio",
"mm_eunk": "Erreur inconnue",
"mm_e404": "Impossible de lire l'audio ; erreur 404 : fichier introuvable.",
"mm_e403": "Impossible de lire l'audio ; erreur 403 : accès refusé.\n\nEssayez d'appuyer sur F5 pour recharger, peut-être que vous avez été déconnecté",
"mm_e500": "Impossible de lire l'audio ; erreur 500 : vérifiez les journaux du serveur.",
"mm_e5xx": "Impossible de lire l'audio ; erreur serveur ",
"mm_nof": "Pas d'autres fichiers audio trouvés par ici",
"mm_prescan": "En recherche d'une autre musique à lire…",
"mm_scank": "Prochaine musique trouvée :",
"mm_uncache": "cache vidé ; toutes les chansons seront retéléchargées lors de la prochaine lecture",
"mm_hnf": "cette chanson n'existe plus",
"im_hnf": "cette image n'existe plus",
"f_empty": 'ce dossier est vide',
"f_chide": 'ceci va cacher les colonnes «{0}»\n\ntu peut les réafficher dans les options',
"f_bigtxt": "ce fichier fait {0} MiB -- tu veut vraiment le voir en tant que texte ?",
"f_bigtxt2": "voir seulement la fin du fichier à la place ? ceci activera aussi le suivi en temps réel, affichant les nouvelles lignes de texte au fur et à mesure",
"fbd_more": '<div id="blazy">showing <code>{0}</code> of <code>{1}</code> files; <a href="#" id="bd_more">show {2}</a> or <a href="#" id="bd_all">show all</a></div>',
"fbd_all": '<div id="blazy">showing <code>{0}</code> of <code>{1}</code> files; <a href="#" id="bd_all">show all</a></div>',
"f_anota": "seulement {0} des {1} elements sont selectioné;\npour selectioner le dossier entier, fait défiler jusqu'au fond",
"f_dls": 'le lien de fichier dans le répertoire actuel\nà été changé en lien de téléchargement',
"f_partial": "Pour télécharger de façon sécurisée un fichier qui est entrain de se faire téléverser, cliquez sur le fichier qui a le même nom, mais sans l'extension de fichier <code>.PARTIAL</code>. Choisissez ANNULER ou appuiez sur la touche Échap pour faire cela.\n\nAppuyer sur OK / Entrée ignorera cet avertissement et continuera à télécharger le fichier temporaire <code>.PARTIAL</code> à la place, ce qui donnera presque certainement des données corrompues.",
"ft_paste": "coller {0} éléments$NHotkey: ctrl-V",
"fr_eperm": 'impossible de renommer:\n vous n\'avez pas la permission “move” dans ce dossier',
"fd_eperm": 'impossible de supprimer:\nvous n\'avez pas la permission “delete” dans ce dossier',
"fc_eperm": 'impossible de couper:\nvous n\'avez pas la permission “move” dans ce dossier',
"fp_eperm": 'impossible de coller:\nvous n\'avez pas la permission “write” dans ce dossier',
"fr_emore": "sélectionnez au moins un élément à renommer",
"fd_emore": "sélectionnez au moins un élément à supprimer",
"fc_emore": "sélectionnez au moins un élément à couper",
"fcp_emore": "sélectionnez au moins un élément à copier dans le presse-papiers",
"fs_sc": "partager le dossier dans lequel vous vous trouvez",
"fs_ss": "partager les fichiers sélectionnés",
"fs_just1d": "vous ne pouvez pas sélectionner plus d'un dossier,\nou mélanger des fichiers et des dossiers dans une seule sélection",
"fs_abrt": "❌ abandonner",
"fs_rand": "🎲 nom.aleatoire",
"fs_go": "✅ créer partage",
"fs_name": "nom",
"fs_src": "source",
"fs_pwd": "mdp",
"fs_exp": "expiration",
"fs_tmin": "min",
"fs_thrs": "heures",
"fs_tdays": "jours",
"fs_never": "éternel",
"fs_pname": "nom de lien optionnel ; sera aléatoire si vide",
"fs_tsrc": "le fichier ou le dossier à partager",
"fs_ppwd": "mot de passe optionnel",
"fs_w8": "création du partage…",
"fs_ok": "appuyez sur <code>Entrée/OK</code> pour le Presse-papiers\nappuyez sur <code>Échap/Annuler</code> pour fermer",
"frt_dec": "peut potentiellement réparer certaines instances de noms de fichiers cassés\">url-decode",
"frt_rst": "réinitialiser les noms de fichiers modifiés à leurs originaux\">↺ reset",
"frt_abrt": "abandonner et fermer cette fenêtre\">❌ cancel",
"frb_apply": "APPLIQUER RENOMMER",
"fr_adv": "renommage par lot / métadonnées / motif\">advanced",
"fr_case": "regex sensible à la casse\">case",
"fr_win": "noms windows-safe; remplacer <code>&lt;&gt;:&quot;\\|?*</code> par des caractères japonais en pleine largeur\">win",
"fr_slash": "remplacer <code>/</code> par un caractère qui ne provoque pas la création de nouveaux dossiers\">no /",
"fr_re": "modèle de recherche regex à appliquer aux noms de fichiers originaux ; les groupes capturés peuvent être référencés dans le champ de format ci-dessous comme &lt;code&gt;(1)&lt;/code&gt; et &lt;code&gt;(2)&lt;/code&gt; et ainsi de suite",
"fr_fmt": "inspiré par foobar2000 : $N&lt;code&gt;(title)&lt;/code&gt; est remplacé par le titre de la chanson, $N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; saute [cette] partie si l'artiste est vide, $N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; remplit le numéro de piste à 2 chiffres",
"fr_pdel": "supprimer",
"fr_pnew": "enregistrer sous",
"fr_pname": "donnez un nom pour le nouveau preset",
"fr_aborted": "abandonné",
"fr_lold": "ancien nom",
"fr_lnew": "nouveau nom",
"fr_tags": "tags pour les fichier selectioné (lecture-seule, juste pour référence):",
"fr_busy": "renomage de {0} items…\n\n{1}",
"fr_efail": "renomage a échoué:\n",
"fr_nchg": "{0} des nouveaux noms ont été modifiés en raison de <code>win</code> et/ou <code>no /</code>\n\nOK pour continuer avec ces nouveaux noms modifiés ?",
"fd_ok": "suppression réussie",
"fd_err": "impossible de supprimer:\n",
"fd_none": "rien n'a été supprimé ; peut-être bloqué par la configuration du serveur (xbd) ?",
"fd_busy": "suppression de {0} éléments…\n\n{1}",
"fd_warn1": "SUPPRIMER ces {0} éléments ?",
"fd_warn2": "<b>Dernière chance !</b> Impossible de revenir en arrière. Supprimer ?",
"fc_ok": "couper {0} éléments",
"fc_warn": 'couper {0} éléments\n\nmais : seul <b>cet</b> onglets peut les coller\n(puisque la sélection est si absolument massive)',
"fcc_ok": "copié {0} éléments dans le presse-papiers",
"fcc_warn": 'copié {0} éléments dans le presse-papiers\n\nmais : seul <b>cet</b> onglet peut les coller\n(puisque la sélection est si absolument massive)',
"fp_apply": "utiliser ces noms",
"fp_skip": "ignorer les conflits", //m
"fp_ecut": "en premier, coupez ou copiez quelques fichiers / dossiers à coller / déplacer\n\nnote: vous pouvez couper / coller a travers different onglets",
"fp_ename": "{0} éléments ne peuvent pas être déplacés ici parce que leurs noms sont déjà pris. Donnez-leur un nouveau nom ci-dessous pour continuer, ou laissez le nom vide (\"ignorer les conflits\") pour les sauter :", //m
"fcp_ename": "{0} éléments ne peuvent pas être copiés ici parce que les noms sont déjà pris. Donnez-leur un nouveau nom ci-dessous pour continuer, ou laissez le nom vide (\"ignorer les conflits\") pour les sauter :", //m
"fp_emore": "il reste encore des collisions de noms de fichiers à corriger",
"fp_ok": "déplacement OK",
"fcp_ok": "copie OK",
"fp_busy": "déplacement de {0} éléments…\n\n{1}",
"fcp_busy": "copie de {0} éléments…\n\n{1}",
"fp_abrt": "abandon en cours...", //m
"fp_err": "deplacement échoué:\n",
"fcp_err": "copie échouée:\n",
"fp_confirm": "déplacer ces {0} éléments ici ?",
"fcp_confirm": "copier ces {0} éléments ici ?",
"fp_etab": 'lecture du presse-papier venant d\'un autre onglet échoué',
"fp_name": "téléversement d'un fichier de votre apareil. Donnez lui un nom:",
"fp_both_m": '<h6>choisisez ce qu\'il faut coller</h6><code>Entrer</code> = Déplacer {0} fichiers de «{1}»\n<code>ESC</code> = Téléverser {2} fichiers de votre appareil',
"fcp_both_m": '<h6>choisissez ce qu\'il faut coller</h6><code>Entrer</code> = Copier {0} fichiers de «{1}»\n<code>ESC</code> = Téléverser {2} fichiers de votre appareil',
"fp_both_b": '<a href="#" id="modal-ok">Déplacer</a><a href="#" id="modal-ng">Téléverser</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Copier</a><a href="#" id="modal-ng">Téléverser</a>',
"mk_noname": "entrez un nom dans le champ de texte à gauche avant de faire ça :p",
"nmd_i1": "ajoutez aussi lextension souhaitée, par exemple <code>.md</code>", //m
"nmd_i2": "vous ne pouvez créer que des fichiers <code>.md</code> car vous navez pas la permission deffacer", //m
"tv_load": "Chargement du document texte:\n\n{0}\n\n{1}% ({2} de {3} MiB chargés)",
"tv_xe1": "impossible de charger le fichier texte:\n\nerreur",
"tv_xe2": "404, fichier introuvable",
"tv_lst": "liste des fichiers texte dans",
"tvt_close": "retour a la vue de dossier$NHotkey: M (ou Échap)\">❌ fermer",
"tvt_dl": "télécharger ce fichier$NHotkey: Y\">💾 télécharger",
"tvt_prev": "montrer le document précédent$NHotkey: i\">⬆ précédent",
"tvt_next": "montrer le document suivant$NHotkey: K\">⬇ suivant",
"tvt_sel": "sélectionner le fichier &nbsp; ( pour couper / copier / supprimer / … )$NHotkey: S\">sel",
"tvt_j": "embellir json$NHotkey: shift-J\">j", //m
"tvt_edit": "ouvrir le fichier dans l'éditeur de texte$NHotkey: E\">✏️ modifier",
"tvt_tail": "surveiller le fichier pour les changements; montrer les nouvelles lignes en temps réel\">📡 suivre",
"tvt_wrap": "retour à la ligne\">↵",
"tvt_atail": "ancrer le défilement au fond de la page\">⚓",
"tvt_ctail": "décoder les couleurs du terminal (ansi escape codes)\">🌈",
"tvt_ntail": "limite de défilement en arrière (combien d'octets de texte à garder chargé)",
"m3u_add1": "musique ajoutée à la playlist m3u",
"m3u_addn": "{0} musiques ajoutées à la playlist m3u",
"m3u_clip": "la playlist m3u est maintenant copiée dans le presse-papier\n\nvous devriez créer un nouveau fichier texte nommé par exemple playlist.m3u et coller la playlist dans ce fichier ; cela la rendra lisible en tant que playlist",
"gt_vau": "ne pas voir les vidéos, juste jouer l'audio\">🎧",
"gt_msel": "activer la séléction de fichiers ; ctrl-clic sur un fichier pour override écraser$N$N<em>quand actif : double-cliquer sur un fichier / dossier pour l'ouvrir</em>$N$NHotkey: S\">multiséléction",
"gt_crop": "rogner les miniatures au centre\"&gt;rogner",
"gt_3x": "miniatures haute résolution\">3x",
"gt_zoom": "zoomer",
"gt_chop": "rogner",
"gt_sort": "trier par",
"gt_name": "nom",
"gt_sz": "taille",
"gt_ts": "date",
"gt_ext": "type",
"gt_c1": "tronquer les noms de fichiers (montrer moins)",
"gt_c2": "tronquer les noms de fichiers (montrer plus)",
"sm_w8": "recherche…",
"sm_prev": "les résultats de recherche ci-dessous proviennent d'une requête précédente:\n ",
"sl_close": "fermer les résultats de recherche",
"sl_hits": "affichage de {0} résultats",
"sl_moar": "chercher plus",
"s_sz": "taille",
"s_dt": "date",
"s_rd": "chemin",
"s_fn": "nom",
"s_ta": "tags",
"s_ua": "up@",
"s_ad": "adv.",
"s_s1": "minimum MiB",
"s_s2": "maximum MiB",
"s_d1": "min. iso8601",
"s_d2": "max. iso8601",
"s_u1": "téléverser après",
"s_u2": "et/ou avant",
"s_r1": "le chemin contient &nbsp; (séparé par des espaces)",
"s_f1": "le nom contient &nbsp; (négation avec -nope)",
"s_t1": "les tags contiennent &nbsp; (^=début, fin=$)",
"s_a1": "propriétés de métadonnées spécifiques",
"md_eshow": "impossible d'afficher le rendu ",
"md_off": "[📜<em>readme</em>] disabled in [⚙️] -- document caché",
"badreply": "Échec de l'analyse de la réponse du serveur",
"xhr403": "403: Accès refusé\n\nessayez d'appuyer sur F5, peut-être que vous avez été déconnecté",
"xhr0": "inconnu (vous avez probablement perdu la connexion au serveur, ou le serveur est hors ligne)",
"cf_ok": "désolé pour cela -- la protection DD" + wah + "oS a été déclenché\n\nles choses devraient reprendre dans environ 30 secondes\n\nsi rien ne se passe, appuyez sur F5 pour recharger la page",
"tl_xe1": "impossible de lister les sous-dossiers:\n\nerreur ",
"tl_xe2": "404: Dossier introuvable",
"fl_xe1": "impossible de lister les fichiers dans le dossier:\n\nerreur ",
"fl_xe2": "404: Dossier introuvable",
"fd_xe1": "impossible de créer le sous-dossier:\n\nerreur ",
"fd_xe2": "404: Dossier parent introuvable",
"fsm_xe1": "impossible d'envoyer le message:\n\nerreur ",
"fsm_xe2": "404: Dossier parent introuvable",
"fu_xe1": "échec du chargement de la liste des unpost du serveur:\n\nerreur ",
"fu_xe2": "404: Fichier introuvable??",
"fz_tar": "fichier gnu-tar non compressé (linux / mac)",
"fz_pax": "tar au format pax non compressé (plus lent)",
"fz_targz": "gnu-tar avec compression gzip niveau 3$N$Ncela est généralement très lent, donc$Nutilisez plutôt tar non compressé",
"fz_tarxz": "gnu-tar avec compression xz niveau 1$N$Ncela est généralement très lent, donc$Nutilisez plutôt tar non compressé",
"fz_zip8": "zip avec noms de fichiers utf8 (peut être instable sur windows 7 et versions antérieures)",
"fz_zipd": "zip avec noms de fichiers cp437 traditionnels, pour les très anciens logiciels",
"fz_zipc": "cp437 avec crc32 calculé tôt,$Nfor MS-DOS PKZIP v2.04g (octobre 1993)$N(prend plus de temps à charger avant que le téléchargement ne commence)",
"un_m1": "vous pouvez supprimer vos téléchargements récents (ou annuler ceux en cours) ci-dessous",
"un_upd": "rafraîchir",
"un_m4": "ou partager les fichiers visibles ci-dessous:",
"un_ulist": "montrer",
"un_ucopy": "copier",
"un_flt": "filtre optionnel:&nbsp; l'URL doit contenir",
"un_fclr": "effacer le filtre",
"un_derr": 'échec de l\'unpost-delete:\n',
"un_f5": 'quelque chose a cassé, veuillez essayer de rafraîchir ou d\'appuyer sur F5',
"un_uf5": "désolé mais vous devez rafraîchir la page (par exemple en appuyant sur F5 ou CTRL-R) avant que ce téléchargement puisse être annulé",
"un_nou": '<b>warning:</b> serveur trop occupé pour afficher les téléversements non finis; cliquez sur le lien "rafraîchir" dans un instant',
"un_noc": '<b>warning:</b> unpost des fichiers entièrement téléchargés n\'est pas activé/permis dans la configuration du serveur',
"un_max": "affichage des 2000 premiers fichiers (utilisez le filtre)",
"un_avail": "{0} téléchargements récents peuvent être supprimés<br />{1} ceux en cours peuvent être annulés",
"un_m2": "triés par date de téléchargement; les plus récents en premier:",
"un_no1": "sike! aucun téléchargement n'est suffisamment récent",
"un_no2": "sike! aucun téléchargement correspondant à ce filtre n'est suffisamment récent",
"un_next": "supprimer les {0} fichiers suivants ci-dessous",
"un_abrt": "abandonner",
"un_del": "supprimer",
"un_m3": "chargement de vos téléchargements récents…",
"un_busy": "suppression de {0} fichiers…",
"un_clip": "{0} liens copiés dans le presse-papiers",
"u_https1": "vous devriez",
"u_https2": "passer à https",
"u_https3": "pour de meilleure performances",
"u_ancient": 'votre navigateur est impressionnamment ancien -- vous devriez peut-être <a href="#" onclick="goto(\'bup\')">utiliser bup à la place</a>',
"u_nowork": "nécessite firefox 53+ ou chrome 57+ ou iOS 11+",
"tail_2old": "nécessite firefox 105+ ou chrome 71+ ou iOS 14.5+",
"u_nodrop": 'votre navigateur est trop ancien pour le téléversement par glisser-déposer',
"u_notdir": "ce n'est pas un dossier!\n\nvotre navigateur est trop ancien,\nveuillez essayer le glisser-déposer à la place",
"u_uri": "pour glisser-déposer des images depuis d'autres fenêtres de navigateur,\nveuillez les déposer sur le gros bouton de téléversement",
"u_enpot": 'passer à <a href="#">l\'interface utilisateur potato</a> (peut améliorer la vitesse de téléversement)',
"u_depot": 'passer à <a href="#">l\'interface utilisateur fancy</a> (peut réduire la vitesse de téléversement)',
"u_gotpot": 'passage à l\'interface utilisateur potato pour une vitesse de téléversement améliorée,\n\nn\'hésitez pas à revenir en arrière si ça ne vous plaît pas !',
"u_pott": "<p>fichiers: &nbsp; <b>{0}</b> fini, &nbsp; <b>{1}</b> échoué, &nbsp; <b>{2}</b> en cours, &nbsp; <b>{3}</b> en attente</p>",
"u_ever": "ceci est le téléverseur de base ; up2k nécessite au moins chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
"u_su2k": 'ceci est le téléverseur de base; <a href="#" id="u2yea">up2k</a> est meilleur',
"u_uput": 'optimiser pour la vitesse (ignorer la somme de contrôle)',
"u_ewrite": 'vous n\'avez pas accès en écriture à ce dossier',
"u_eread": 'vous n\'avez pas accès en lecture à ce dossier',
"u_enoi": 'la recherche de fichiers n\'est pas activée dans la configuration du serveur',
"u_enoow": "l'écrasage ne fonctionnera pas ici; besoin de permissions de suppression",
"u_badf": 'Ces {0} fichiers (sur {1} au total) ont été ignorés, probablement en raison de permissions système de fichiers:\n\n',
"u_blankf": 'Ces {0} fichiers (sur {1} au total) sont vides; les téléverser quand même ?\n\n',
"u_applef": 'Ces {0} fichiers (sur {1} au total) sont probablement indésirables;\nAppuyez sur <code>OK/Enter</code> pour IGNORER les fichiers suivants,\nAppuyez sur <code>Annuler/Échap</code> pour NE PAS exclure, et TÉLÉVERSER ceux-ci également:\n\n',
"u_just1": '\nPeut-être que cela fonctionne mieux si vous sélectionnez juste un fichier',
"u_ff_many": "si vous utilisez <b>Linux / MacOS / Android,</b> alors ce nombre de fichiers <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>peut</em> faire planter Firefox!</a>\nSi cela se produit, veuillez réessayer (ou utiliser Chrome).",
"u_up_life": "Ce téléversement va être supprimé du serveur\n{0} après son achèvement",
"u_asku": 'téléverser ces {0} fichiers vers <code>{1}</code>',
"u_unpt": "vous pouvez défaire / supprimer ce téléversement en utilisant le 🧯 en haut à gauche",
"u_bigtab": 'sur le point d\'afficher {0} fichiers\n\ncela peut faire planter votre navigateur, êtes-vous sûr ?',
"u_scan": 'Analyse des fichiers…',
"u_dirstuck": 'l\'itérateur de répertoire est bloqué en essayant d\'accéder aux {0} éléments suivants ; il sera ignoré :',
"u_etadone": 'Terminé ({0}, {1} fichiers)',
"u_etaprep": '(préparation au téléversement)',
"u_hashdone": 'calcul de la somme de contrôle terminé',
"u_hashing": 'calcul de la somme de contrôle',
"u_hs": 'établissement d\'une liaison…',
"u_started": "les fichiers sont maintenant en cours de téléversement ; voir [🚀]",
"u_dupdefer": "dupliqué ; sera traité après tous les autres fichiers",
"u_actx": "cliquez sur ce texte pour éviter la perte de<br />performance lors du passage à d'autres fenêtres/onglets",
"u_fixed": "OK!&nbsp; Résolu 👍",
"u_cuerr": "echec du téléversement du morceau {0} de {1};\nprobablement inoffensif, poursuite\n\nfichier : {2}",
"u_cuerr2": "le serveur a rejeté le téléversement (morceau {0} de {1});\nréessaiera plus tard\n\nfichier : {2}\n\nerreur ",
"u_ehstmp": "réessaiera ; voir en bas à droite",
"u_ehsfin": "le serveur a rejeté la demande de finalisation du téléversement ; nouvelle tentative…",
"u_ehssrch": "le serveur a rejeté la demande d'effectuer une recherche ; nouvelle tentative…",
"u_ehsinit": "le serveur a rejeté la demande d'initier le téléversement ; nouvelle tentative…",
"u_eneths": "erreur réseau lors de l'exécution de l'initialisation du téléversement ; nouvelle tentative…",
"u_enethd": "erreur réseau lors du test de l'existence de la cible ; nouvelle tentative…",
"u_cbusy": "attente que le serveur nous fasse à nouveau confiance après un problème réseau…",
"u_ehsdf": "le serveur est à court d'espace disque !\n\nil va continuer de réessayer, au cas où quelqu'un\nlibérerait suffisamment d'espace pour continuer",
"u_emtleak1": "il semble que votre navigateur web ait une fuite de mémoire ;\nveuillez",
"u_emtleak2": ' <a href="{0}">passer à https (recommandé)</a> ou ',
"u_emtleak3": ' ',
"u_emtleakc": 'essayez la solution suivante:\n<ul><li>appuyez sur <code>F5</code> pour rafraîchir la page</li><li>ensuite désactivez le bouton &nbsp;<code>mt</code>&nbsp; dans les &nbsp;<code>⚙️ paramètres</code></li><li>et réessayez ce téléversement</li></ul>Les téléversements seront un peu plus lents, mais tant pis.\nDésolé pour le dérangement !\n\nPS : chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">a un correctif</a> pour cela',
"u_emtleakf": 'essayez la solution suivante:\n<ul><li>appuyez sur <code>F5</code> pour rafraîchir la page</li><li>ensuite activez <code>🥔</code> (pomme de terre) dans l\'interface de téléversement</li><li>et réessayez ce téléversement</li></ul>\nPS : firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">aura probablement un correctif</a> à un moment donné',
"u_s404": "pas trouvé sur le serveur",
"u_expl": "expliquer",
"u_maxconn": "la plupart des navigateur limite ceci à 6, mais firefox vous permet de l'augmenter avec <code>connections-per-server</code> dans <code>about:config</code>",
"u_tu": '<p class="warn">WARNING: turbo enclenché, <span>&nbsp;le client peut ne pas détecter et reprendre les téléversements incomplets ; voir l\'info-bulle du bouton turbo</span></p>',
"u_ts": '<p class="warn">WARNING: turbo enclenché, <span>&nbsp;les résultats de recherche peuvent être incorrects ; voir l\'info-bulle du bouton turbo</span></p>',
"u_turbo_c": "turbo est désactivé dans la configuration du serveur",
"u_turbo_g": "désactivation de turbo car vous n'avez pas de\nprivilèges de listing de répertoires dans ce volume",
"u_life_cfg": 'suppression automatique après <input id="lifem" p="60" /> min (ou <input id="lifeh" p="3600" /> heures)',
"u_life_est": 'le téléversement sera supprimé <span id="lifew" tt="local time">---</span>',
"u_life_max": 'ce dossier impose une\ndurée de vie maximale de {0}',
"u_unp_ok": 'unpost est autorisé pour {0}',
"u_unp_ng": 'unpost ne sera PAS autorisé',
"ue_ro": 'votre accès à ce dossier est en lecture seule\n\n',
"ue_nl": 'vous n\'êtes actuellement pas connecté',
"ue_la": 'vous êtes actuellement connecté en tant que "{0}"',
"ue_sr": 'vous êtes actuellement en mode recherche de fichiers\n\nchangez en mode téléversement en cliquant sur la loupe 🔎 (à côté du grand bouton RECHERCHER), et essayez de téléverser à nouveau\n\ndésolé',
"ue_ta": 'essayez de téléverser à nouveau, cela devrait fonctionner maintenant',
"ue_ab": "ce fichier a déjà été téléversé dans un autre dossier, et ce téléversement doit être terminé avant que le fichier puisse être téléversé ailleurs.\n\nVous pouvez annuler et oublier le téléversement initial en utilisant le bouton 🧯 en haut à gauche.",
"ur_1uo": "OK: Fichier téléversé avec succès",
"ur_auo": "OK: Tous les {0} fichiers téléversés avec succès",
"ur_1so": "OK: Fichier trouvé sur le serveur",
"ur_aso": "OK: Tous les {0} fichiers trouvés sur le serveur",
"ur_1un": "Échec du téléversement, désolé",
"ur_aun": "Tous les {0} téléversements ont échoué, désolé",
"ur_1sn": "Fichier NON trouvé sur le serveur",
"ur_asn": "Les {0} fichiers n'ont PAS ÉTÉ trouvés sur le serveur",
"ur_um": "Terminé;\n{0} téléversements OK,\n{1} téléversements échoués, désolé",
"ur_sm": "Terminé;\n{0} fichiers trouvés sur le serveur,\n{1} fichiers NON trouvés sur le serveur",
"rc_opn": "ouvrir", //m
"rc_ply": "Lire", //m
"rc_pla": "Lire comme audio", //m
"rc_txt": "ouvrir dans le visionneur de fichiers", //m
"rc_md": "ouvrir dans léditeur de texte", //m
"rc_dl": "télécharger", //m
"rc_zip": "télécharger comme archive", //m
"rc_del": "supprimer", //m
"rc_cut": "couper", //m
"rc_cpy": "copier", //m
"rc_pst": "coller", //m
"rc_nfo": "nouveau dossier", //m
"rc_nfi": "nouveau fichier", //m
"rc_sal": "tout sélectionner", //m
"rc_sin": "inverser la sélection", //m
"lang_set": "rafraîchir pour que les changements prennent effet ?",
"splash": {
"a1": "rafraîchir",
"b1": "salut étranger &nbsp; <small>(vous n'êtes pas connecté.)</small>",
"c1": "déconnexion",
"d1": "vidange de la pile",
"d2": "affiche l'état de tous les threads actifs",
"e1": "recharger la configuration",
"e2": "recharger le fichier de configuration (comptes/volumes/indicateurs de volume),$Net rescanner tous les volumes e2ds$N$Nnote : n'importe quel changement aux paramètres globaux$Nnécessite un redémarrage complet pour prendre effet",
"f1": "vous pouvez naviguer :",
"g1": "vous pouvez télécharger sur :",
"cc1": "autres choses :",
"h1": "désactiver k304",
"i1": "activer k304",
"j1": "activer k304 va déconnecter votre client sur chaque HTTP 304, ce qui peut éviter à certains proxies défectueux de rester bloqués (les pages ne se chargent soudainement plus), <em>mais</em> cela ralentira également les choses en général",
"k1": "réinitialiser les paramètres du client",
"l1": "connectez-vous pour en savoir plus :",
"ls3": "se connecter", //m
"lu4": "nom d'utilisateur", //m
"lp4": "mot de passe", //m
"lo3": "déconnecter “{0}” partout", //m
"lo2": "cela mettra fin à la session sur tous les navigateurs", //m
"m1": "heureux de vous revoir,",
"n1": "404 introuvable &nbsp;┐( ´ -`)┌",
"o1": 'ou peut-être que vous n\'y avez pas accès -- essayer un mot de passe ou <a href="' + SR + '/?h">aller à la page d\'accueil</a>',
"p1": "403 interdit &nbsp;~┻━┻",
"q1": 'utiliser un mot de passe ou <a href="' + SR + '/?h">aller à la page d\'accueil</a>',
"r1": "aller à la page d\'accueil",
".s1": "rescanner",
"t1": "action",
"u2": "temps écoulé depuis la dernière écriture sur le serveur$N(téléchargement/renommage/...)$N$N17j = 17 jours$N1h23 = 1 heure 23 minutes$N4m56 = 4 minutes 56 secondes",
"v1": "connecter",
"v2": "utilisez ce serveur en tant que disque dur local",
"w1": "passer à https",
"x1": "changer mot de passe",
"y1": "modifier les partages",
"z1": "déverrouiller ce partage :",
"ta1": "entrez d'abord votre nouveau mot de passe",
"ta2": "répétez pour confirmer le nouveau mot de passe :",
"ta3": "une faute de frappe a été détectée ; veuillez réessayer.",
"nop": "ERREUR : Le mot de passe ne peut pas être vide", //m
"nou": "ERREUR : Le nom dutilisateur et/ou le mot de passe ne peut pas être vide", //m
"aa1": "fichiers entrants :",
"ab1": "désactiver no304",
"ac1": "activer no304",
"ad1": "l'activation de no304 désactivera toute mise en cache ; essayez ceci si k304 n'était pas suffisant. Cela va générer un trafic réseau considérable !",
"ae1": "téléchargements actifs :",
"af1": "afficher les derniers téléchargements",
"ag1": "afficher les utilisateurs IdP connus", //m
}
};

710
copyparty/web/tl/grc.js Normal file
View file

@ -0,0 +1,710 @@
// Οι γραμμές που τελειώνουν με //m είναι μη επαληθευμένες μηχανικές μεταφράσεις
Ls.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", "επιλογή αρχείου (για αποκοπή/αντιγραφή/μετονομασία)"],
["Y", "λήψη αρχείου κειμένου"], //m
["⇧ J", "ομορφοποίηση json"], //m
]
],
"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": "Αποσύνδεση ",
"login": "Σύνδεση", //m
"access": " πρόσβαση",
"ot_close": "κλείσιμο υπομενού",
"ot_search": "αναζήτηση αρχείων με βάση χαρακτηριστικά, διαδρομή / όνομα, μουσικά tags ή οποιονδήποτε συνδυασμό$N$N&lt;code&gt;foo bar&lt;/code&gt; = πρέπει να περιέχει και τα «foo» και «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = πρέπει να περιέχει το «foo» αλλά όχι το «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = να ξεκινά με «yana» και να είναι αρχείο «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = να περιέχει ακριβώς «try unite»$N$Nη μορφή ημερομηνίας είναι iso-8601, όπως$N&lt;code&gt;2009-12-31&lt;/code&gt; ή &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: διαγραφή πρόσφατων μεταφορτώσεων ή ακύρωση ανολοκλήρωτων",
"ot_bup": "bup: βασικός uploader, υποστηρίζει μέχρι και netscape 4.0",
"ot_mkdir": "mkdir: δημιουργία νέου φακέλου",
"ot_md": "new-file: δημιουργία νέου αρχείου κειμένου", //m
"ot_msg": "msg: αποστολή μηνύματος στο server log",
"ot_mp": "επιλογές media player",
"ot_cfg": "επιλογές ρυθμίσεων",
"ot_u2i": 'up2k: ανέβασε αρχεία (αν έχεις δικαίωμα εγγραφής) ή ενεργοποίησε τη λειτουργία αναζήτησης για να δεις αν υπάρχουν ήδη στο server$N$Nοι μεταφορτώσεις συνεχίζονται αν διακοπούν, είναι πολυνηματικές και διατηρούν τις χρονοσφραγίδες, αλλά καταναλώνουν περισσότερο CPU από τον [🎈]&nbsp; (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!',
"ot_u2w": 'up2k: ανέβασε αρχεία με υποστήριξη συνέχισης (κλείσε τον browser και ρίξε τα ίδια αρχεία ξανά μετά)$N$Nπολυνηματικό, διατηρεί τις χρονοσφραγίδες, αλλά καταναλώνει περισσότερο CPU από τον [🎈]&nbsp; (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!',
"ot_noie": 'Χρησιμοποίησε Chrome / Firefox / Edge',
"ab_mkdir": "δημιουργία φακέλου",
"ab_mkdoc": "νέο αρχείο κειμένου", //m
"ab_msg": "στείλε μήνυμα στο server log",
"ay_path": "πήγαινε σε φακέλους",
"ay_files": "πήγαινε σε αρχεία",
"wt_ren": "μετονομασία επιλεγμένων$NΣυντόμευση: F2",
"wt_del": "διαγραφή επιλεγμένων$NΣυντόμευση: ctrl-K",
"wt_cut": "αποκοπή επιλεγμένων &lt;small&gt;(και επικόλληση αλλού)&lt;/small&gt;$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♻: πάντα να αντικαθίστανται αν διαφέρουν$N⏭: παράλειψη όλων των υπαρχόντων αρχείων χωρίς όρους", //m
"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": "μέση ταχύτητα &lt;em&gt;υπολογισμού hash&lt;/em&gt; και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
"ut_etau": "μέση ταχύτητα &lt;em&gt;μεταφόρτωσης&lt;/em&gt; και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
"ut_etat": "μέση &lt;em&gt;συνολική&lt;/em&gt; ταχύτητα και εκτίμηση χρόνου μέχρι την ολοκλήρωση",
"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_hfsz": "μέγεθος αρχείου", //m
"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": "η απόκρυψη στηλών ακυρώθηκε",
"cl_rcm": "μενού δεξιού κλικ", //m
"ct_grid": '田 το πλέγμα',
"ct_ttips": '◔ ◡ ◔"> συμβουλές εργαλείων',
"ct_thumb": 'σε προβολή πλέγματος, εναλλαγή εικονιδίων ή μικρογραφιών$NΠλήκτρο συντόμευσης: T">🖼️ μικρογραφίες',
"ct_csel": 'χρησιμοποίησε CTRL και SHIFT για επιλογή αρχείων σε προβολή πλέγματος">επιλογή',
"ct_dl": 'εξαναγκασμός λήψης (να μην εμφανίζεται ενσωματωμένα) όταν γίνεται κλικ σε ένα αρχείο">dl', //m
"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>&quot;έχει το ίδιο μέγεθος αρχείου στον server?&quot;</em> οπότε αν το περιεχόμενο είναι διαφορετικό, ΔΕΝ θα ανέβει$N$Nπρέπει να το κλείσεις όταν τελειώσει η μεταφόρτωση και μετά να &quot;μεταφορτώσεις&quot; πάλι τα ίδια αρχεία για να τα επιβεβαιώσει το τοπικό σου πρόγραμμα\">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": "πόσους κανόνες ταξινόμησης (&lt;code&gt;,sorthref&lt;/code&gt;) να συμπεριλάβει σε URLs πολυμέσων. Αν το βάλεις 0 αγνοεί και κανόνες ταξινόμησης στους συνδέσμους πολυμέσων",
"cdt_ren": "ενεργοποίηση προσαρμοσμένου μενού δεξιού κλικ, το κανονικό μενού είναι προσβάσιμο με shift + δεξί κλικ", //m
"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&nbsp; είναι στην αριστερή στήλη )",
"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": "καθάρισε την προσωρινή μνήμη &nbsp;(δοκίμασε αυτό αν ο browser έχει αποθηκεύσει$Nχαλασμένο αντίγραφο τραγουδιού και αρνείται να παίξει)\">εκκαθάριση",
"mt_mloop": "τυχαία αναπαραγωγή στον ανοικτό φάκελο\">🔁 τυχαία αναπαραγωγή",
"mt_mnext": "φόρτωση επόμενου φακέλου και συνέχιση\">📂 επόμενο",
"mt_mstop": "σταμάτησε την αναπαραγωγή\">⏸ σταμάτημα",
"mt_cflac": "μετατροπή flac / wav σε {0}\">flac",
"mt_caac": "μετατροπή aac / m4a σε {0}\">aac",
"mt_coth": "μετατροπή όλων των άλλων (εκτός των mp3) σε {0}\">άλλο",
"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ενίσχυση &lt;code&gt;0&lt;/code&gt; = στάνταρ 100% ένταση (απαράλλαχτη)$N$Nεύρος &lt;code&gt;1 &nbsp;&lt;/code&gt; = στάνταρ στερεοφωνικό (απαράλλαχτο)$Nεύρος &lt;code&gt;0.5&lt;/code&gt; = 50% αριστερά-δεξιά μίξη ήχου$Nεύρος &lt;code&gt;0 &nbsp;&lt;/code&gt; = μονοφωνικό$N$Nενίσχυση &lt;code&gt;-0.8&lt;/code&gt; &amp; εύρος &lt;code&gt;10&lt;/code&gt; = αφαίρεση φωνής :^)$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/Εντάξει</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Πάτα Εντάξει / 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/Εντάξει</code> για Πρόχειρο\nπάτα <code>ESC/Άκυρο</code> για Κλείσιμο",
"frt_dec": "μπορεί να διορθώσει μερικές περιπτώσεις κατεστραμμένων ονομάτων αρχείων\">αποκωδικοποίηση url",
"frt_rst": "επανέφερε τα ονόματα αρχείων στα αρχικά τους\">↺ επαναφορά",
"frt_abrt": "ακύρωσε και κλείσε αυτό το παράθυρο\">❌ ακύρωση",
"frb_apply": "ΕΦΑΡΜΟΓΗ ΜΕΤΟΝΟΜΑΣΙΑΣ",
"fr_adv": "μαζική / μεταδεδομένα / μετονομασία με πρότυπα\">προχωρημένη",
"fr_case": "regex με διάκριση πεζών/κεφαλαίων\">case",
"fr_win": "ασφαλή ονόματα για windows; αντικαθιστά <code>&lt;&gt;:&quot;\\|?*</code> με ιαπωνικούς χαρακτήρες πλήρους πλάτους\">win",
"fr_slash": "αντικαθίσταται <code>/</code> με χαρακτήρα που δεν δημιουργεί νέους φακέλους\">όχι /",
"fr_re": "μοτίβα αναζήτησης (regex) για αναζήτηση στα αρχικά ονόματα; τα καταγραφόμενα groups μπορούν να χρησιμοποιηθούν στο πεδίο μορφοποίησης παρακάτω όπως &lt;code&gt;(1)&lt;/code&gt; και &lt;code&gt;(2)&lt;/code&gt; και ούτω καθεξής",
"fr_fmt": "εμπνευσμένο από foobar2000:$N&lt;code&gt;(title)&lt;/code&gt; αντικαθίσταται από τίτλο τραγουδιού,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; παραλείπει το [this] αν το artist είναι κενό$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; γεμίζει τον αριθμό κομματιού σε 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_skip": "αγνόησε συγκρούσεις", //m
"fp_ecut": "πρώτα κάνε αποκοπή ή αντιγραφή κάποιων αρχείων / φακέλων για επικόλληση / μετακίνηση\n\nσημείωση: μπορείς να αποκόπτεις / επικολλάς ανάμεσα σε διαφορετικές καρτέλες browser",
"fp_ename": "τα {0} αντικείμενα δεν μπορούν να μετακινηθούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό (\"αγνόησε συγκρούσεις\") για να τα αγνοήσεις:", //m
"fcp_ename": "τα {0} αντικείμενα δεν μπορούν να αντιγραφούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό (\"αγνόησε συγκρούσεις\") για να τα αγνοήσεις:", //m
"fp_emore": "υπάρχουν ακόμα συγκρούσεις ονομάτων που πρέπει να διορθωθούν",
"fp_ok": "μετακίνηση OK",
"fcp_ok": "αντιγραφή OK",
"fp_busy": "μετακίνηση {0} αντικειμένων...\n\n{1}",
"fcp_busy": "αντιγραφή {0} αντικειμένων...\n\n{1}",
"fp_abrt": "γίνεται ακύρωση...", //m
"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",
"nmd_i1": "μπορείτε επίσης να προσθέσετε την κατάληξη που θέλετε, όπως <code>.md</code>", //m
"nmd_i2": "μπορείτε να δημιουργήσετε μόνο αρχεία <code>.md</code> επειδή δεν έχετε δικαίωμα διαγραφής", //m
"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": "επέλεξε αρχείο &nbsp; (για αποκοπή / αντιγραφή / διαγραφή / ...)$NΣυντόμευση: S\">επιλογή",
"tvt_j": "ομορφοποίηση json$NΣυντόμευση: shift-J\">j", //m
"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&lt;em&gt;όταν είναι ενεργό: διπλό κλικ σε αρχείο / φάκελο το ανοίγει&lt;/em&gt;$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": "το μονοπάτι περιέχει &nbsp; (χωρισμένα με κενό)",
"s_f1": "το όνομα περιέχει &nbsp; (άρνηση με -nope)",
"s_t1": "οι ετικέτες περιέχουν &nbsp; (^=αρχή, τέλος=$)",
"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": "προαιρετικό φίλτρο:&nbsp; η διεύθυνση πρέπει να περιέχει",
"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&amp;drop μεταφορτώσεις",
"u_notdir": "αυτός δεν είναι φάκελος!\n\nο browser σου είναι πολύ παλιός,\nδοκίμασε drag&amp;drop αντ' αυτού",
"u_uri": "για να κάνεις drag&amp;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>αρχεία: &nbsp; <b>{0}</b> ολοκληρωμένα, &nbsp; <b>{1}</b> αποτυχημένα, &nbsp; <b>{2}</b> σε εξέλιξη, &nbsp; <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>Εντάξει/Enter</code> για ΝΑ ΑΓΝΟΗΘΟΥΝ τα παρακάτω αρχεία,\nΠάτα <code>Άκυρο/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": "ΟΚ!&nbsp; Το διόρθωσα 👍",
"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>μετά απενεργοποίησε το &nbsp;<code>mt</code>&nbsp; κουμπί στις &nbsp;<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>&nbsp;το πρόγραμμα πελάτη ίσως να μην ανιχνεύσει και να μην ξαναεκκινήσει μισοτελειωμένες μεταφορτώσεις; δες τα tooltip του κουμπιού turbo</span></p>',
"u_ts": '<p class="warn">ΠΡΟΕΙΔΟΠΟΙΗΣΗ: το turbo είναι ενεργοποιημένο, <span>&nbsp;τα αποτελέσματα αναζήτησης μπορεί να είναι λάθος; δες τα 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} αρχεία ΔΕΝ βρέθηκαν στο διακομιστή",
"rc_opn": "άνοιγμα", //m
"rc_ply": "αναπαραγωγή", //m
"rc_pla": "αναπαραγωγή ως ήχος", //m
"rc_txt": "άνοιγμα στον προβολέα αρχείων", //m
"rc_md": "άνοιγμα στον επεξεργαστή κειμένου", //m
"rc_dl": "λήψη", //m
"rc_zip": "λήψη ως αρχείο", //m
"rc_del": "διαγραφή", //m
"rc_cut": "αποκοπή", //m
"rc_cpy": "αντιγραφή", //m
"rc_pst": "επικόλληση", //m
"rc_nfo": "νέος φάκελος", //m
"rc_nfi": "νέο αρχείο", //m
"rc_sal": "επιλογή όλων", //m
"rc_sin": "αντιστροφή επιλογής", //m
"lang_set": "ανανέωση σελίδας για εφαρμογή της αλλαγής;",
"splash": {
"a1": "ανανέωση",
"b1": "γεια σου ξένε! &nbsp; <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": "συνδέσου για περισσότερα:",
"ls3": "σύνδεση", //m
"lu4": "όνομα χρήστη", //m
"lp4": "κωδικός πρόσβασης", //m
"lo3": "αποσύνδεση του “{0}” από παντού", //m
"lo2": "αυτό θα τερματίσει τη συνεδρία σε όλους τους περιηγητές", //m
"m1": "καλώς ήρθες,",
"n1": "404 δεν βρέθηκε &nbsp;┐( ´ -`)┌",
"o1": '´η μήπως δεν έχεις πρόσβαση -- δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>',
"p1": "403 απαγορευμένο &nbsp;~┻━┻",
"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": "βρέθηκε τυπογραφικό λάθος· δοκίμασε ξανά",
"nop": "ΣΦΑΛΜΑ: Ο κωδικός πρόσβασης δεν μπορεί να είναι κενός", //m
"nou": "ΣΦΑΛΜΑ: Το όνομα χρήστη και/ή ο κωδικός πρόσβασης δεν μπορεί να είναι κενό", //m
"aa1": "εισερχόμενα αρχεία:",
"ab1": "απενεργοποίηση no304",
"ac1": "ενεργοποίηση no304",
"ad1": "η ενεργοποίηση του no304 θα απενεργοποιήσει όλη την προσωρινή αποθήκευση· δοκίμασέ το αν το k304 δεν ήταν αρκετό. Προσοχή, θα σπαταλήσει τεράστιο όγκο δικτυακής κίνησης!",
"ae1": "ενεργές μεταφορτώσεις:",
"af1": "προβολή πρόσφατων μεταφορτώσεων",
"ag1": "εμφάνιση γνωστών χρηστών IdP", //m
}
};

710
copyparty/web/tl/ita.js Normal file
View file

@ -0,0 +1,710 @@
// Le righe che terminano con //m sono traduzioni automatiche non verificate
Ls.ita = {
"tt": "Italiano",
"cols": {
"c": "pulsanti azione",
"dur": "durata",
"q": "qualità / bitrate",
"Ac": "codec audio",
"Vc": "codec video",
"Fmt": "formato / container",
"Ahash": "checksum audio",
"Vhash": "checksum video",
"Res": "risoluzione",
"T": "tipo file",
"aq": "qualità audio / bitrate",
"vq": "qualità video / bitrate",
"pixfmt": "subsampling / struttura pixel",
"resw": "risoluzione orizzontale",
"resh": "risoluzione verticale",
"chs": "canali audio",
"hz": "frequenza di campionamento",
},
"hks": [
[
"varie",
["ESC", "chiudi vari elementi"],
"file-manager",
["G", "alterna vista lista / griglia"],
["T", "alterna miniature / icone"],
["⇧ A/D", "dimensione miniature"],
["ctrl-K", "elimina selezionati"],
["ctrl-X", "taglia selezione negli appunti"],
["ctrl-C", "copia selezione negli appunti"],
["ctrl-V", "incolla (sposta/copia) qui"],
["Y", "scarica selezionati"],
["F2", "rinomina selezionati"],
"file-list-sel",
["spazio", "alterna selezione file"],
["↑/↓", "sposta cursore selezione"],
["ctrl ↑/↓", "sposta cursore e viewport"],
["⇧ ↑/↓", "seleziona file prec/succ"],
["ctrl-A", "seleziona tutti i file / cartelle"],
], [
"navigation",
["B", "alterna breadcrumb / pannello nav"],
["I/K", "cartella prec/succ"],
["M", "cartella genitore (o comprimi corrente)"],
["V", "alterna cartelle / file di testo nel pannello nav"],
["A/D", "dimensione pannello nav"],
], [
"audio-player",
["J/L", "brano prec/succ"],
["U/O", "salta 10sec indietro/avanti"],
["0..9", "salta a 0%..90%"],
["P", "play/pausa (avvia anche)"],
["S", "seleziona brano in riproduzione"],
["Y", "scarica brano"],
], [
"image-viewer",
["J/L, ←/→", "immagine prec/succ"],
["Home/End", "prima/ultima immagine"],
["F", "schermo intero"],
["R", "ruota in senso orario"],
["⇧ R", "ruota in senso antiorario"],
["S", "seleziona immagine"],
["Y", "scarica immagine"],
], [
"video.player",
["U/O", "salta 10sec indietro/avanti"],
["P/K/Spazio", "play/pausa"],
["C", "continua riproduzione successivo"],
["V", "loop"],
["M", "muto"],
["[ e ]", "imposta intervallo loop"],
], [
"textfile-viewer",
["I/K", "file prec/succ"],
["M", "chiudi file di testo"],
["E", "modifica file di testo"],
["S", "seleziona file (per taglia/copia/rinomina)"],
["Y", "scarica il file di testo"], //m
["⇧ J", "abbellire json"], //m
]
],
"m_ok": "OK",
"m_ng": "Annulla",
"enable": "Abilita",
"danger": "PERICOLO",
"clipped": "copiato negli appunti",
"ht_s1": "secondo",
"ht_s2": "secondi",
"ht_m1": "minuto",
"ht_m2": "minuti",
"ht_h1": "ora",
"ht_h2": "ore",
"ht_d1": "giorno",
"ht_d2": "giorni",
"ht_and": " e ",
"goh": "control-panel",
"gop": 'cartella sorella precedente">prec',
"gou": 'cartella genitore">su',
"gon": 'prossima cartella">succ',
"logout": "Logout ",
"login": "Accedi", //m
"access": " accesso",
"ot_close": "chiudi sottomenu",
"ot_search": "cerca file per attributi, percorso / nome, tag musicali, o qualsiasi combinazione di questi$N$N&lt;code&gt;foo bar&lt;/code&gt; = deve contenere sia «foo» che «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = deve contenere «foo» ma non «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = inizia con «yana» ed è un file «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contiene esattamente «try unite»$N$Nil formato data è iso-8601, come$N&lt;code&gt;2009-12-31&lt;/code&gt; o &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
"ot_unpost": "unpost: elimina i tuoi caricamenti recenti, o interrompi quelli non completati",
"ot_bup": "bup: uploader di base, supporta anche netscape 4.0",
"ot_mkdir": "mkdir: crea una nuova directory",
"ot_md": "new-file: crea un nuovo file di testo", //m
"ot_msg": "msg: invia un messaggio al log del server",
"ot_mp": "opzioni lettore multimediale",
"ot_cfg": "opzioni di configurazione",
"ot_u2i": 'up2k: carica file (se hai accesso in scrittura) o attiva la modalità ricerca per vedere se esistono già da qualche parte sul server$N$NI caricamenti sono ripristinabili, multithreaded, e i timestamp dei file vengono preservati, ma usa più CPU di [🎈]&nbsp; (l\'uploader di base)<br /><br />durante i caricamenti, questa icona diventa un indicatore di progresso!',
"ot_u2w": 'up2k: carica file con supporto per il ripristino (chiudi il browser e trascina gli stessi file più tardi)$N$NMultithreaded, e i timestamp dei file vengono preservati, ma usa più CPU di [🎈]&nbsp; (l\'uploader di base)<br /><br />durante i caricamenti, questa icona diventa un indicatore di progresso!',
"ot_noie": 'Perfavore usa Chrome / Firefox / Edge',
"ab_mkdir": "crea directory",
"ab_mkdoc": "nuovo file di testo", //m
"ab_msg": "invia msg al log srv",
"ay_path": "salta alle cartelle",
"ay_files": "salta ai file",
"wt_ren": "rinomina elementi selezionati$NTasto rapido: F2",
"wt_del": "elimina elementi selezionati$NTasto rapido: ctrl-K",
"wt_cut": "taglia elementi selezionati &lt;small&gt;(poi incolla altrove)&lt;/small&gt;$NTasto rapido: ctrl-X",
"wt_cpy": "copia elementi selezionati negli appunti$N(per incollarli altrove)$NTasto rapido: ctrl-C",
"wt_pst": "incolla una selezione precedentemente tagliata / copiata$NTasto rapido: ctrl-V",
"wt_selall": "seleziona tutti i file$NTasto rapido: ctrl-A (quando il file è focalizzato)",
"wt_selinv": "inverti selezione",
"wt_zip1": "scarica questa cartella come archivio",
"wt_selzip": "scarica selezione come archivio",
"wt_seldl": "scarica selezione come file separati$NTasto rapido: Y",
"wt_npirc": "copia info traccia formato irc",
"wt_nptxt": "copia info traccia testo semplice",
"wt_m3ua": "aggiungi alla playlist m3u (clicca <code>📻copia</code> dopo)",
"wt_m3uc": "copia playlist m3u negli appunti",
"wt_grid": "alterna vista griglia / lista$NTasto rapido: G",
"wt_prev": "traccia precedente$NTasto rapido: J",
"wt_play": "play / pausa$NTasto rapido: P",
"wt_next": "traccia successiva$NTasto rapido: L",
"ul_par": "caricamenti paralleli:",
"ut_rand": "randomizza nomi file",
"ut_u2ts": "copia il timestamp di ultima modifica$Ndal tuo filesystem al server\">📅",
"ut_ow": "sovrascrivere file esistenti sul server?$N🛡: mai (genererà un nuovo nome file)$N🕒: sovrascrivi se il file del server è più vecchio del tuo$N♻: sovrascrivi sempre se i file sono diversi$N⏭: ignora sempre tutti i file esistenti", //m
"ut_mt": "continua l'hashing di altri file durante il caricamento$N$NProva a disabilitare se la tua CPU o HDD è un collo di bottiglia",
"ut_ask": 'chiedi conferma prima che inizi il caricamento">💭',
"ut_pot": "migliora la velocità di caricamento su dispositivi lenti$Nrendendo l'interfaccia meno complessa",
"ut_srch": "non caricare realmente, invece controlla se i file esistono già $N sul server (scansionerà tutte le cartelle che puoi leggere)",
"ut_par": "metti in pausa i caricamenti impostandolo a 0$N$NAumenta se la tua connessione è lenta / alta latenza$N$NMantienilo a 1 su LAN o se l'HDD del server è un collo di bottiglia",
"ul_btn": "trascina file / cartelle<br>qui (o cliccami)",
"ul_btnu": "C A R I C A",
"ul_btns": "C E R C A",
"ul_hash": "hash",
"ul_send": "invia",
"ul_done": "fatto",
"ul_idle1": "nessun caricamento ancora in coda",
"ut_etah": "velocità media di &lt;em&gt;hashing&lt;/em&gt;, e tempo stimato al completamento",
"ut_etau": "velocità media di &lt;em&gt;caricamento&lt;/em&gt; e tempo stimato al completamento",
"ut_etat": "velocità &lt;em&gt;totale&lt;/em&gt; media e tempo stimato al completamento",
"uct_ok": "completato con successo",
"uct_ng": "non-valido: fallito / rifiutato / non-trovato",
"uct_done": "ok e ng combinati",
"uct_bz": "hashing o caricamento",
"uct_q": "inattivo, in attesa",
"utl_name": "nome file",
"utl_ulist": "lista",
"utl_ucopy": "copia",
"utl_links": "link",
"utl_stat": "stato",
"utl_prog": "progresso",
// keep short:
"utl_404": "404",
"utl_err": "ERRORE",
"utl_oserr": "Errore-SO",
"utl_found": "trovato",
"utl_defer": "rinvia",
"utl_yolo": "YOLO",
"utl_done": "finito",
"ul_flagblk": "i file sono stati aggiunti alla coda</b><br>tuttavia c'è un up2k occupato in un'altra scheda del browser,<br>quindi aspetto che quello finisca prima",
"ul_btnlk": "la configurazione del server ha bloccato questo interruttore in questo stato",
"udt_up": "Carica",
"udt_srch": "Cerca",
"udt_drop": "lascialo qui",
"u_nav_m": '<h6>ok, cosa hai?</h6><code>Invio</code> = File (uno o più)\n<code>ESC</code> = Una cartella (incluse sottocartelle)',
"u_nav_b": '<a href="#" id="modal-ok">File</a><a href="#" id="modal-ng">Una cartella</a>',
"cl_opts": "opzioni",
"cl_hfsz": "dimensione file", //m
"cl_themes": "tema",
"cl_langs": "lingua",
"cl_ziptype": "download cartella",
"cl_uopts": "opzioni up2k",
"cl_favico": "favicon",
"cl_bigdir": "cartelle grandi",
"cl_hsort": "#ordinamento",
"cl_keytype": "notazione tasti",
"cl_hiddenc": "colonne nascoste",
"cl_hidec": "nascondi",
"cl_reset": "reset",
"cl_hpick": "tocca le intestazioni delle colonne per nascondere nella tabella sottostante",
"cl_hcancel": "nascondere colonne annullato",
"cl_rcm": "menu contestuale", //m
"ct_grid": '田 griglia',
"ct_ttips": '◔ ◡ ◔"> tooltip',
"ct_thumb": 'nella vista griglia, alterna icone o miniature$NTasto rapido: T">🖼️ miniature',
"ct_csel": 'usa CTRL e SHIFT per la selezione file nella vista griglia">sel',
"ct_dl": 'forza il download (non visualizzare inline) quando si clicca su un file">dl', //m
"ct_ihop": 'quando il visualizzatore immagini è chiuso, scorri fino all\'ultimo file visualizzato">g⮯',
"ct_dots": 'mostra file nascosti (se il server lo permette)">dotfile',
"ct_qdel": 'quando elimini file, chiedi conferma solo una volta">qdel',
"ct_dir1st": 'ordina cartelle prima dei file">📁 prima',
"ct_nsort": 'ordinamento naturale (per nomi file con cifre iniziali)">nsort',
"ct_utc": 'mostra tutte le date/ore in UTC">UTC',
"ct_readme": 'mostra README.md negli elenchi cartelle">📜 readme',
"ct_idxh": 'mostra index.html invece dell\'elenco cartelle">htm',
"ct_sbars": 'mostra barre di scorrimento">⟊',
"cut_umod": "se un file esiste già sul server, aggiorna il timestamp di ultima modifica del server per farlo coincidere con il tuo file locale (richiede permessi di scrittura+eliminazione)\">re📅",
"cut_turbo": "il pulsante yolo, probabilmente NON lo vuoi abilitare:$N$NUsalo se stavi caricando una grande quantità di file e hai dovuto riavviare per qualche motivo, e vuoi continuare il caricamento il prima possibile$N$NQuesto sostituisce il controllo hash con un semplice <em>&quot;questo ha la stessa dimensione file sul server?&quot;</em> quindi se il contenuto del file è diverso NON verrà caricato$N$NDovresti spegnere questo quando il caricamento è finito, e poi &quot;caricare&quot; di nuovo gli stessi file per far verificare al client\">turbo",
"cut_datechk": "non ha effetto a meno che il pulsante turbo sia abilitato$N$NRiduce il fattore yolo di una piccola quantità; controlla se i timestamp dei file sul server corrispondono ai tuoi$N$NDovrebbe <em>teoricamente</em> catturare la maggior parte dei caricamenti non finiti / corrotti, ma non è un sostituto per fare un passaggio di verifica con turbo disabilitato dopo\">date-chk",
"cut_u2sz": "dimensione (in MiB) di ogni chunk di caricamento; valori grandi volano meglio attraverso l'atlantico. Prova valori bassi su connessioni molto inaffidabili",
"cut_flag": "assicura che solo una scheda stia caricando alla volta $N -- anche le altre schede devono avere questo abilitato $N -- influisce solo sulle schede dello stesso dominio",
"cut_az": "carica file in ordine alfabetico, invece che dal file più piccolo prima$N$NL'ordine alfabetico può rendere più facile controllare a occhio se qualcosa è andato storto sul server, ma rende il caricamento leggermente più lento su fibra / LAN",
"cut_nag": "notifica SO quando il caricamento si completa$N(solo se il browser o la scheda non è attiva)",
"cut_sfx": "allarme sonoro quando il caricamento si completa$N(solo se il browser o la scheda non è attiva)",
"cut_mt": "usa multithreading per accelerare l'hashing dei file$N$NQuesto usa web-worker e richiede$Npiù RAM (fino a 512 MiB extra)$N$NRende https 30% più veloce, http 4.5x più veloce\">mt",
"cut_wasm": "usa wasm invece dell'hasher integrato del browser; migliora la velocità sui browser basati su chrome ma aumenta il carico CPU, e molte versioni vecchie di chrome hanno bug che fanno consumare tutta la RAM al browser e crashare se questo è abilitato\">wasm",
"cft_text": "testo favicon (vuoto e aggiorna per disabilitare)",
"cft_fg": "colore primo piano",
"cft_bg": "colore sfondo",
"cdt_lim": "numero massimo di file da mostrare in una cartella",
"cdt_ask": "quando scorri verso il fondo,$Ninvece di caricare più file,$Nchiedi cosa fare",
"cdt_hsort": "quante regole di ordinamento (&lt;code&gt;,sorthref&lt;/code&gt;) includere negli URL multimediali. Impostandolo a 0 ignorerà anche le regole di ordinamento incluse nei link multimediali quando li clicchi",
"cdt_ren": "abilita il menu contestuale personalizzato, il menu normale è accessibile con shift + clic destro", //m
"tt_entree": "mostra pannello nav (barra laterale albero directory)$NTasto rapido: B",
"tt_detree": "mostra breadcrumb$NTasto rapido: B",
"tt_visdir": "scorri alla cartella selezionata",
"tt_ftree": "alterna albero cartelle / file di testo$NTasto rapido: V",
"tt_pdock": "mostra cartelle genitore in un pannello ancorato in alto",
"tt_dynt": "crescita automatica mentre l'albero si espande",
"tt_wrap": "a capo parola",
"tt_hover": "rivela righe che traboccano al passaggio del mouse$N( interrompe lo scorrimento a meno che il cursore $N&nbsp; del mouse non sia nella grondaia sinistra )",
"ml_pmode": "alla fine della cartella...",
"ml_btns": "comandi",
"ml_tcode": "transcodifica",
"ml_tcode2": "transcodifica in",
"ml_tint": "tinta",
"ml_eq": "equalizzatore audio",
"ml_drc": "compressore gamma dinamica",
"mt_loop": "loop/ripeti una canzone\">🔁",
"mt_one": "fermati dopo una canzone\">1⃣",
"mt_shuf": "mescola le canzoni in ogni cartella\">🔀",
"mt_aplay": "autoplay se c'è un song-ID nel link che hai cliccato per accedere al server$N$NDisabilitando questo fermerà anche l'aggiornamento dell'URL della pagina con song-ID quando riproduci musica, per prevenire autoplay se queste impostazioni vengono perse ma l'URL rimane\">a▶",
"mt_preload": "inizia a caricare la prossima canzone verso la fine per riproduzione senza interruzioni\">preload",
"mt_prescan": "vai alla prossima cartella prima che finisca l'ultima canzone$Nmantenendo felice il browser web$Ncosì non si ferma la riproduzione\">nav",
"mt_fullpre": "prova a precaricare l'intera canzone;$N✅ abilita su connessioni <b>inaffidabili</b>,$N❌ <b>disabilita</b> su connessioni lente probabilmente\">full",
"mt_fau": "sui telefoni, previeni che la musica si fermi se la prossima canzone non si precarica abbastanza velocemente (può rendere glitchy la visualizzazione dei tag)\">☕️",
"mt_waves": "barra di ricerca forma d'onda:$Nmostra ampiezza audio nello scrubber\">~s",
"mt_npclip": "mostra pulsanti per copiare negli appunti la canzone attualmente in riproduzione\">/np",
"mt_m3u_c": "mostra pulsanti per copiare negli appunti le$Ncanzoni selezionate come voci playlist m3u8\">📻",
"mt_octl": "integrazione so (tasti multimediali / osd)\">os-ctl",
"mt_oseek": "permetti ricerca attraverso integrazione so$N$Nnota: su alcuni dispositivi (iPhone),$Nquesto sostituisce il pulsante canzone successiva\">seek",
"mt_oscv": "mostra copertina album in osd\">art",
"mt_follow": "mantieni la traccia in riproduzione scorrevole nella vista\">🎯",
"mt_compact": "controlli compatti\">⟎",
"mt_uncache": "pulisci cache &nbsp;(prova ad attivare se il tuo browser ha messo in cache$Nuna copia rotta di una canzone e si rifiuta di riprodurla)\">uncache",
"mt_mloop": "loop della cartella aperta\">🔁 loop",
"mt_mnext": "carica la prossima cartella e continua\">📂 succ",
"mt_mstop": "ferma riproduzione\">⏸ stop",
"mt_cflac": "converti flac / wav in {0}\">flac",
"mt_caac": "converti aac / m4a in {0}\">aac",
"mt_coth": "converti tutti gli altri (non mp3) in {0}\">oth",
"mt_c2opus": "scelta migliore per desktop, laptop, android\">opus",
"mt_c2owa": "opus-weba, per iOS 17.5 e più recenti\">owa",
"mt_c2caf": "opus-caf, per iOS 11 fino a 17\">caf",
"mt_c2mp3": "usa questo su dispositivi molto vecchi\">mp3",
"mt_c2flac": "qualità audio migliore, ma download pesanti\">flac", //m
"mt_c2wav": "riproduzione non compressa (ancora più grande)\">wav", //m
"mt_c2ok": "bene, buona scelta",
"mt_c2nd": "quello non è il formato di output raccomandato per il tuo dispositivo, ma va bene",
"mt_c2ng": "il tuo dispositivo non sembra supportare questo formato di output, ma proviamo comunque",
"mt_xowa": "ci sono bug in iOS che prevengono la riproduzione in background usando questo formato; usa caf o mp3 invece",
"mt_tint": "livello sfondo (0-100) sulla barra di ricerca$Nper rendere il buffering meno distraente",
"mt_eq": "abilita l'equalizzatore e controllo guadagno;$N$Nboost &lt;code&gt;0&lt;/code&gt; = volume standard 100% (non modificato)$N$Nwidth &lt;code&gt;1 &nbsp;&lt;/code&gt; = stereo standard (non modificato)$Nwidth &lt;code&gt;0.5&lt;/code&gt; = 50% crossfeed sinistra-destra$Nwidth &lt;code&gt;0 &nbsp;&lt;/code&gt; = mono$N$Nboost &lt;code&gt;-0.8&lt;/code&gt; &amp; width &lt;code&gt;10&lt;/code&gt; = rimozione vocale :^)$N$Nabilitando l'equalizzatore rende gli album senza interruzioni completamente senza interruzioni, quindi lascialo acceso con tutti i valori a zero (eccetto width = 1) se ti importa di quello",
"mt_drc": "abilita il compressore gamma dinamica (appiattitore volume / brickwaller); abiliterà anche EQ per bilanciare gli spaghetti, quindi imposta tutti i campi EQ eccetto 'width' a 0 se non lo vuoi$N$NAbbassa il volume dell'audio sopra THRESHOLD dB; per ogni RATIO dB oltre THRESHOLD c'è 1 dB di output, quindi i valori di default di tresh -24 e ratio 12 significa che non dovrebbe mai diventare più forte di -22 dB ed è sicuro aumentare il boost equalizzatore a 0.8, o anche 1.8 con ATK 0 e un RLS enorme come 90 (funziona solo in firefox; RLS è max 1 in altri browser)$N$N(vedi wikipedia, lo spiegano molto meglio)",
"mb_play": "riproduci",
"mm_hashplay": "riprodurre questo file audio?",
"mm_m3u": "premi <code>Invio/OK</code> per Riprodurre\npremi <code>ESC/Annulla</code> per Modificare",
"mp_breq": "serve firefox 82+ o chrome 73+ o iOS 15+",
"mm_bload": "ora caricando...",
"mm_bconv": "convertendo in {0}, attendi...",
"mm_opusen": "il tuo browser non può riprodurre file aac / m4a;\ntranscodifica in opus ora abilitata",
"mm_playerr": "riproduzione fallita: ",
"mm_eabrt": "Il tentativo di riproduzione è stato cancellato",
"mm_enet": "La tua connessione internet è instabile",
"mm_edec": "Questo file è presumibilmente corrotto??",
"mm_esupp": "Il tuo browser non capisce questo formato audio",
"mm_eunk": "Errore Sconosciuto",
"mm_e404": "Non è stato possibile riprodurre audio; errore 404: File non trovato.",
"mm_e403": "Non è stato possibile riprodurre audio; errore 403: Accesso negato.\n\nProva a premere F5 per ricaricare, forse sei stato disconnesso",
"mm_e500": "Non è stato possibile riprodurre audio; errore 500: Controlla i log del server.",
"mm_e5xx": "Non è stato possibile riprodurre audio; errore server ",
"mm_nof": "non trovo altri file audio nelle vicinanze",
"mm_prescan": "Cercando musica da riprodurre dopo...",
"mm_scank": "Trovata la prossima canzone:",
"mm_uncache": "cache pulita; tutte le canzoni si riscaricheranno alla prossima riproduzione",
"mm_hnf": "quella canzone non esiste più",
"im_hnf": "quell'immagine non esiste più",
"f_empty": 'questa cartella è vuota',
"f_chide": 'questo nasconderà la colonna «{0}»\n\npuoi mostrare le colonne nella scheda impostazioni',
"f_bigtxt": "questo file è {0} MiB grande -- visualizzare davvero come testo?",
"f_bigtxt2": "visualizzare solo la fine del file invece? questo abiliterà anche following/tailing, mostrando righe di testo appena aggiunte in tempo reale",
"fbd_more": '<div id="blazy">mostrando <code>{0}</code> di <code>{1}</code> file; <a href="#" id="bd_more">mostra {2}</a> o <a href="#" id="bd_all">mostra tutti</a></div>',
"fbd_all": '<div id="blazy">mostrando <code>{0}</code> di <code>{1}</code> file; <a href="#" id="bd_all">mostra tutti</a></div>',
"f_anota": "solo {0} dei {1} elementi sono stati selezionati;\nper selezionare l'intera cartella, prima scorri fino in fondo",
"f_dls": 'i link dei file nella cartella corrente sono stati\ncambiati in link di download',
"f_partial": "Per scaricare in sicurezza un file che è attualmente in fase di caricamento, clicca il file che ha lo stesso nome, ma senza l'estensione <code>.PARTIAL</code>. Premi ANNULLA o Escape per farlo.\n\nPremendo OK / Invio ignorerai questo avviso e continuerai a scaricare il file <code>.PARTIAL</code> scratch, che quasi sicuramente ti darà dati corrotti.",
"ft_paste": "incolla {0} elementi$NTasto rapido: ctrl-V",
"fr_eperm": 'impossibile rinominare:\nnon hai il permesso “sposta” in questa cartella',
"fd_eperm": 'impossibile eliminare:\nnon hai il permesso “elimina” in questa cartella',
"fc_eperm": 'impossibile tagliare:\nnon hai il permesso “sposta” in questa cartella',
"fp_eperm": 'impossibile incollare:\nnon hai il permesso “scrivi” in questa cartella',
"fr_emore": "seleziona almeno un elemento da rinominare",
"fd_emore": "seleziona almeno un elemento da eliminare",
"fc_emore": "seleziona almeno un elemento da tagliare",
"fcp_emore": "seleziona almeno un elemento da copiare negli appunti",
"fs_sc": "condividi la cartella in cui ti trovi",
"fs_ss": "condividi i file selezionati",
"fs_just1d": "non puoi selezionare più di una cartella,\no mescolare file e cartelle in una selezione",
"fs_abrt": "❌ interrompi",
"fs_rand": "🎲 nome.casuale",
"fs_go": "✅ crea condivisione",
"fs_name": "nome",
"fs_src": "sorgente",
"fs_pwd": "password",
"fs_exp": "scadenza",
"fs_tmin": "min",
"fs_thrs": "ore",
"fs_tdays": "giorni",
"fs_never": "eterno",
"fs_pname": "nome link opzionale; sarà casuale se vuoto",
"fs_tsrc": "il file o cartella da condividere",
"fs_ppwd": "password opzionale",
"fs_w8": "creando condivisione...",
"fs_ok": "premi <code>Invio/OK</code> per Appunti\npremi <code>ESC/Annulla</code> per Chiudere",
"frt_dec": "può risolvere alcuni casi di nomi file corrotti\">url-decode",
"frt_rst": "ripristina nomi file modificati a quelli originali\">↺ reset",
"frt_abrt": "interrompi e chiudi questa finestra\">❌ annulla",
"frb_apply": "APPLICA RINOMINA",
"fr_adv": "rinomina batch / metadata / pattern\">avanzato",
"fr_case": "regex case-sensitive\">maiusc",
"fr_win": "nomi sicuri per windows; sostituisce <code>&lt;&gt;:&quot;\\|?*</code> con caratteri giapponesi fullwidth\">win",
"fr_slash": "sostituisce <code>/</code> con un carattere che non causa la creazione di nuove cartelle\">no /",
"fr_re": "pattern di ricerca regex da applicare ai nomi file originali; i gruppi di cattura possono essere referenziati nel campo formato sottostante come &lt;code&gt;(1)&lt;/code&gt; e &lt;code&gt;(2)&lt;/code&gt; e così via",
"fr_fmt": "ispirato da foobar2000:$N&lt;code&gt;(title)&lt;/code&gt; è sostituito dal titolo della canzone,$N&lt;code&gt;[(artist) - ](title)&lt;/code&gt; salta [questa] parte se artista è vuoto$N&lt;code&gt;$lpad((tn),2,0)&lt;/code&gt; aggiunge padding al numero traccia a 2 cifre",
"fr_pdel": "elimina",
"fr_pnew": "salva come",
"fr_pname": "fornisci un nome per il tuo nuovo preset",
"fr_aborted": "interrotto",
"fr_lold": "nome vecchio",
"fr_lnew": "nome nuovo",
"fr_tags": "tag per i file selezionati (sola lettura, solo per riferimento):",
"fr_busy": "rinominando {0} elementi...\n\n{1}",
"fr_efail": "rinomina fallita:\n",
"fr_nchg": "{0} dei nuovi nomi sono stati alterati a causa di <code>win</code> e/o <code>no /</code>\n\nOK per continuare con questi nuovi nomi alterati?",
"fd_ok": "eliminazione OK",
"fd_err": "eliminazione fallita:\n",
"fd_none": "niente è stato eliminato; forse bloccato dalla configurazione server (xbd)?",
"fd_busy": "eliminando {0} elementi...\n\n{1}",
"fd_warn1": "ELIMINARE questi {0} elementi?",
"fd_warn2": "<b>Ultima possibilità!</b> Nessun modo per annullare. Eliminare?",
"fc_ok": "tagliati {0} elementi",
"fc_warn": 'tagliati {0} elementi\n\nma: solo <b>questa</b> scheda-browser può incollarli\n(dato che la selezione è così assolutamente massiva)',
"fcc_ok": "copiati {0} elementi negli appunti",
"fcc_warn": 'copiati {0} elementi negli appunti\n\nma: solo <b>questa</b> scheda-browser può incollarli\n(dato che la selezione è così assolutamente massiva)',
"fp_apply": "usa questi nomi",
"fp_skip": "salta conflitti", //m
"fp_ecut": "prima taglia o copia alcuni file / cartelle da incollare / spostare\n\nnota: puoi tagliare / incollare attraverso diverse schede del browser",
"fp_ename": "{0} elementi non possono essere spostati qui perché i nomi sono già presi. Dai loro nuovi nomi qui sotto per continuare, o lascia vuoto il nome (\"salta conflitti\") per saltarli:", //m
"fcp_ename": "{0} elementi non possono essere copiati qui perché i nomi sono già presi. Dai loro nuovi nomi qui sotto per continuare, o lascia vuoto il nome (\"salta conflitti\") per saltarli:", //m
"fp_emore": "ci sono ancora alcune collisioni di nomi file rimaste da risolvere",
"fp_ok": "spostamento OK",
"fcp_ok": "copia OK",
"fp_busy": "spostando {0} elementi...\n\n{1}",
"fcp_busy": "copiando {0} elementi...\n\n{1}",
"fp_abrt": "annullamento in corso...", //m
"fp_err": "spostamento fallito:\n",
"fcp_err": "copia fallita:\n",
"fp_confirm": "spostare questi {0} elementi qui?",
"fcp_confirm": "copiare questi {0} elementi qui?",
"fp_etab": 'fallito leggere appunti da altra scheda browser',
"fp_name": "caricando un file dal tuo dispositivo. Dagli un nome:",
"fp_both_m": '<h6>scegli cosa incollare</h6><code>Invio</code> = Sposta {0} file da «{1}»\n<code>ESC</code> = Carica {2} file dal tuo dispositivo',
"fcp_both_m": '<h6>scegli cosa incollare</h6><code>Invio</code> = Copia {0} file da «{1}»\n<code>ESC</code> = Carica {2} file dal tuo dispositivo',
"fp_both_b": '<a href="#" id="modal-ok">Sposta</a><a href="#" id="modal-ng">Carica</a>',
"fcp_both_b": '<a href="#" id="modal-ok">Copia</a><a href="#" id="modal-ng">Carica</a>',
"mk_noname": "scrivi un nome nel campo di testo a sinistra prima di farlo :p",
"nmd_i1": "puoi anche aggiungere lestensione che vuoi, per esempio <code>.md</code>", //m
"nmd_i2": "puoi creare solo file <code>.md</code> perché non hai il permesso di eliminare", //m
"tv_load": "Caricando documento di testo:\n\n{0}\n\n{1}% ({2} di {3} MiB caricati)",
"tv_xe1": "impossibile caricare file di testo:\n\nerrore ",
"tv_xe2": "404, file non trovato",
"tv_lst": "lista di file di testo in",
"tvt_close": "torna alla vista cartella$NTasto rapido: M (o Esc)\">❌ chiudi",
"tvt_dl": "scarica questo file$NTasto rapido: Y\">💾 scarica",
"tvt_prev": "mostra documento precedente$NTasto rapido: i\">⬆ prec",
"tvt_next": "mostra documento successivo$NTasto rapido: K\">⬇ succ",
"tvt_sel": "seleziona file &nbsp; ( per taglia / copia / elimina / ... )$NTasto rapido: S\">sel",
"tvt_j": "abbellire json$NTasto rapido: shift-J\">j", //m
"tvt_edit": "apri file nell'editor di testo$NTasto rapido: E\">✏️ modifica",
"tvt_tail": "monitora file per cambiamenti; mostra nuove righe in tempo reale\">📡 segui",
"tvt_wrap": "a capo parola\">↵",
"tvt_atail": "blocca scorrimento in fondo alla pagina\">⚓",
"tvt_ctail": "decodifica colori terminale (codici escape ansi)\">🌈",
"tvt_ntail": "limite scrollback (quanti byte di testo mantenere caricati)",
"m3u_add1": "canzone aggiunta alla playlist m3u",
"m3u_addn": "{0} canzoni aggiunte alla playlist m3u",
"m3u_clip": "playlist m3u ora copiata negli appunti\n\ndovresti creare un nuovo file di testo chiamato qualcosa.m3u e incollare la playlist in quel documento; questo la renderà riproducibile",
"gt_vau": "non mostrare video, riproduci solo l'audio\">🎧",
"gt_msel": "abilita selezione file; ctrl-click un file per sovrascrivere$N$N&lt;em&gt;quando attivo: doppio-click un file / cartella per aprirlo&lt;/em&gt;$N$NTasto rapido: S\">multiselezione",
"gt_crop": "ritaglia miniature al centro\">ritaglia",
"gt_3x": "miniature hi-res\">3x",
"gt_zoom": "zoom",
"gt_chop": "taglia",
"gt_sort": "ordina per",
"gt_name": "nome",
"gt_sz": "dimensione",
"gt_ts": "data",
"gt_ext": "tipo",
"gt_c1": "tronca nomi file di più (mostra meno)",
"gt_c2": "tronca nomi file di meno (mostra di più)",
"sm_w8": "cercando...",
"sm_prev": "i risultati di ricerca qui sotto sono da una query precedente:\n ",
"sl_close": "chiudi risultati ricerca",
"sl_hits": "mostrando {0} risultati",
"sl_moar": "carica altro",
"s_sz": "dimensione",
"s_dt": "data",
"s_rd": "percorso",
"s_fn": "nome",
"s_ta": "tag",
"s_ua": "car@",
"s_ad": "avanz.",
"s_s1": "MiB minimo",
"s_s2": "MiB massimo",
"s_d1": "iso8601 min.",
"s_d2": "iso8601 max.",
"s_u1": "caricato dopo",
"s_u2": "e/o prima",
"s_r1": "percorso contiene &nbsp; (separato da spazi)",
"s_f1": "nome contiene &nbsp; (nega con -nope)",
"s_t1": "tag contiene &nbsp; (^=inizio, fine=$)",
"s_a1": "proprietà metadata specifiche",
"md_eshow": "impossibile renderizzare ",
"md_off": "[📜<em>readme</em>] disabilitato in [⚙️] -- documento nascosto",
"badreply": "Fallito nel parsare risposta dal server",
"xhr403": "403: Accesso negato\n\nprova a premere F5, forse sei stato disconnesso",
"xhr0": "sconosciuto (probabilmente persa connessione al server, o server offline)",
"cf_ok": "scusa per quello -- la protezione DD" + wah + "oS è entrata in azione\n\nle cose dovrebbero riprendere in circa 30 sec\n\nse non succede niente, premi F5 per ricaricare la pagina",
"tl_xe1": "impossibile elencare sottocartelle:\n\nerrore ",
"tl_xe2": "404: Cartella non trovata",
"fl_xe1": "impossibile elencare file nella cartella:\n\nerrore ",
"fl_xe2": "404: Cartella non trovata",
"fd_xe1": "impossibile creare sottocartella:\n\nerrore ",
"fd_xe2": "404: Cartella genitore non trovata",
"fsm_xe1": "impossibile inviare messaggio:\n\nerrore ",
"fsm_xe2": "404: Cartella genitore non trovata",
"fu_xe1": "fcaricamento fallito per la lista unpost dal server:\n\nerrore ",
"fu_xe2": "404: File non trovato??",
"fz_tar": "file gnu-tar non compresso (linux / mac)",
"fz_pax": "tar formato pax non compresso (più lento)",
"fz_targz": "gnu-tar con compressione gzip livello 3$N$NSolitamente è molto lento, quindi$Nusa tar non compresso",
"fz_tarxz": "gnu-tar con compressione xz livello 1$N$NQuesto è solitamente molto lento, quindi$Nusa tar non compresso",
"fz_zip8": "zip con nomi file utf8 (forse instabile su windows 7 e precedenti)",
"fz_zipd": "zip con nomi file cp437 tradizionali, per software molto vecchio",
"fz_zipc": "cp437 con crc32 calcolato presto,$Nper MS-DOS PKZIP v2.04g (ottobre 1993)$N(ci vuole più tempo per elaborare prima che possa iniziare il download)",
"un_m1": "puoi eliminare i tuoi caricamenti recenti (o interrompere quelli non finiti) qui sotto",
"un_upd": "aggiorna",
"un_m4": "o condividi i file visibili qui sotto:",
"un_ulist": "mostra",
"un_ucopy": "copia",
"un_flt": "filtro opzionale:&nbsp; URL deve contenere",
"un_fclr": "resetta filtro",
"un_derr": 'unpost-delete fallito:\n',
"un_f5": 'qualcosa si è rotto, prova un aggiornamento o premi F5',
"un_uf5": "scusa ma devi aggiornare la pagina (per esempio premendo F5 o CTRL-R) prima che questo caricamento possa essere interrotto",
"un_nou": '<b>avviso:</b> server troppo occupato per mostrare caricamenti non finiti; clicca il link "aggiorna" tra un po\'',
"un_noc": '<b>avviso:</b> unpost di file completamente caricati non è abilitato/permesso nella configurazione server',
"un_max": "mostrando primi 2000 file (usa il filtro)",
"un_avail": "{0} caricamenti recenti possono essere eliminati<br />{1} non finiti possono essere interrotti",
"un_m2": "ordinati per tempo di caricamento; più recenti prima:",
"un_no1": "scherzo! nessun caricamento è abbastanza recente",
"un_no2": "scherzo! nessun caricamento che corrisponde a quel filtro è abbastanza recente",
"un_next": "elimina i prossimi {0} file qui sotto",
"un_abrt": "interrompi",
"un_del": "elimina",
"un_m3": "caricando i tuoi caricamenti recenti...",
"un_busy": "eliminando {0} file...",
"un_clip": "{0} link copiati negli appunti",
"u_https1": "dovresti",
"u_https2": "passare a https",
"u_https3": "per prestazioni migliori",
"u_ancient": 'il tuo browser è incredibilmente antico -- forse dovresti <a href="#" onclick="goto(\'bup\')">usare bup invece</a>',
"u_nowork": "serve firefox 53+ o chrome 57+ o iOS 11+",
"tail_2old": "serve firefox 105+ o chrome 71+ o iOS 14.5+",
"u_nodrop": 'il tuo browser è troppo vecchio per il caricamento drag-and-drop',
"u_notdir": "quella non è una cartella!\n\nil tuo browser è troppo vecchio,\nprova dragdrop invece",
"u_uri": "per trascinare immagini da altre finestre del browser,\nrilasciale sul pulsante upload grande",
"u_enpot": 'passa alla <a href="#">UI patata</a> (può migliorare velocità upload)',
"u_depot": 'passa alla <a href="#">UI elegante</a> (può ridurre velocità upload)',
"u_gotpot": 'passando alla UI patata per migliorare velocità upload,\n\nsentiti libero di non essere d\'accordo e tornare indietro!',
"u_pott": "<p>file: &nbsp; <b>{0}</b> finiti, &nbsp; <b>{1}</b> falliti, &nbsp; <b>{2}</b> occupati, &nbsp; <b>{3}</b> in coda</p>",
"u_ever": "questo è l'uploader di base; up2k necessita almeno<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1",
"u_su2k": 'questo è l\'uploader di base; <a href="#" id="u2yea">up2k</a> è migliore',
"u_uput": 'velocizza (salta checksum)',
"u_ewrite": 'non hai accesso in scrittura a questa cartella',
"u_eread": 'non hai accesso in lettura a questa cartella',
"u_enoi": 'file-search non è abilitato nella configurazione server',
"u_enoow": "non puoi sovrascrivere qui; serve permesso Elimina",
"u_badf": 'Questi {0} file (di {1} totali) sono stati saltati, probabilmente a causa di permessi filesystem:\n\n',
"u_blankf": 'Questi {0} file (di {1} totali) sono vuoti; caricarli comunque?\n\n',
"u_applef": 'Questi {0} file (di {1} totali) sono probabilmente indesiderabili;\nPremi <code>OK/Invio</code> per SALTARE i seguenti file,\nPremi <code>Annulla/ESC</code> per NON escludere, e CARICARE anche quelli:\n\n',
"u_just1": '\nForse funziona meglio se selezioni solo un file',
"u_ff_many": "se stai usando <b>Linux / MacOS / Android,</b> allora questa quantità di file <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>potrebbe</em> far crashare Firefox!</a>\nse succede, riprova (o usa Chrome).",
"u_up_life": "Questo caricamento sarà eliminato dal server\n{0} dopo che si completa",
"u_asku": 'caricare questi {0} file in <code>{1}</code>',
"u_unpt": "puoi annullare / eliminare questo caricamento usando 🧯 in alto a sinistra",
"u_bigtab": 'sto per mostrare {0} file\n\nquesto potrebbe far crashare il tuo browser, sei sicuro?',
"u_scan": 'Scansionando file...',
"u_dirstuck": 'iteratore directory si è bloccato tentando di accedere ai seguenti {0} elementi; salterò:',
"u_etadone": 'Fatto ({0}, {1} file)',
"u_etaprep": '(preparando per caricare)',
"u_hashdone": 'hashing completato',
"u_hashing": 'hash',
"u_hs": 'handshaking...',
"u_started": "i file ora sono in caricamento; vedi [🚀]",
"u_dupdefer": "duplicato; sarà processato dopo tutti gli altri file",
"u_actx": "clicca questo testo per prevenire perdita di<br />prestazioni quando cambi ad altre finestre/schede",
"u_fixed": "OK!&nbsp; Risolto 👍",
"u_cuerr": "caricamento fallito del chunk {0} di {1};\nprobabilmente innocuo, continuo\n\nfile: {2}",
"u_cuerr2": "il server ha rifiutato il caricamento (chunk {0} di {1});\nriproverò più tardi\n\nfile: {2}\n\nerrore ",
"u_ehstmp": "riproverò; vedi in basso a destra",
"u_ehsfin": "il server ha rifiutato la richiesta di finalizzare caricamento; riprovando...",
"u_ehssrch": "il server ha rifiutato la richiesta di eseguire ricerca; riprovando...",
"u_ehsinit": "il server ha rifiutato la richiesta di iniziare caricamento; riprovando...",
"u_eneths": "errore di rete durante handshake per upload; riprovando...",
"u_enethd": "errore di rete durante test esistenza target; riprovando...",
"u_cbusy": "aspettando che il server si fidi di noi di nuovo dopo un problema di rete...",
"u_ehsdf": "il server ha finito lo spazio su disco!\n\ncontinuerò a riprovare, nel caso qualcuno\nliberi abbastanza spazio per continuare",
"u_emtleak1": "sembra che il tuo browser possa avere un memory leak;\nper favore",
"u_emtleak2": ' <a href="{0}">passa a https (raccomandato)</a> o ',
"u_emtleak3": ' ',
"u_emtleakc": 'prova quanto segue:\n<ul><li>premi <code>F5</code> per aggiornare la pagina</li><li>poi disabilita il pulsante &nbsp;<code>mt</code>&nbsp; nelle &nbsp;<code>⚙️ impostazioni</code></li><li>e riprova quel caricamento</li></ul>I caricamenti saranno un po\' più lenti, ma pazienza.\nScusa per il disturbo !\n\nPS: chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">ha un bugfix</a> per questo',
"u_emtleakf": 'prova quanto segue:\n<ul><li>premi <code>F5</code> per aggiornare la pagina</li><li>poi abilita <code>🥔</code> (patata) nell\'UI caricamento<li>e riprova quel caricamento</li></ul>\nPS: firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">avrà sperabilmente un bugfix</a> ad un certo punto',
"u_s404": "non trovato sul server",
"u_expl": "spiega",
"u_maxconn": "la maggior parte dei browser limita questo a 6, ma firefox ti permette di alzarlo con <code>connections-per-server</code> in <code>about:config</code>",
"u_tu": '<p class="warn">AVVISO: turbo abilitato, <span>&nbsp;client potrebbe non rilevare e riprendere caricamenti incompleti; vedi tooltip pulsante turbo</span></p>',
"u_ts": '<p class="warn">AVVISO: turbo abilitato, <span>&nbsp;risultati ricerca possono essere incorretti; vedi tooltip pulsante turbo</span></p>',
"u_turbo_c": "turbo è disabilitato nella configurazione server",
"u_turbo_g": "disabilitando turbo perché non hai\nprivilegi di elenco directory all'interno di questo volume",
"u_life_cfg": 'auto-elimina dopo <input id="lifem" p="60" /> min (o <input id="lifeh" p="3600" /> ore)',
"u_life_est": 'caricamento sarà eliminato <span id="lifew" tt="ora locale">---</span>',
"u_life_max": 'questa cartella impone una\nvita massima di {0}',
"u_unp_ok": 'unpost è permesso per {0}',
"u_unp_ng": 'unpost NON sarà permesso',
"ue_ro": 'il tuo accesso a questa cartella è solo-Lettura\n\n',
"ue_nl": 'attualmente non sei loggato',
"ue_la": 'attualmente sei loggato come "{0}"',
"ue_sr": 'attualmente sei in modalità file-search\n\npassa alla modalità upload cliccando la lente d\'ingrandimento 🔎 (accanto al grande pulsante CERCA), e prova a caricare di nuovo\n\nscusa',
"ue_ta": 'prova a caricare di nuovo, dovrebbe funzionare ora',
"ue_ab": "questo file è già in caricamento in un'altra cartella, e quel caricamento deve essere completato prima che il file possa essere caricato altrove.\n\nPuoi interrompere e dimenticare il caricamento iniziale usando l'🧯 in alto a sinistra",
"ur_1uo": "OK: File caricato con successo",
"ur_auo": "OK: Tutti i {0} file caricati con successo",
"ur_1so": "OK: File trovato sul server",
"ur_aso": "OK: Tutti i {0} file trovati sul server",
"ur_1un": "Caricamento fallito, scusa",
"ur_aun": "Tutti i {0} caricamenti falliti, scusa",
"ur_1sn": "File NON trovato sul server",
"ur_asn": "I {0} file NON sono stati trovati sul server",
"ur_um": "Finito;\n{0} caricamenti OK,\n{1} caricamenti falliti, scusa",
"ur_sm": "Finito;\n{0} file trovati sul server,\n{1} file NON trovati sul server",
"rc_opn": "apri", //m
"rc_ply": "riproduci", //m
"rc_pla": "riproduci come audio", //m
"rc_txt": "apri nel visualizzatore di file", //m
"rc_md": "apri nelleditor di testo", //m
"rc_dl": "scarica", //m
"rc_zip": "scarica come archivio", //m
"rc_del": "elimina", //m
"rc_cut": "taglia", //m
"rc_cpy": "copia", //m
"rc_pst": "incolla", //m
"rc_nfo": "nuova cartella", //m
"rc_nfi": "nuovo file", //m
"rc_sal": "seleziona tutto", //m
"rc_sin": "inverti selezione", //m
"lang_set": "aggiornare per rendere effettivo il cambiamento?",
"splash": {
"a1": "aggiorna",
"b1": "ciao &nbsp; <small>(non sei connesso)</small>",
"c1": "disconnetti",
"d1": "stato",
"d2": "mostra lo stato di tutti i thread attivi",
"e1": "ricarica configurazione",
"e2": "ricarica i file di configurazione (account/volumi/flag dei volumi),\n e riesegue la scansione di tutti i volumi e2ds.\n\nNota: qualsiasi modifica alle impostazioni globali richiede un riavvio completo per avere effetto",
"f1": "puoi visualizzare:",
"g1": "puoi caricare su:",
"cc1": "altro:",
"h1": "disattiva k304",
"i1": "attiva k304",
"j1": "k304 interrompe la connessione per ogni HTTP 304. Questo aiuta contro alcuni proxy difettosi che possono bloccarsi o smettere improvvisamente di caricare pagine, ma riduce notevolmente le prestazioni",
"k1": "resetta impostazioni",
"l1": "accedi:",
"ls3": "accedi", //m
"lu4": "nome utente", //m
"lp4": "password", //m
"lo3": "disconnetti “{0}” ovunque", //m
"lo2": "questo terminerà la sessione su tutti i browser", //m
"m1": "bentornato,",
"n1": "404: file non trovato &nbsp;┐( ´ -`)┌",
"o1": "oppure forse non hai accesso? prova una password o <a href=\"SR/?h\">torna alla home</a>",
"p1": "403: accesso negato &nbsp;~┻━┻",
"q1": "prova una password o <a href=\"SR/?h\">torna alla home</a>",
"r1": "torna alla home",
".s1": "mappa",
"t1": "azione",
"u2": "tempo dall'ultima scrittura sul server\n (caricamento / rinomina / ...)\n\n17d = 17 giorni\n1h23 = 1 ora 23 minuti\n4m56 = 4 minuti 56 secondi",
"v1": "connetti",
"v2": "usa questo server come un disco locale",
"w1": "passa a https",
"x1": "cambia password",
"y1": "le tue condivisioni",
"z1": "sblocca area:",
"ta1": "devi prima inserire una nuova password",
"ta2": "ripeti per confermare la nuova password:",
"ta3": "errore di digitazione; riprova",
"nop": "ERRORE: La password non può essere vuota", //m
"nou": "ERRORE: Il nome utente e/o la password non possono essere vuoti", //m
"aa1": "in arrivo:",
"ab1": "disattiva no304",
"ac1": "attiva no304",
"ad1": "no304 disabilita completamente la cache. Se k304 non è sufficiente, prova questa opzione. Aumenterà notevolmente il consumo di dati!",
"ae1": "in uscita:",
"af1": "mostra i file caricati di recente",
"ag1": "mostra utenti IdP conosciuti",
}
};

Some files were not shown because too many files have changed in this diff Show more