From 0bc1b8f71534cb99de9d7fa627b4b6dafff5e09f Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 10:22:52 +0000 Subject: [PATCH 01/66] readme: webdav and opengraph are incompatible by default --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 889ea8b8..72b104c8 100644 --- a/README.md +++ b/README.md @@ -1425,6 +1425,8 @@ note that this disables hotlinking because the opengraph spec demands it; to sne you can also hotlink files regardless by appending `?raw` to the url +> WARNING: if you plan to use WebDAV, then `--og-ua` / `og_ua` must be configured + if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object) From 50f162935533b601e1811d96f838f302c0507d1e Mon Sep 17 00:00:00 2001 From: Techflash <72118300+techflashYT@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:16:00 -0700 Subject: [PATCH 02/66] Add test results for Wii Internet Channel Signed-off-by: Techflash <72118300+techflashYT@users.noreply.github.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72b104c8..d038207b 100644 --- a/README.md +++ b/README.md @@ -2431,6 +2431,7 @@ quick summary of more eccentric web-browsers trying to view a directory index: | **SerenityOS** (7e98457) | hits a page fault, works with `?b=u`, file upload not-impl | | **sony psp** 5.50 | can browse, upload/mkdir/msg (thx dwarf) [screenshot](https://github.com/user-attachments/assets/9d21f020-1110-4652-abeb-6fc09c533d4f) | | **nintendo 3ds** | can browse, upload, view thumbnails (thx bnjmn) | +| **Nintendo Wii (Opera 9.0 "Internet Channel")** | can browse, can't upload or download (no local storage), can view images - works best with `?b=u`, default view broken |

From c69c7c8ac06e900906a35fa909991fa563ad1fee Mon Sep 17 00:00:00 2001 From: Chinpo Nya Date: Fri, 1 Aug 2025 23:21:42 +0200 Subject: [PATCH 03/66] additional instructions for --ah-cli --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d038207b..1a500c5b 100644 --- a/README.md +++ b/README.md @@ -2702,6 +2702,10 @@ optionally also specify `--ah-cli` to enter an interactive mode where it will ha the default configs take about 0.4 sec and 256 MiB RAM to process a new password on a decent laptop +when generating hashes using `--ah-cli` for docker or systemd services, make sure it is using the same `--ah-salt` by: +* inspecting the generated salt using `--show-ah-salt` in copyparty service configuration +* setting the same `--ah-salt` in both environments + ## https From c805c60f4093077cc2a51408597667be7a905705 Mon Sep 17 00:00:00 2001 From: Beethoven <44652883+Beethoven-n@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:09:29 -0500 Subject: [PATCH 04/66] (scripts/prep.sh) update i forgot to follow the style woops Signed-off-by: Beethoven <44652883+Beethoven-n@users.noreply.github.com> --- scripts/prep.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/prep.sh b/scripts/prep.sh index c08d09ed..a4c8a132 100755 --- a/scripts/prep.sh +++ b/scripts/prep.sh @@ -34,10 +34,10 @@ update_mpr_pkgbuild() { # /^sha256sums=/{sub(/[0-9a-f]{64}/,sha)}; # 1' PKGBUILD >a # mv a PKGBUILD - - echo thing 1 - sed -s -i "s/pkgver=\"\"/pkgver=\"$ver\"/" PKGBUILD - sed -s -i "s/sha256sums=(\".*\")/sha256sums=(\"$sha\")/" PKGBUILD + # TODO: check if this still works. if so, remove the following 2 lines: + + sed -s -i "s/pkgver=\"\"/pkgver=\"$ver\"/" PKGBUILD + sed -s -i "s/sha256sums=(\".*\")/sha256sums=(\"$sha\")/" PKGBUILD rm -rf x } From 3798e19a26d975f0b4ef1596706b1c62a4b1baca Mon Sep 17 00:00:00 2001 From: DeStilleGast <3677706+DeStilleGast@users.noreply.github.com> Date: Sun, 3 Aug 2025 18:20:10 +0200 Subject: [PATCH 05/66] Dutch translation (#426) * Update browser.js to include Dutch language * Update splash.js to include some Dutch translations Signed-off-by: DeStilleGast <3677706+DeStilleGast@users.noreply.github.com> --- copyparty/web/browser.js | 629 ++++++++++++++++++++++++++++++++++++++- copyparty/web/splash.js | 42 +++ 2 files changed, 670 insertions(+), 1 deletion(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 5340d5bb..af0c0e39 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3141,6 +3141,633 @@ var Ls = { "lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?", }, + "nld": { + "tt": "Nederlands", + + "cols": { + "c": "Action knoppen", + "dur": "Duratie", + "q": "Kwaliteit / bitrate", + "Ac": "Audio codec", + "Vc": "Video codec", + "Fmt": "Formaat / container", + "Ahash": "Audio checksum", + "Vhash": "Video checksum", + "Res": "Resolution", + "T": "Bestandstype", + "aq": "Audio kwaliteit / bitrate", + "vq": "Video kwaliteit / bitrate", + "pixfmt": "Subsampling / pixel structure", + "resw": "Horizontale resolutie", + "resh": "Verticale resolutie", + "chs": "Audiokanalen", + "hz": "Samplefrequentie" + }, + + "hks": [ + [ + "diversen", + ["ESC", "Sluit verschillende dingen"], + + "bestand beheer", + ["G", "Verwissel tussen list / grid weergave"], + ["T", "Verwissel tussen miniaturen / iconen"], + ["⇧ A/D", "Thumbnail formaat"], + ["ctrl-K", "Verwijder geselecteerde"], + ["ctrl-X", "Knip selectie naar klembord"], + ["ctrl-C", "Kopieer selectie naar klembord"], + ["ctrl-V", "Hier plakken (verplaatsen/kopieëren)"], + ["Y", "Download geselecteerde"], + ["F2", "Hernoem geselecteerde"], + + "bestand-lijst-selectie", + ["space", "wissel bestand selectie"], + ["↑/↓", "verplaats selectie cursor"], + ["ctrl ↑/↓", "verplaats cursor en scherm"], + ["⇧ ↑/↓", "select vorige/volgende bestand"], + ["ctrl-A", "selecteer alle bestanden / mappen"], + ], [ + "navigatie", + ["B", "verwissel breadcrumbs / navpane"], + ["I/K", "Vorige/volgende map"], + ["M", "Bovenliggende map (of huidige uitvouwen)"], + ["V", "Berwissel map / tekstbestand in navpane"], + ["A/D", "Navpane formaat"], + ], [ + "muziek-speler", + ["J/L", "Vorige/volgende song"], + ["U/O", "Skip 10sec terug/vooruit"], + ["0..9", "Spring naar 0%..90%"], + ["P", "Speel/pauzeer (start ook)"], + ["S", "Selecteer afspelende song"], + ["Y", "Download song"], + ], [ + "afbeelding viewer", + ["J/L, ←/→", "Vorige/volgende afbeelding"], + ["Home/End", "Eerste/laatste afbeelding"], + ["F", "Volledig scherm"], + ["R", "Draai rechtsom"], + ["⇧ R", "Draai linksom"], + ["S", "Selecteer afbeelding"], + ["Y", "Download afbeelding"], + ], [ + "video-speler", + ["U/O", "Skip 10sec terug/vooruit"], + ["P/K/Space", "Speel/pauze"], + ["C", "Verder met volgende"], + ["V", "herhaal"], + ["M", "stil"], + ["[ and ]", "zet herhaal interval"], + ], [ + "tekstbestand-viewer", + ["I/K", "vorige/volgende bestand"], + ["M", "sluit tekst bestand"], + ["E", "bewerk tekst bestand"], + ["S", "selecteer bestand (voor knip/kopie/hernoem)"], + ] + ], + + "m_ok": "OK", + "m_ng": "Annuleren", + + "enable": "Inschakelen", + "danger": "GEVAARLIJK", + "clipped": "Gekopieërd naar klembord", + + "ht_s1": "seconde", + "ht_s2": "secondes", + "ht_m1": "minuut", + "ht_m2": "minuten", + "ht_h1": "uur", + "ht_h2": "uur", + "ht_d1": "dag", + "ht_d2": "dagen", + "ht_and": " en ", + + "goh": "Beheer-paneel", + "gop": 'Vorige map">Vorige', + "gou": 'Bovenligende map">Omhoog', + "gon": 'Volgende map">Volgende', + "logout": "Uitloggen ", + "access": " Toegang", + "ot_close": "Sluit onder-menu", + "ot_search": "Zoek voor bestanden bij attributes, pad / naam, muziek tags, of elk andere combinatie tussen$N$N<code>foo bar</code> = moet beide «foo» en «bar» bevatten,$N<code>foo -bar</code> = moet «foo» bevatten maar geen «bar»,$N<code>^yana .opus$</code> = start met «yana» en moet een «opus» bestand zijn$N<code>"try unite"</code> = moet precies «try unite» bevatten$N$Nde datum formaat is iso-8601, zoals$N<code>2009-12-31</code> of <code>2020-09-12 23:30:00</code>", + "ot_unpost": "unpost: verwijder je recente uploads, of onvoltooide uploads afbreken", + "ot_bup": "bup: Basisuploader, supports zelfs netscape 4.0", + "ot_mkdir": "mkdir: Maak een nieuwe map", + "ot_md": "new-md: Maak een nieuwe markdown bestand", + "ot_msg": "msg: Verstuur een bericht naar de server logs", + "ot_mp": "Media speler opties", + "ot_cfg": "Configuratie opties", + "ot_u2i": 'up2k: upload bestanden (als je schrijf toegang hebt) of verwissel naar zoek-mode om te zien of ze ergens bestaan op de server$N$Nuploads zijn hervatbaar, multithreaded, en bestandstijdstempels blijven behouden, maar het gebruikt meer CPU dan [🎈]  (de basic uploader)

tijdens het uploaden, dit icoon word dan een progress indicatie!', + "ot_u2w": 'up2k: upload bestanden met hervattings ondersteuning (sluit je webbrowser en selecteer dezelfde bestand later opnieuw)$N$Nmultithreaded, en bestandstijdstempels blijven behouden, maar het gebruikt meer CPU dan [🎈]  (de basic uploader)

tijdens het uploaden, dit icoon word dan een progress indicatie!', + "ot_noie": 'Gebruik alstublieft Chrome / Firefox / Edge', + + "ab_mkdir": "maak map", + "ab_mkdoc": "nieuw markdown doc", + "ab_msg": "verstuur msg naar srv log", + + "ay_path": "skip naar mappen", + "ay_files": "skip naar bestanden", + + "wt_ren": "Hernoem geselecteerde items$NHotkey: F2", + "wt_del": "Berwijder geselecteerde items$NHotkey: ctrl-K", + "wt_cut": "Knip geselecteerde items <small>(en plak het ergens anders)</small>$NHotkey: ctrl-X", + "wt_cpy": "Kopieer geselecteerde items naar klembord$N(om te plakken ergens anders)$NHotkey: ctrl-C", + "wt_pst": "Plak eeen laatst geknipte / gekopieërde selectie$NHotkey: ctrl-V", + "wt_selall": "Selecteer alle bestanden$NHotkey: ctrl-A (wanneer bestand gefocused is)", + "wt_selinv": "Selectie omkeren", + "wt_zip1": "Download deze map als archief", + "wt_selzip": "Download selectie als archief", + "wt_seldl": "Download selectie als losse bestanden$NHotkey: Y", + "wt_npirc": "Kopieer irc-geformarteerde track info", + "wt_nptxt": "Kopieer platte tekst track info", + "wt_m3ua": "Aan m3u afspeellijst toevoegen (klik 📻kopieer later)", + "wt_m3uc": "Kopieer m3u playlist naar klembord", + "wt_grid": "Verwissel grid / lijst weergave$NHotkey: G", + "wt_prev": "Vorig nummer$NHotkey: J", + "wt_play": "Afspelen / pauzeer$NHotkey: P", + "wt_next": "Volgend nummer$NHotkey: L", + + "ul_par": "Parallel uploads:", + "ut_rand": "Willekeurige bestandsnaam", + "ut_u2ts": "Kopieer de laatste-gewijzigde tijdstamp$Nvan je bestandsysteem naar de server\">📅", + "ut_ow": "Overschrijf bestaande bestanden op de server?$N🛡️: nooit (zal in plaats daarvan een nieuwe bestandsnaam genereren)$N🕒: overschrijven als de server-bestand ouder is dan het geüploade bestand$N♻️: altijd overschrijven als de bestanden verschillend zijn", + "ut_mt": "Ga door met hashen van andere bestanden tijdens het uploaden$N$Moet je misschien uitschakelen als je CPU of HDD het niet aan kan", + "ut_ask": 'Vraag voor bevestiging voordat het uploaden start">💭', + "ut_pot": "Verbeter de uploadsnelheid voor langzame apparaten$Ndoor de interface minder complex te maken", + "ut_srch": "Niet uploaden, maar check of de bestanden als op de server bestaan$N (checkt alle mappen die waar jij toegang op hebt)", + "ut_par": "Pauzeer bij zetten het op 0$N$Nverhoog als je verbinding traag is$N$Nhou het op 1 als je netwerk of server HDD het niet aankan", + "ul_btn": "Drop bestanden / mappen
hier (of klik mij)", + "ul_btnu": "U P L O A D", + "ul_btns": "Z O E K E N", + + "ul_hash": "Gash", + "ul_send": "Verstuur", + "ul_done": "Klaar", + "ul_idle1": "Geen uploads in wachtrij", + "ut_etah": "Gemiddelde <em>hashing</em> snelheid en geschatte tijd tot de voltooiing", + "ut_etau": "Gemiddelde <em>upload</em> snelheid en geschatte tijd tot voltooiing", + "ut_etat": "Gemiddelde <em>totale</em> snelheid en geschatte tijd tot voltooiing", + + "uct_ok": "Succesvol afgerond", + "uct_ng": "Niet goed: gefaald / geweigerd / niet gevonden", + "uct_done": "ok en ng gecombineerd", + "uct_bz": "Hashing van uploads", + "uct_q": "Inactief, in afwachting", + + "utl_name": "Bestandsnaam", + "utl_ulist": "Lijst", + "utl_ucopy": "Kopieer", + "utl_links": "Links", + "utl_stat": "Status", + "utl_prog": "Vooruitgang", + + // keep short: + "utl_404": "404", + "utl_err": "FOUT", + "utl_oserr": "OS-FOUT", + "utl_found": "gevonden", + "utl_defer": "Uitgesteld", + "utl_yolo": "YOLO", + "utl_done": "klaar", + + "ul_flagblk": "De bestanden zijn toegevoegd aan de wachtrij
maar er is een drukke up2k bezig in een andere tabblad,
wachten totdat die eerst klaar is", + "ul_btnlk": "De server configuratie heeft deze schakelaar versleuteld in deze staat", + + "udt_up": "Upload", + "udt_srch": "Zoeken", + "udt_drop": "Laat hier los", + + "u_nav_m": '
Hey, wat heb jij daar?
Enter = Bestanden (een of meer)\nESC = Een map (inclusief submappen)', + "u_nav_b": 'BestandenEen map', + + "cl_opts": "Switches", + "cl_themes": "Thema", + "cl_langs": "Taal", + "cl_ziptype": "Download map als", + "cl_uopts": "up2k switches", + "cl_favico": "Favicon", + "cl_bigdir": "Item limiet in map", + "cl_hsort": "#sorteer", + "cl_keytype": "Key notaties", + "cl_hiddenc": "Verborgen kolomen", + "cl_hidec": "Verborgen", + "cl_reset": "Reset", + "cl_hpick": "Tik op de kolomkoppen om ze in de onderstaande tabel te verbergen", + "cl_hcancel": "Kolumn verbergen geannuleerd", + + "ct_grid": '田 grid', + "ct_ttips": '◔ ◡ ◔">ℹ️ tooltips', + "ct_thumb": 'In grid-overzicht, wissel tussen iconen of thumbnails$NHotkey: T">🖼️ thumbs', + "ct_csel": 'Gebruik CTRL en SHIFT voor de bestand selectie in grid-overzicht>sel', + "ct_ihop": 'Als je afbeeldingviewer afsluit, scroll omlaag naar de laatst bekeken bestand">g⮯', + "ct_dots": 'Laat verborgen bestanden zien (als de server dat toestaat)">dotfiles', + "ct_qdel": 'Waneeer je een bestand verwijderd, vraag eenmalig om bevestiging">qdel', + "ct_dir1st": 'Sorteer mappen eerst en dan de bestanden">📁 first', + "ct_nsort": 'Natural sort (voor bestandsnamen dat beginnen met getallen)">nsort', + "ct_readme": 'Laat README.md in mappen lijst zien">📜 readme', + "ct_utc": 'Toon alle datums en tijden in UTC">UTC', + "ct_idxh": 'Laat index.html zien in plaats van de map overzicht">htm', + "ct_sbars": 'Laat scrollbars zien">⟊', + + "cut_umod": "Als een bestand al bestaat op de server, update de 'gewijzigd' waarde op het bestand wat op de server staat met het bestand wat je geupload hebt (vereist schrijf+verwijder rechten)\">re📅", + + "cut_turbo": "De yolo knop, die wil jij waarschijnlijk NIET actief wilt hebben:$N$Ngebruik dit als je heel veel bestanden gaat uploaden EN je moest het herstarten voor een reden en je wilt doorgaan met uploaden ASAP$N$Ndit vervangt de hash-check met een simpele "heeft dit dezelfde bestands groote op de server?", zo als de bestands inhoud verschillend is, dan worden ze NIET geupload$N$NJe zou deze optie weer uit moeten zetten als de upload klaar is en dan "upload" de zelfde bestanden opnieuw uploaden zo de client het kan verifieren\">turbo", + + "cut_datechk": "Heeft geen effect tenzij de turbo knop actief is$N$Nverminder de yolo factor (een klein beetje); controlleert of de bestand tijdstamp op de server hetzelfde is met het geuploade bestand$N$Ndit zou in theorie de meest onvoltooide/onvoledige uploads, maar dit is geen vervaning voor de verificatie-check met de turbo knop uitgeschakeld daarna\">date-chk", + + "cut_u2sz": "Grote (in MiB) voor elk geuploade stuk; grote waardes vliegen beter over de Atlantische Oceaan. Probeer lage waardes op zeer onstabiele verbindingen", + + "cut_flag": "Alleen een tabblad kan bestanden uploaden $N -- andere tabbladen moeten deze optie ook actief hebben $N -- dit heeft alleen effect op de tabbladen die op hetzelfde domain zijn", + + "cut_az": "Bestanden uploaden in alfabetische volgorde, in plaats van kleinste bestanden eerst$N$Nalfabetische volgorde kan het makkelijker maken om te zien of er wat fout is gegaan op de server, dit maakt het uploaden ietsjes trager op fiber / LAN", + + "cut_nag": "Systeem notificatie weergeven als een upload voltooid is$N(alleen als de browser of tabblad niet actief is)", + "cut_sfx": "Geluid waarschuwing afspelen als een upload voltooid is$N(alleen als de browser of tabblad niet actief is)", + + "cut_mt": "Gebruik multithreading om bestands-hashing te versnellen$N$Ndit gebruikt web-workers en vereist$Nmeer geheugen (tot wel 512 MiB extra)$N$Nmaakt https 30% sneller en http 4.5x sneller\">mt", + + "cut_wasm": "Gebruik wasm in plaats van de webbrowser ingebouwde hasher; verbetert de snelheid op chrome-gebaseerde webbrowsers maar verhoogd CPU gebruik, veel oude versie van chrome hebben een bug dat een geheugen lek heeft, dat kan alle geheugen in gebruik nemen en crashen als dit actief is\">wasm", + + "cft_text": "Favicon tekst (laat leeg en vernieuw om uit te schakelen)", + "cft_fg": "Voorgrondkleur", + "cft_bg": "Achtergrondkleur", + + "cdt_lim": "Max aantal bestanden laten zien in een map", + "cdt_ask": "Als helemaal naar beneden gescrolld bent,$Nin plaats van meer inladen,$Nvraag wat het moet doen", + "cdt_hsort": "Hoeveel sorteerregels (<code>,sorthref</code>) moeten er in media-URL's worden opgenomen? Als je dit op 0 instelt, worden de sorteerregels in medialinks ook genegeerd wanneer erop geklikt word.", + + "tt_entree": "Laat navpane zien (directoryboom zijbalk)$NHotkey: B", + "tt_detree": "Laat breadcrumbs zien$NHotkey: B", + "tt_visdir": "Scroll naar geselecteerde map", + "tt_ftree": "Verwissel tussen directoryboom / tekst bestanden$NHotkey: V", + "tt_pdock": "Laat bovenliggende mappen zien in een vastgezet deelvenster bovenaan", + "tt_dynt": "Automatisch groeien naarmate de directoryboom zich uitbreidt", + "tt_wrap": "Automatische terugloop", + "tt_hover": "Laat overlopenden lijnen zien bij zweven$N(stopt het scrollen tenzij de muis in de linker gedeelte van het scherm is)", + + "ml_pmode": "Aan het einde van de map...", + "ml_btns": "Cmds", + "ml_tcode": "Transcode", + "ml_tcode2": "Transcode naar", + "ml_tint": "Tint", + "ml_eq": "Audio-equalizer", + "ml_drc": "Dynamisch bereikcompressor", + + "mt_loop": "Loop/herhaal een nummer\">🔁", + "mt_one": "Stop na een nummer\">1️⃣", + "mt_shuf": "Shuffle alle muziek in alle mappen\">🔀", + "mt_aplay": "Autoplay als er een song-ID staat in de link waarop je hebt geklikt om naar de server te gaan$N$NAls u dit uitschakelt, wordt de pagina-URL ook niet meer bijgewerkt met nummer-ID's tijdens het afspelen van muziek. Dit voorkomt automatisch afspelen als deze instellingen verloren gaan, maar de URL behouden blijft.\">a▶", + "mt_preload": "Begin het laden van de volgende nummer vlak voordat de huidige nummer het einde bereikt voor gapless playback\">preload", + "mt_prescan": "Ga naar de volgende map voordat de laatste nummer eindigd$NMaakt de webbrower blij$NZo het afspelen van muziek niet gestopt word\">nav", + "mt_fullpre": "Probeer het hele nummer vooraf te laden;$N✅ activeer dit op onstabiele verbindingen,$N❌ zet uit als je waarschijnlijk een trage verbinding hebt\">full", + "mt_fau": "Op telefoons, voorkom muziek van stoppen als de volgende nummer niet snel genoeg voorgeladen is (kan de weergave van tags glitchy maken)\">☕️", + "mt_waves": "Waveform zoekbar:$NToon audio-amplitude in de zoekbar\">~s", + "mt_npclip": "Knoppen tonen voor het clipboarden van het nummer dat op dat moment wordt afgespeeld\">/np", + "mt_m3u_c": "Knoppen tonen om de geselecteerde nummers als m3u8-afspeellijstitems te clipboarden\">📻", + "mt_octl": "OS-integratie (media hotkeys / osd)\">os-ctl", + "mt_oseek": "Zoeken via os-integratie mogelijk maken$N$NNotitie: op sommige toestellen (iPhones) dit vervcangt de volgende-nummer knop\">seek", + "mt_oscv": "Albumhoes weergeven in osd\">art", + "mt_follow": "Het afgespeelde nummer in beeld houden\">🎯", + "mt_compact": "Compacte bedieningselementen\">⟎", + "mt_uncache": "Cache wissen  (Probeer dit als uw browser een kapotte kopie van een nummer heeft gecached, waardoor het niet afgespeeld kan worden)\">uncache", + "mt_mloop": "De open map herhalen\">🔁 loop", + "mt_mnext": "Laad de volgende map en ga verder\">📂 next", + "mt_mstop": "Stoppen met afspelen\">⏸ stop", + "mt_cflac": "flac / wav omzetten naar opus\">flac", + "mt_caac": "aac / m4a omzetten naar opus\">aac", + "mt_coth": "Alle andere bestanden (geen mp3) converteren naar opus\">oth", + "mt_c2opus": "Beste keuze voor computers, laptops, android\">opus", + "mt_c2owa": "opus-weba, voor iOS 17.5 en nieuwer\">owa", + "mt_c2caf": "opus-caf, voor iOS 11 tot en met iOS 17\">caf", + "mt_c2mp3": "Gebruik dit hele oude toestellen\">mp3", + "mt_c2ok": "Mooi, goede keuze", + "mt_c2nd": "Dat is niet het aanbevolen uitvoerformaat voor uw apparaat, maar dat is prima", + "mt_c2ng": "Uw apparaat lijkt dit uitvoerformaat niet te ondersteunen, maar we gaan het toch proberen", + "mt_xowa": "iOS bevat bugs waardoor dit formaat niet op de achtergrond kan worden afgespeeld; gebruik in plaats daarvan caf of mp3.", + "mt_tint": "Achtergrond helderheid (0-100) op de zoekbalk om bufferen minder storend te maken", + "mt_eq": "Schakelt de equalizer en gain-control in;$N$Nboost <code>0</code> = standaard 100% volume (ongeweijzigd)$N$Nwidth <code>1  </code> = standaard stereo (ongeweijzigd)$Nwidth <code>0.5</code> = 50% links-rechts crossfeed$Nwidth <code>0  </code> = mono$N$Nboost <code>-0.8</code> & width <code>10</code> = stemverwijdering :^)$N$NDoor de equalizer in te schakelen, worden gapless albums volledig gapless. Laat hem dus aanstaan met alle waarden op nul (behalve width = 1) als je dat belangrijk vindt.", + "mt_drc": "Schakelt de dynamic range compressor in (volume flattener / brickwaller); schakelt ook EQ in om de spaghetti te balanceren, dus zet alle EQ velden behalve ‘width’ op 0 als je dat niet wilt.$N$Nverlaagt het volume van audio boven THRESHOLD dB; voor elke RATIO dB voorbij THRESHOLD is er 1 dB output, dus standaardwaarden van tresh -24 en ratio 12 betekenen dat het nooit luider dan -22 dB zou moeten worden en het is veilig om de equalizer boost te verhogen tot 0.8, of zelfs 1.8 met ATK 0 en een enorme RLS zoals 90 (werkt alleen in firefox; RLS is max 1 in andere browsers)$N$N(zie wikipedia, die legt het veel beter uit)", + + "mb_play": "Afspelen", + "mm_hashplay": "Deze audio bestand afspelen?", + "mm_m3u": "Druk op Enter/OK om af te spelen\nDruk op ESC/Cancel om te bewerken", + "mp_breq": "Heeft firefox 82+ of chrome 73+ of iOS 15+", + "mm_bload": "Aan het laden...", + "mm_bconv": "Opmzetten naar {0}, even geduld...", + "mm_opusen": "Uw browser kan geen aac / m4a-bestanden afspelen;\ntranscodering naar opus is nu ingeschakeld", + "mm_playerr": "Afspelen mislukt: ", + "mm_eabrt": "De afspeelpoging is geannuleerd", + "mm_enet": "Je internetverbinding is onstabiel", + "mm_edec": "Dit bestand is vermoedelijk beschadigd??", + "mm_esupp": "Uw browser begrijpt deze audio-formaat niet", + "mm_eunk": "Onbekende fout", + "mm_e404": "Kan audio niet afspelen; fout 404: Bestand niet gevonden..", + "mm_e403": "Kan audio niet afspelen; fout 403: Toegang geweigerd.\n\nProbeer op F5 te drukken om opnieuw te laden, misschien ben je uitgelogd", + "mm_e500": "Kan geen audio afspelen; fout 500: Controleer serverlogs.", + "mm_e5xx": "Kan geen audio afspelen; serverfout ", + "mm_nof": "Geen audiobestanden meer vinden in de buurt", + "mm_prescan": "Op zoek naar muziek om als volgende te spelen...", + "mm_scank": "Het volgende nummer gevonden:", + "mm_uncache": "Cache gewist; alle nummers worden opnieuw gedownload bij de volgende keer afspelen", + "mm_hnf": "Dat liedje bestaat niet meer", + + "im_hnf": "Deze afbeelding bestaat niet meer", + + "f_empty": 'Deze map is leeg', + "f_chide": 'Dit verbergt kolom «{0}»\n\nje kunt kolommen verbergen op de instellingen tabblad', + "f_bigtxt": "Dit bestand is {0} MiB groot -- echt bekijken als tekst?", + "f_bigtxt2": "Wilt u alleen het einde van het bestand bekijken? Dit maakt ook volgen/tailen mogelijk, waarbij nieuw toegevoegde tekstregels in realtime worden weergegeven.", + "fbd_more": '
{0} van de {1} bestanden weergegeven; Toon {2} of Laat alles zien
', + "fbd_all": '
{0} van de {1} bestanden weergegeven; Laat alles zien
', + "f_anota": "Alleen {0} van de {1} items zijn geselecteerd;\nom de volledige map te selecteren, scrol je eerst naar beneden", + + "f_dls": 'de bestandslinks in de huidige map zijn veranderd in downloadlinks', + + "f_partial": "Om een bestand dat momenteel wordt geüpload veilig te downloaden, klikt u op het bestand met dezelfde bestandsnaam, maar zonder de bestandsextensie .PARTIAL. Druk op Annuleren of Escape om dit te doen.\n\nAls u op OK / Enter drukt, wordt deze waarschuwing genegeerd en gaat u verder met het downloaden van het gedeeltelijke .PARTIAL scratchbestand, waardoor u vrijwel zeker beschadigde gegevens krijgt.", + + "ft_paste": "plakken {0} items$NHotkey: ctrl-V", + "fr_eperm": 'kan de naam niet wijzigen:\nje hebt geen “move” rechten in deze map', + "fd_eperm": 'kan niet verwijderen:\nje hebt geen “delete” rechten in deze map', + "fc_eperm": 'kan niet knippen:\nje hebt geen “move” rechten in deze map', + "fp_eperm": 'kan niet plakken:\nje hebt geen “schrijf” rechten in deze map', + "fr_emore": "selecteer ten minste één item om te hernoemen", + "fd_emore": "selecteer minstens één item om te verwijderen", + "fc_emore": "selecteer ten minste één item om te knippen", + "fcp_emore": "selecteer ten minste één item om naar het klembord te kopiëren", + + "fs_sc": "Deel de map waarin je je bevindt", + "fs_ss": "De geselecteerde bestand(en) delen", + "fs_just1d": "U kunt niet meer dan één map selecteren\nof mix bestanden en mappen in één selectie", + "fs_abrt": "❌ Afbreken", + "fs_rand": "🎲 rand.naam", + "fs_go": "✅ Maak share", + "fs_name": "Naam", + "fs_src": "Bron", + "fs_pwd": "Wachtwoord", + "fs_exp": "Verloopt", + "fs_tmin": "min", + "fs_thrs": "uur", + "fs_tdays": "dag(en)", + "fs_never": "eeuwig", + "fs_pname": "Optionele linknaam; is willekeurig als deze leeg is", + "fs_tsrc": "Het bestand of de map die u wilt delen", + "fs_ppwd": "Optioneel wachtwoord", + "fs_w8": "Delen...", + "fs_ok": "Druk op Enter/OK naar klembord te zetten\Druk op ESC/Cancel om te sluiten", + + "frt_dec": "Kan sommige gevallen van gebroken bestandsnamen oplossen\">url-decode", + "frt_rst": "Gewijzigde bestandsnamen terugzetten naar de oorspronkelijke namen\">↺ reset", + "frt_abrt": "Afbreken en dit venster sluiten\">❌ Annuleren", + "frb_apply": "HERNOEMEN TOEPASSEN", + "fr_adv": "Batch / metadata / patroon hernoemen\">Geavanceerd", + "fr_case": "Hoofdlettergevoelige regex\">case", + "fr_win": "Windows-veilige namen; vervangen <>:"\\|?* met japanse tekens over de volledige breedte\">win", + "fr_slash": "Vervang / met een teken waardoor er geen nieuwe mappen worden gemaakt\">geen /", + "fr_re": "Regex zoekpatroon om toe te passen op originele bestandsnamen; naar capturing groups kan worden verwezen in het onderstaande opmaakveld zoals <code>(1)</code> en <code>(2)</code> enzovoort", + "fr_fmt": "Geïnspireerd door foobar2000 :$N<code>(titel)</code> wordt vervangen door de titel van het nummer,$N<code>[(artiest) - ](titel)</code> sla [dit] gedeelte over als artiest leeg is$N<code>$lpad((tn),2,0)</code> vult tracknummer op tot 2 cijfers (0X)", + "fr_pdel": "Verwijderen", + "fr_pnew": "Opslaan als", + "fr_pname": "Geef een naam op voor je nieuwe preset", + "fr_aborted": "Afgebroken", + "fr_lold": "Oude naam", + "fr_lnew": "Nieuwe naam", + "fr_tags": "Tags voor de geselecteerde bestanden (alleen-lezen, alleen ter referentie):", + "fr_busy": "Hernoemen van {0} items...\n\n{1}", + "fr_efail": "Hernoemen mislukt:\n", + "fr_nchg": "{0} van de nieuwe namen zijn gewijzigd als gevolg van win en/of geen /\n\nOK om door te gaan met deze gewijzigde nieuwe namen?", + + "fd_ok": "Verwijderen OK", + "fd_err": "Verwijderen mislukt:\n", + "fd_none": "Er is niets verwijderd; misschien geblokkeerd door serverconfiguratie (xbd)?", + "fd_busy": "{0} items verwijderen...\n\n{1}", + "fd_warn1": "VERWIJDER deze {0} items?", + "fd_warn2": "LAATSTE KANS! Geen manier om ongedaan te maken. Verwijderen?", + + "fc_ok": "Knip {0} items", + "fc_warn": 'Knip {0} items\n\nmaar: alleen deze browser-tabblad kan weer plakken\n(omdat de selectie zo enorm is)', + + "fcc_ok": "{0} items naar klembord gekopieerd", + "fcc_warn": '{0} items naar klembord gekopieerd\n\maar: alleen deze browser-tabblad kan weer plakken\n(omdat de selectie zo enorm is)', + + "fp_apply": "Gebruik deze namen", + "fp_ecut": "Knip of kopieer eerst enkele bestanden/mappen om te verplaatsen/plakken\n\nnotitie: je kunt knippen/plakken in verschillende browsertabbladen", + "fp_ename": "{0} items kunnen hier niet worden verplaatst omdat de namen al in gebruik zijn. Geef ze hieronder een nieuwe naam om verder te gaan, of verwijder de naam om ze over te slaan:", + "fcp_ename": "{0} items kunnen hier niet worden gekopieerd omdat de namen al in gebruik zijn. Geef ze hieronder een nieuwe naam om verder te gaan, of verwijder de naam om ze over te slaan:", + "fp_emore": "Er zijn nog enkele bestandsnaambotsingen die moeten worden opgelost", + "fp_ok": "Verplaatsen OK", + "fcp_ok": "Kopiëren OK", + "fp_busy": "{0} items verplaatsen...\n\n{1}", + "fcp_busy": "{0} items kopiëren...\n\n{1}", + "fp_err": "Verplaatsen mislukt:\n", + "fcp_err": "Kopieëren mislukt:\n", + "fp_confirm": "Verplaats deze {0} items hierheen?", + "fcp_confirm": "Kopieer deze {0} items hier?", + "fp_etab": 'Kan klembord van ander browsertabblad niet lezen', + "fp_name": "Een bestand uploaden vanaf uw apparaat. Geef het een naam:", + "fp_both_m": '
Kies wat je wilt plakken
Enter = Verplaatsen {0} bestanden van «{1}»\nESC = Upload {2} bestanden van je apparaat', + "fcp_both_m": '
Kies wat je wilt plakken
Enter = Kopieer {0} bestanden van «{1}»\nESC = Upload {2} bestanden van je apparaat', + "fp_both_b": 'VerplaatsUpload', + "fcp_both_b": 'KopieerUpload', + + "mk_noname": "Voer een naam in het tekstveld aan de linkerkant voordat je verder gaat :p", + + "tv_load": "Tekstdocument laden:\n\n{0}\n\n{1}% ({2} van de {3} MiB geladen)", + "tv_xe1": "Kon tekstbestand niet laden:\n\nfout ", + "tv_xe2": "404, bestand niet gevonden", + "tv_lst": "Lijst met tekstbestanden in", + "tvt_close": "Terugkeren naar mapweergave$NHotkey: M (of Esc)\">❌ Sluiten", + "tvt_dl": "Download dit bestand$NHotkey: Y\">💾 download", + "tvt_prev": "Vorig document tonen$NHotkey: i\">⬆ prev", + "tvt_next": "Volgende document tonen$NHotkey: K\">⬇ next", + "tvt_sel": "Selecteer bestand   ( voor knip / verplaats / verwijder / ... )$NHotkey: S\">sel", + "tvt_edit": "Bestand openen in teksteditor$NHotkey: E\">✏️ bewerk", + "tvt_tail": "Bestand controleren op wijzigingen; nieuwe regels in realtime weergeven\">📡 volgen", + "tvt_wrap": "Automatische terugloop\">↵", + "tvt_atail": "Vergrendelen scroll naar onderkant van pagina\">⚓", + "tvt_ctail": "Kleuren van terminals decoderen (ansi escape codes)\">🌈", + "tvt_ntail": "Terugrollimiet (hoeveel tekst geladen moeten blijven)", + + "m3u_add1": "Nummer toegevoegd aan m3u afspeellijst", + "m3u_addn": "{0} nummers toegevoegd aan m3u-afspeellijst", + "m3u_clip": "m3u-afspeellijst nu gekopieerd naar klembord\n\nje moet een nieuw tekstbestand maken met de naam iets.m3u en de afspeellijst in dat document plakken; dit maakt het afspeelbaar", + + "gt_vau": "Laat geen video's zien, speel alleen de audio af\">🎧", + "gt_msel": "Schakel bestandsselectie in; ctrl-klik op een bestand om te openen$N$N<em>indien actief: dubbelklik op een bestand / map om het te openen</em>$N$NHotkey: S\">multiselect", + "gt_crop": "Gecentreerde miniaturen\">crop", + "gt_3x": "Hi-res miniaturen\">3x", + "gt_zoom": "Zoom", + "gt_chop": "Verkorten", + "gt_sort": "Sorteer bij", + "gt_name": "naam", + "gt_sz": "grootte", + "gt_ts": "datum", + "gt_ext": "type", + "gt_c1": "Bestandsnamen meer inkorten (minder tonen)", + "gt_c2": "Bestandsnamen minder inkorten (meer tonen)", + + "sm_w8": "Zoeken...", + "sm_prev": "Onderstaande zoekresultaten zijn afkomstig van een eerdere zoekopdracht:\n ", + "sl_close": "Zoekresultaten sluiten", + "sl_hits": "Toont {0} treffers", + "sl_moar": "Laad meer", + + "s_sz": "grootte", + "s_dt": "datum", + "s_rd": "pad", + "s_fn": "naam", + "s_ta": "tags", + "s_ua": "op@", + "s_ad": "adv.", + "s_s1": "Minimaal MiB", + "s_s2": "Maximaal MiB", + "s_d1": "Min. iso8601", + "s_d2": "Max. iso8601", + "s_u1": "Uploaded na", + "s_u2": "en/of voor", + "s_r1": "Pad bevad   (spatie-gescheiden)", + "s_f1": "Naam bevat   (ontkennen met -nope)", + "s_t1": "Tags bevat   (^=start, einde=$)", + "s_a1": "Specifieke metadata-eigenschappen", + + "md_eshow": "Kan niet weergeven ", + "md_off": "[📜readme] uitgeschakeld in [⚙️] -- document verborgen", + + "badreply": "Mislukt om antwoord van server te parsen", + + "xhr403": "403: Toegang geweigerd\n\nprobeer F5 in te drukken, misschien ben je uitgelogd", + "xhr0": "Onbekend (waarschijnlijk verbinding met server verloren of server is offline)", + "cf_ok": "Sorry daarvoor -- DD" + wah + "OS-bescherming ingeschakeld\n\nalles zou binnen ongeveer 30 seconden moeten hervatten\n\nals er niets gebeurt, druk dan op F5 om de pagina opnieuw te laden", + "tl_xe1": "Kon submappen niet weergeven:\n\nfout ", + "tl_xe2": "404: Map niet gevonden", + "fl_xe1": "Kon bestanden in map niet weergeven:\n\nfout ", + "fl_xe2": "404: Map niet gevonden", + "fd_xe1": "Kon submap niet aanmaken:\n\nfout ", + "fd_xe2": "404: Bovenliggende map niet gevonden", + "fsm_xe1": "Kon bericht niet verzenden:\n\nfout ", + "fsm_xe2": "404: Bovenliggende map niet gevonden", + "fu_xe1": "Mislukt om unpost lijst van server te laden:\n\nfout ", + "fu_xe2": "404: Bestand niet gevonden??", + + "fz_tar": "gnu-tar bestand uitpakken (linux / mac)", + "fz_pax": "pax-formaat tar uitpakken (trager)", + "fz_targz": "gnu-tar met gzip niveau 3 compressie$N$Ndit is meestal erg langzaam, dus gebruik in plaats daarvan ongecomprimeerde tar", + "fz_tarxz": "gnu-tar met xz-niveau 1 compressie$N$Ndit is meestal erg langzaam, dus gebruik in plaats daarvan ongecomprimeerde tar", + "fz_zip8": "Zip met utf8 bestandsnamen (misschien onhandig op windows 7 en ouder)", + "fz_zipd": "Zip met traditionele cp437-bestandsnamen, voor echt oude software", + "fz_zipc": "cp437 met crc32 vroeg berekend$Nvoor MS-DOS PKZIP v2.04g (oktober 1993)$N(het duurt langer voordat het downloaden kan beginnen)", + + "un_m1": "Hieronder kunt u uw recente uploads verwijderen (of onvoltooide uploads afbreken)", + "un_upd": "Vernieuwen", + "un_m4": "of deel de bestanden die hieronder zichtbaar zijn:", + "un_ulist": "Toon", + "un_ucopy": "Kopieer", + "un_flt": "Optionele filter:  URL moet het volgende bevatten", + "un_fclr": "Reset filter", + "un_derr": 'unpost-verwijderen mislukt:\n', + "un_f5": 'Er is iets kapot, probeer te verversen of druk op F5', + "un_uf5": "Sorry, maar u moet de pagina vernieuwen (bijvoorbeeld door op F5 of CTRL-R te drukken) voordat deze upload kan worden afgebroken.", + "un_nou": 'Waarschuwing: server te druk om onvoltooide uploads weer te geven; klik straks op de "refresh" link', + "un_noc": 'Waarschuwing: unpost van volledig geüploade bestanden is niet ingeschakeld/toegestaan in de serverconfiguratie', + "un_max": "Toont de eerste 2000 bestanden (gebruik de filter)", + "un_avail": "{0} recente uploads kunnen worden verwijderd
{1} onvoltooide kunnen worden afgebroken", + "un_m2": "Gesorteerd op uploadtijd; meest recente eerst:", + "un_no1": "sike! geen enkele upload is recent genoeg", + "un_no2": "sike! geen uploads die aan dat filter voldoen zijn voldoende recent", + "un_next": "Verwijder de volgende {0} bestanden", + "un_abrt": "Afbreken", + "un_del": "Verwijderen", + "un_m3": "Je recente uploads laden...", + "un_busy": "Verwijderen van {0} bestanden...", + "un_clip": "{0} links gekopieerd naar klembord", + + "u_https1": "Je moet", + "u_https2": "overschakelen naar https", + "u_https3": "voor betere prestaties", + "u_ancient": 'Je browser is indrukwekkend oud -- misschien moet je in plaats daarvan bup gebruiken', + "u_nowork": "Je moet firefox 53+ of chrome 57+ of iOS 11+ hebben", + "tail_2old": "Je moet firefox 105+ of chrome 71+ of iOS 14.5+ hebben", + "u_nodrop": 'Je browser is te oud voor uploaden via slepen en neerzetten', + "u_notdir": "Dat is geen map!\n\nuw browser is te oud,\nprobeer in plaats daarvan sleep en neerzetten", + "u_uri": "Om afbeeldingen te slepen vanuit andere browser tabblad,\nplaats deze dan op de grote uploadknop", + "u_enpot": 'Overschakelen naar potato UI (kan uploadsnelheid verbeteren)', + "u_depot": 'Overschakelen naar fancy UI (kan uploadsnelheid verminderen)', + "u_gotpot": 'Overschakelen naar de potato UI voor verbeterde uploadsnelheid,\n\nVoel je vrij om het er niet mee eens te zijn en schakel terug!', + "u_pott": "

Bestanden:   {0} klaar,   {1} mislukt,   {2} bezig,   {3} in de wachtrij

", + "u_ever": "Dit is de basis uploader; up2k heeft minstens het volgende nodig
chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1", + "u_su2k": 'Dit is de basis uploader; up2k is beter', + "u_uput": 'Optimaliseren voor snelheid (checksum overslaan)', + "u_ewrite": 'Je hebt geen schrijftoegang tot deze map', + "u_eread": 'Je hebt geen leestoegang tot deze map', + "u_enoi": 'Zoeken naar bestanden is niet ingeschakeld in de serverconfiguratie', + "u_enoow": "Overschrijven zal hier niet werken; je heb verwijder toestemming nodig", + "u_badf": 'Deze {0} bestanden (van {1} totaal) zijn overgeslagen, mogelijk door bestandssysteemmachtigingen:\n\n', + "u_blankf": 'Deze {0} bestanden (van {1} totaal) zijn leeg; alsnog uploaden?\n\n', + "u_applef": 'Deze {0} bestanden (van {1} totaal) zijn waarschijnlijk ongewenst;\nKlik op OK/Enter om de volgende bestanden over te slaan,\Klik op Cancel/ESC niet uit te sluiten en deze ook te uploaden:\n\n', + "u_just1": '\nMisschien werkt het beter als je slechts één bestand selecteert', + "u_ff_many": "Als je Linux / MacOS / Android, gebruikt dan kan deze hoeveelheid bestanden Firefox crashen!\nals dat gebeurt, probeer het dan opnieuw (of gebruik Chrome).", + "u_up_life": "Deze upload wordt verwijderd van de server\n{0} nadat het is voltooid", + "u_asku": 'Upload deze {0} bestanden naar {1}', + "u_unpt": "Je kunt deze upload ongedaan maken / verwijderen met de linkerbovenhoek 🧯", + "u_bigtab": 'We staan op het punt om {0} bestanden te tonen\n\nDit kan uw browser laten crashen, weet je het zeker??', + "u_scan": 'Bestanden scannen...', + "u_dirstuck": 'Directory iterator liep vast bij het benaderen van het volgende {0} items; zal het volgende overslaan:', + "u_etadone": 'Klaar ({0}, {1} bestanden)', + "u_etaprep": '(klaarmaken om te uploaden)', + "u_hashdone": 'hashing klaar', + "u_hashing": 'Hash', + "u_hs": 'Hallo zeggen...', + "u_started": "De bestanden worden nu geüpload; zie [🚀]", + "u_dupdefer": "Duplicaat; wordt verwerkt na alle andere bestanden", + "u_actx": "klik op deze tekst om prestatieverlies
bij het overschakelen naar andere vensters/tabbladen te voorkomen", + "u_fixed": "OK!  Fixed it 👍", + "u_cuerr": "Mislukt bij het uploaden van stuk {0} van {1};\nwaarschijnlijk ongevaarlijk, doorgaan\n\nbestand: {2}", + "u_cuerr2": "Upload door server geweigerd (stuk {0} van {1});\nzal later opnieuw proberen\n\nbestand: {2}\n\nfout ", + "u_ehstmp": "Zal opnieuw proberen; zie rechtsonder", + "u_ehsfin": "Server heeft het verzoek om de upload te finaliseren afgewezen; opnieuw proberen...", + "u_ehssrch": "Server heeft de zoekaanvraag afgewezen; opnieuw proberen...", + "u_ehsinit": "Server heeft het verzoek om het uploaden te starten afgewezen; opnieuw proberen...", + "u_eneths": "Netwerkfout tijdens het uitvoeren van de uploadhanddruk; opnieuw proberen...", + "u_enethd": "Netwerkfout tijdens het testen van het bestaan van het doel; opnieuw proberen...", + "u_cbusy": "Wachten tot de server ons weer vertrouwt na een netwerkstoring...", + "u_ehsdf": "Server heeft geen schijfruimte meer!\n\nzal blijven proberen, voor het geval iemand genoeg ruimte vrijmaakt om door te gaan", + "u_emtleak1": "Het lijkt erop dat uw webbrowser een geheugenlek heeft;\nprobeer", + "u_emtleak2": ' over te schakel over naar https (aanbevolen) of ', + "u_emtleak3": ' ', + "u_emtleakc": 'Probeer het volgende:\n
  • druk op F5 om de pagina te verversen
  • dan schakel de  mt  uit, deze knop staat in  ⚙️ instellingen
  • en probeer de upload opnieuw
Uploaden zal wat langzamer gaan, maar ja.\nSorry voor de problemen!\n\nPS: chrome v107 heeft een bugfix voor dit', + "u_emtleakf": '{robeer het volgende:\n
  • druk op F5 om de pagina te verversen
  • dan activeer 🥔 (aardappel) in de upload scherm
  • en probeer de upload opnieuw
\nPS: firefox heeft mogelijk een fix op een gegeven moment', + "u_s404": "Niet gevonden op server", + "u_expl": "Leg uit", + "u_maxconn": "De meeste browsers beperken dit tot 6, maar firefox laat je dit verhogen met network.http.max-persistent-connections-per-server in about:config", + "u_tu": '

WAARSCHUWING: turbo ingeschakeld,  webbrowser detecteert en hervat onvolledige uploads mogelijk niet; zie de tooltip van de turboknop

', + "u_ts": '

WAARSCHUWING: turbo ingeschakeld,  zoekresultaten kunnen onjuist zijn; zie turbo-knop tooltip

', + "u_turbo_c": "Turbo is uitgeschakeld in serverconfiguratie", + "u_turbo_g": "Turbo uitgeschakeld, je geen recht om mappen in deze volume te tonen", + "u_life_cfg": 'Automatisch verwijderen na minuten (of uur)', + "u_life_est": 'Upload wordt verwijderd ---', + "u_life_max": 'Deze map dwingt een\nmaximale levensduur van {0} af', + "u_unp_ok": 'unpost is toegestaan voor {0}', + "u_unp_ng": 'unpost zijn NIET toegestaan', + "ue_ro": 'Je toegang tot deze map is alleen-lezen\n\n', + "ue_nl": 'Je bent momenteel niet ingelogd', + "ue_la": 'Je bent momenteel aangemeld als "{0}"', + "ue_sr": 'U bevindt zich momenteel in de bestandszoekmodus\n\nschakel over naar uploadmodus door op het vergrootglas te klikken 🔎 (naast de grote ZOEK-knop), en probeer opnieuw te uploaden\n\nsorry', + "ue_ta": 'Probeer opnieuw te uploaden, het zou nu moeten werken', + "ue_ab": "Dit bestand wordt al geüpload naar een andere map en die upload moet worden voltooid voordat het bestand naar een andere map kan worden geüpload.\n\nU kunt de eerste upload afbreken en laten vergeten met de linkerbovenhoek 🧯", + "ur_1uo": "OK: Bestand succesvol geüpload", + "ur_auo": "OK: Alle {0} bestanden succesvol geüpload", + "ur_1so": "OK: Bestand gevonden op server", + "ur_aso": "OK: Alle {0} bestanden gevonden op server", + "ur_1un": "Uploaden mislukt, sorry", + "ur_aun": "Alle {0} uploads mislukt, sorry", + "ur_1sn": "Bestand NIET gevonden op server", + "ur_asn": "De {0} bestanden zijn NIET gevonden op de server", + "ur_um": "Voltooid;\n{0} upload(s) OK,\n{1} upload(s) mislukt, sorry", + "ur_sm": "Voltooid;\n{0} bestand(en) gevonden op de server,\n{1} bestand(en) NIET gevonden op de server", + + "lang_set": "Vernieuw de pagina om de wijziging door te voeren?", + }, "rus": { "tt": "Русский", @@ -5023,7 +5650,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "deu", "fin", "rus", "spa", "ukr"]; +var LANGS = ["eng", "nor", "chi", "deu", "fin", "nld", "rus", "spa", "ukr"]; if (window.langmod) langmod(); diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 4ad53b9b..06cb0bf7 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -176,6 +176,48 @@ var Ls = { "af1": "näytä viimeaikaiset lataukset", "ag1": "näytä tunnetut IdP-käyttäjät", }, + "nld": { + "a1": "Update", + "b1": "Hallo, hoe gaat het met jou?   (Je bent niet ingelogd)", + "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:", + "m1": "Welkom terug,", + "n1": "404: bestand bestaat niet  ┐( ´ -`)┌", + "o1": 'of misschien heb je geen toegang? probeer een wachtwoord of ga naar startscherm', + "p1": "403: toegang geweigerd  ~┻━┻", + "q1": 'Probeer een wachtwoord of ga naar startscherm', + "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", + }, "spa": { "a1": "actualizar", "b1": "hola   (no has iniciado sesión)", From a38e6e65d5e578fcfc6940dcb88c0269582e7556 Mon Sep 17 00:00:00 2001 From: AOTREVAI <46420278+AOTREVAI@users.noreply.github.com> Date: Sun, 3 Aug 2025 20:38:16 +0200 Subject: [PATCH 06/66] Translate to Italian (#458) * Translating to Italian * Update browser.js * sync splash.js, browser.js * Update browser.js * Update splash.js --------- Signed-off-by: AOTREVAI <46420278+AOTREVAI@users.noreply.github.com> --- copyparty/web/browser.js | 629 ++++++++++++++++++++++++++++++++++++++- copyparty/web/splash.js | 42 +++ 2 files changed, 670 insertions(+), 1 deletion(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index af0c0e39..b26f02fc 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3141,6 +3141,633 @@ var Ls = { "lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?", }, + "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)"], + ] + ], + + "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 ", + "access": " accesso", + "ot_close": "chiudi sottomenu", + "ot_search": "cerca file per attributi, percorso / nome, tag musicali, o qualsiasi combinazione di questi$N$N<code>foo bar</code> = deve contenere sia «foo» che «bar»,$N<code>foo -bar</code> = deve contenere «foo» ma non «bar»,$N<code>^yana .opus$</code> = inizia con «yana» ed è un file «opus»$N<code>"try unite"</code> = contiene esattamente «try unite»$N$Nil formato data è iso-8601, come$N<code>2009-12-31</code> o <code>2020-09-12 23:30:00</code>", + "ot_unpost": "unpost: elimina i tuoi caricamenti recenti, o interrompi quelli non completati", + "ot_bup": "bup: uploader di base, supporta anche netscape 4.0", + "ot_mkdir": "mkdir: crea una nuova directory", + "ot_md": "new-md: crea un nuovo documento markdown", + "ot_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 [🎈]  (l\'uploader di base)

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 [🎈]  (l\'uploader di base)

durante i caricamenti, questa icona diventa un indicatore di progresso!', + "ot_noie": 'Perfavore usa Chrome / Firefox / Edge', + + "ab_mkdir": "crea directory", + "ab_mkdoc": "nuovo doc markdown", + "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 <small>(poi incolla altrove)</small>$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 📻copia 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", + "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
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 <em>hashing</em>, e tempo stimato al completamento", + "ut_etau": "velocità media di <em>caricamento</em> e tempo stimato al completamento", + "ut_etat": "velocità <em>totale</em> 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
tuttavia c'è un up2k occupato in un'altra scheda del browser,
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": '
ok, cosa hai?
Invio = File (uno o più)\nESC = Una cartella (incluse sottocartelle)', + "u_nav_b": 'FileUna cartella', + + "cl_opts": "opzioni", + "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", + + "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_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 "questo ha la stessa dimensione file sul server?" quindi se il contenuto del file è diverso NON verrà caricato$N$NDovresti spegnere questo quando il caricamento è finito, e poi "caricare" 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 teoricamente 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 (<code>,sorthref</code>) includere negli URL multimediali. Impostandolo a 0 ignorerà anche le regole di ordinamento incluse nei link multimediali quando li clicchi", + + "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  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 inaffidabili,$N❌ disabilita 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  (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 opus\">flac", + "mt_caac": "converti aac / m4a in opus\">aac", + "mt_coth": "converti tutti gli altri (non mp3) in opus\">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_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 <code>0</code> = volume standard 100% (non modificato)$N$Nwidth <code>1  </code> = stereo standard (non modificato)$Nwidth <code>0.5</code> = 50% crossfeed sinistra-destra$Nwidth <code>0  </code> = mono$N$Nboost <code>-0.8</code> & width <code>10</code> = 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 Invio/OK per Riprodurre\npremi ESC/Annulla 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": '
mostrando {0} di {1} file; mostra {2} o mostra tutti
', + "fbd_all": '
mostrando {0} di {1} file; mostra tutti
', + "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 .PARTIAL. Premi ANNULLA o Escape per farlo.\n\nPremendo OK / Invio ignorerai questo avviso e continuerai a scaricare il file .PARTIAL 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 Invio/OK per Appunti\npremi ESC/Annulla 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 <>:"\\|?* con caratteri giapponesi fullwidth\">win", + "fr_slash": "sostituisce / 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 <code>(1)</code> e <code>(2)</code> e così via", + "fr_fmt": "ispirato da foobar2000:$N<code>(title)</code> è sostituito dal titolo della canzone,$N<code>[(artist) - ](title)</code> salta [questa] parte se artista è vuoto$N<code>$lpad((tn),2,0)</code> 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 win e/o no /\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": "Ultima possibilità! Nessun modo per annullare. Eliminare?", + + "fc_ok": "tagliati {0} elementi", + "fc_warn": 'tagliati {0} elementi\n\nma: solo questa 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 questa scheda-browser può incollarli\n(dato che la selezione è così assolutamente massiva)', + + "fp_apply": "usa questi nomi", + "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 per saltarli:", + "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 per saltarli:", + "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_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": '
scegli cosa incollare
Invio = Sposta {0} file da «{1}»\nESC = Carica {2} file dal tuo dispositivo', + "fcp_both_m": '
scegli cosa incollare
Invio = Copia {0} file da «{1}»\nESC = Carica {2} file dal tuo dispositivo', + "fp_both_b": 'SpostaCarica', + "fcp_both_b": 'CopiaCarica', + + "mk_noname": "scrivi un nome nel campo di testo a sinistra prima di farlo :p", + + "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   ( per taglia / copia / elimina / ... )$NTasto rapido: S\">sel", + "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<em>quando attivo: doppio-click un file / cartella per aprirlo</em>$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   (separato da spazi)", + "s_f1": "nome contiene   (nega con -nope)", + "s_t1": "tag contiene   (^=inizio, fine=$)", + "s_a1": "proprietà metadata specifiche", + + "md_eshow": "impossibile renderizzare ", + "md_off": "[📜readme] 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:  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": 'avviso: server troppo occupato per mostrare caricamenti non finiti; clicca il link "aggiorna" tra un po\'', + "un_noc": 'avviso: 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
{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 usare bup invece', + "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 UI patata (può migliorare velocità upload)', + "u_depot": 'passa alla UI elegante (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": "

file:   {0} finiti,   {1} falliti,   {2} occupati,   {3} in coda

", + "u_ever": "questo è l'uploader di base; up2k necessita almeno
chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1", + "u_su2k": 'questo è l\'uploader di base; up2k è 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 OK/Invio per SALTARE i seguenti file,\nPremi Annulla/ESC 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 Linux / MacOS / Android, allora questa quantità di file potrebbe far crashare Firefox!\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 {1}', + "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
prestazioni quando cambi ad altre finestre/schede", + "u_fixed": "OK!  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": ' passa a https (raccomandato) o ', + "u_emtleak3": ' ', + "u_emtleakc": 'prova quanto segue:\n
  • premi F5 per aggiornare la pagina
  • poi disabilita il pulsante  mt  nelle  ⚙️ impostazioni
  • e riprova quel caricamento
I caricamenti saranno un po\' più lenti, ma pazienza.\nScusa per il disturbo !\n\nPS: chrome v107 ha un bugfix per questo', + "u_emtleakf": 'prova quanto segue:\n
  • premi F5 per aggiornare la pagina
  • poi abilita 🥔 (patata) nell\'UI caricamento
  • e riprova quel caricamento
\nPS: firefox avrà sperabilmente un bugfix 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 connections-per-server in about:config", + "u_tu": '

AVVISO: turbo abilitato,  client potrebbe non rilevare e riprendere caricamenti incompleti; vedi tooltip pulsante turbo

', + "u_ts": '

AVVISO: turbo abilitato,  risultati ricerca possono essere incorretti; vedi tooltip pulsante turbo

', + "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 min (o ore)', + "u_life_est": 'caricamento sarà eliminato ---', + "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", + + "lang_set": "aggiornare per rendere effettivo il cambiamento?", + }, "nld": { "tt": "Nederlands", @@ -5650,7 +6277,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "deu", "fin", "nld", "rus", "spa", "ukr"]; +var LANGS = ["eng", "nor", "chi", "deu", "fin", "ita", "nld", "rus", "spa", "ukr"]; if (window.langmod) langmod(); diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 06cb0bf7..44f315ff 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -176,6 +176,48 @@ var Ls = { "af1": "näytä viimeaikaiset lataukset", "ag1": "näytä tunnetut IdP-käyttäjät", }, + "ita": { + "a1": "aggiorna", + "b1": "ciao   (non sei connesso)", + "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:", + "m1": "bentornato,", + "n1": "404: file non trovato  ┐( ´ -`)┌", + "o1": "oppure forse non hai accesso? prova una password o torna alla home", + "p1": "403: accesso negato  ~┻━┻", + "q1": "prova una password o torna alla home", + "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" +}, "nld": { "a1": "Update", "b1": "Hallo, hoe gaat het met jou?   (Je bent niet ingelogd)", From b469db3c621a93a258924b1bb399c5672607bc8e Mon Sep 17 00:00:00 2001 From: Toby Kohlhagen Date: Sun, 3 Aug 2025 23:26:13 +1000 Subject: [PATCH 07/66] Add wav transcoding option --- copyparty/httpcli.py | 2 +- copyparty/mtag.py | 2 ++ copyparty/th_cli.py | 4 ++-- copyparty/th_srv.py | 45 +++++++++++++++++++++++++++++++++++++--- copyparty/web/browser.js | 15 ++++++++++---- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index bea4ce43..51620912 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -4684,7 +4684,7 @@ class HttpCli(object): # for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]})) cfmt = "" if self.thumbcli and not self.args.no_bacode: - for zs in ("opus", "mp3", "w", "j", "p"): + for zs in ("opus", "mp3", "wav", "w", "j", "p"): if zs in self.ouparam or uarg == zs: cfmt = zs diff --git a/copyparty/mtag.py b/copyparty/mtag.py index cacfda39..240b5a83 100644 --- a/copyparty/mtag.py +++ b/copyparty/mtag.py @@ -270,6 +270,8 @@ def parse_ffprobe(txt: str) -> tuple[dict[str, tuple[int, Any]], dict[str, list[ ["channel_layout", "chs"], ["sample_rate", ".hz"], ["bit_rate", ".aq"], + ["bits_per_sample", ".bps"], + ["bits_per_raw_sample", ".bprs"], ["duration", ".dur"], ] diff --git a/copyparty/th_cli.py b/copyparty/th_cli.py index cfb148c2..6c2632b5 100644 --- a/copyparty/th_cli.py +++ b/copyparty/th_cli.py @@ -88,7 +88,7 @@ class ThumbCli(object): if rem.startswith(".hist/th/") and rem.split(".")[-1] in ["webp", "jpg", "png"]: return os.path.join(ptop, rem) - if fmt[:1] in "jw": + if fmt[:1] in "jw" and fmt != "wav": sfmt = fmt[:1] if sfmt == "j" and self.args.th_no_jpg: @@ -129,7 +129,7 @@ class ThumbCli(object): tpath = thumb_path(histpath, rem, mtime, fmt, self.fmt_ffa) tpaths = [tpath] - if fmt[:1] == "w": + if fmt[:1] == "w" and fmt != "wav": # also check for jpg (maybe webp is unavailable) tpaths.append(tpath.rsplit(".", 1)[0] + ".jpg") diff --git a/copyparty/th_srv.py b/copyparty/th_srv.py index 67413c10..8eaf9287 100644 --- a/copyparty/th_srv.py +++ b/copyparty/th_srv.py @@ -50,7 +50,7 @@ HAVE_AVIF = False HAVE_WEBP = False EXTS_TH = set(["jpg", "webp", "png"]) -EXTS_AC = set(["opus", "owa", "caf", "mp3"]) +EXTS_AC = set(["opus", "owa", "caf", "mp3", "wav"]) EXTS_SPEC_SAFE = set("aif aiff flac mp3 opus wav".split()) PTN_TS = re.compile("^-?[0-9a-f]{8,10}$") @@ -355,8 +355,9 @@ class ThumbSrv(object): tex = tpath.rsplit(".", 1)[-1] want_mp3 = tex == "mp3" want_opus = tex in ("opus", "owa", "caf") + want_wav = tex == "wav" want_png = tex == "png" - want_au = want_mp3 or want_opus + want_au = want_mp3 or want_opus or want_wav for lib in self.args.th_dec: can_au = lib == "ff" and ( ext in self.fmt_ffa or ext in self.fmt_ffv @@ -371,6 +372,8 @@ class ThumbSrv(object): funs.append(self.conv_opus) elif want_mp3: funs.append(self.conv_mp3) + elif want_wav: + funs.append(self.conv_wav) elif want_png: funs.append(self.conv_waves) png_ok = True @@ -580,7 +583,7 @@ class ThumbSrv(object): self._run_ff(cmd, vn) def _run_ff(self, cmd: list[bytes], vn: VFS, oom: int = 400) -> None: - # self.log((b" ".join(cmd)).decode("utf-8")) + self.log((b" ".join(cmd)).decode("utf-8")) ret, _, serr = runcmd(cmd, timeout=vn.flags["convt"], nice=True, oom=oom) if not ret: return @@ -807,6 +810,42 @@ class ThumbSrv(object): # fmt: on self._run_ff(cmd, vn, oom=300) + def conv_wav(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: + if self.args.no_acode or not self.args.q_wav: + raise Exception("disabled in server config") + + self.wait4ram(0.2, tpath) + tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2)) + if "ac" not in tags: + raise Exception("not audio") + + bits = tags[".bps"][1] + if bits == 0.0: + bits = tags[".bprs"][1] + + codec = b"pcm_s32le" + if bits == 16.0: + codec = b"pcm_s16le" + elif bits == 24.0: + codec = b"pcm_s24le" + + self.log("conv2 wav-tmp", 6) + + # fmt: off + cmd = [ + b"ffmpeg", + b"-nostdin", + b"-v", b"error", + b"-hide_banner", + b"-i", fsenc(abspath), + b"-map", b"0:a:0", + b"-c:a", codec, + fsenc(tpath) + ] + # fmt: on + print(cmd) + self._run_ff(cmd, vn, oom=300) + def conv_opus(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: if self.args.no_acode or not self.args.q_opus: raise Exception("disabled in server config") diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index b26f02fc..bd9fbbe7 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -306,6 +306,7 @@ var Ls = { "mt_c2owa": "opus-weba, for iOS 17.5 and newer\">owa", "mt_c2caf": "opus-caf, for iOS 11 through 17\">caf", "mt_c2mp3": "use this on very old devices\">mp3", + "mt_c2wav": "use this for uncompressed playback\">wav", "mt_c2ok": "nice, good choice", "mt_c2nd": "that's not the recommended output format for your device, but that's fine", "mt_c2ng": "your device does not seem to support this output format, but let's try anyways", @@ -6802,6 +6803,7 @@ var mpl = (function () { ' None: - self.log((b" ".join(cmd)).decode("utf-8")) + # self.log((b" ".join(cmd)).decode("utf-8")) ret, _, serr = runcmd(cmd, timeout=vn.flags["convt"], nice=True, oom=oom) if not ret: return @@ -810,8 +813,33 @@ class ThumbSrv(object): # fmt: on self._run_ff(cmd, vn, oom=300) + def conv_flac(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: + if self.args.no_acode or self.args.no_flac: + raise Exception("disabled in server config") + + self.wait4ram(0.2, tpath) + tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2)) + if "ac" not in tags: + raise Exception("not audio") + + self.log("conv2 flac", 6) + + # fmt: off + cmd = [ + b"ffmpeg", + b"-nostdin", + b"-v", b"error", + b"-hide_banner", + b"-i", fsenc(abspath), + b"-map", b"0:a:0", + b"-c:a", b"flac", + fsenc(tpath) + ] + # fmt: on + self._run_ff(cmd, vn, oom=300) + def conv_wav(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: - if self.args.no_acode or not self.args.q_wav: + if self.args.no_acode or self.args.no_wav: raise Exception("disabled in server config") self.wait4ram(0.2, tpath) @@ -824,12 +852,12 @@ class ThumbSrv(object): bits = tags[".bprs"][1] codec = b"pcm_s32le" - if bits == 16.0: + if bits <= 16.0: codec = b"pcm_s16le" - elif bits == 24.0: + elif bits <= 24.0: codec = b"pcm_s24le" - self.log("conv2 wav-tmp", 6) + self.log("conv2 wav", 6) # fmt: off cmd = [ @@ -843,7 +871,6 @@ class ThumbSrv(object): fsenc(tpath) ] # fmt: on - print(cmd) self._run_ff(cmd, vn, oom=300) def conv_opus(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index bd9fbbe7..201b3588 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -306,7 +306,8 @@ var Ls = { "mt_c2owa": "opus-weba, for iOS 17.5 and newer\">owa", "mt_c2caf": "opus-caf, for iOS 11 through 17\">caf", "mt_c2mp3": "use this on very old devices\">mp3", - "mt_c2wav": "use this for uncompressed playback\">wav", + "mt_c2flac": "best sound quality\">flac", + "mt_c2wav": "uncompressed playback\">wav", "mt_c2ok": "nice, good choice", "mt_c2nd": "that's not the recommended output format for your device, but that's fine", "mt_c2ng": "your device does not seem to support this output format, but let's try anyways", @@ -6803,6 +6804,7 @@ var mpl = (function () { 'owa", "mt_c2caf": "opus-caf, for iOS 11 through 17\">caf", "mt_c2mp3": "use this on very old devices\">mp3", + "mt_c2flac": "best sound quality\">flac", + "mt_c2wav": "uncompressed playback\">wav", "mt_c2ok": "nice, good choice", "mt_c2nd": "that's not the recommended output format for your device, but that's fine", "mt_c2ng": "your device does not seem to support this output format, but let's try anyways", From 0d09fb681869932b16015e5cba0b068ed4a27508 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:23:41 +0000 Subject: [PATCH 09/66] audio transcoding tweaks --- README.md | 3 +++ copyparty/__main__.py | 4 ++-- copyparty/authsrv.py | 2 ++ copyparty/mtag.py | 4 +++- copyparty/th_srv.py | 8 ++++---- copyparty/web/browser.js | 37 ++++++++++++++++++++++++++----------- copyparty/web/splash.js | 1 + scripts/tl.js | 5 +++-- 8 files changed, 44 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1a500c5b..93b6a464 100644 --- a/README.md +++ b/README.md @@ -1084,6 +1084,9 @@ open the `[🎺]` media-player-settings tab to configure it, * `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1 * `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the most part * `[mp3]` -- the myth, the legend, the undying master of mediocre sound quality that definitely works everywhere + * `[flac]` -- lossless but compressed, for LAN and/or fiber playback on electrostatic headphones + * `[wav]` -- lossless and uncompressed, for LAN and/or fiber playback on electrostatic headphones connected to very old equipment + * `flac` and `wav` must be enabled with `--allow-flac` / `--allow-wav` to allow spending the disk space * "tint" reduces the contrast of the playback bar diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 183fb916..21bda508 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1447,10 +1447,10 @@ def add_transcoding(ap): ap2 = ap.add_argument_group('transcoding options') ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable") ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable") + ap2.add_argument("--allow-wav", action="store_true", help="allow transcoding to wav (lossless, uncompressed)") + ap2.add_argument("--allow-flac", action="store_true", help="allow transcoding to flac (lossless, compressed)") ap2.add_argument("--no-caf", action="store_true", help="disable transcoding to caf-opus (affects iOS v12~v17), will use mp3 instead") ap2.add_argument("--no-owa", action="store_true", help="disable transcoding to webm-opus (iOS v18 and later), will use mp3 instead") - ap2.add_argument("--no-wav", action="store_true", help="disable transcoding to wav (lossless, uncompressed)") - ap2.add_argument("--no-flac", action="store_true", help="disable transcoding to flac (lossless, compressed)") ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding") ap2.add_argument("--no-bacode", action="store_true", help="disable batch audio transcoding by folder download (zip/tar)") ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 01fad895..76a09ecd 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -2751,6 +2751,8 @@ class AuthSrv(object): "s_name": self.args.bname, "have_up2k_idx": "e2d" in vf, "have_acode": not self.args.no_acode, + "have_c2flac": self.args.allow_flac, + "have_c2wav": self.args.allow_wav, "have_shr": self.args.shr, "have_zip": not self.args.no_zip, "have_mv": not self.args.no_mv, diff --git a/copyparty/mtag.py b/copyparty/mtag.py index 240b5a83..e9428b79 100644 --- a/copyparty/mtag.py +++ b/copyparty/mtag.py @@ -67,6 +67,8 @@ HAVE_FFPROBE = not os.environ.get("PRTY_NO_FFPROBE") and have_ff("ffprobe") CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif".split()) CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b") +FMT_AU = set("mp3 ogg flac wav".split()) + class MParser(object): def __init__(self, cmdline: str) -> None: @@ -242,7 +244,7 @@ def parse_ffprobe(txt: str) -> tuple[dict[str, tuple[int, Any]], dict[str, list[ ret: dict[str, Any] = {} # processed md: dict[str, list[Any]] = {} # raw tags - is_audio = fmt.get("format_name") in ["mp3", "ogg", "flac", "wav"] + is_audio = fmt.get("format_name") in FMT_AU if fmt.get("filename", "").split(".")[-1].lower() in ["m4a", "aac"]: is_audio = True diff --git a/copyparty/th_srv.py b/copyparty/th_srv.py index e8094b5a..f40d0a43 100644 --- a/copyparty/th_srv.py +++ b/copyparty/th_srv.py @@ -814,8 +814,8 @@ class ThumbSrv(object): self._run_ff(cmd, vn, oom=300) def conv_flac(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: - if self.args.no_acode or self.args.no_flac: - raise Exception("disabled in server config") + if self.args.no_acode or not self.args.allow_flac: + raise Exception("flac not permitted in server config") self.wait4ram(0.2, tpath) tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2)) @@ -839,8 +839,8 @@ class ThumbSrv(object): self._run_ff(cmd, vn, oom=300) def conv_wav(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None: - if self.args.no_acode or self.args.no_wav: - raise Exception("disabled in server config") + if self.args.no_acode or not self.args.allow_wav: + raise Exception("wav not permitted in server config") self.wait4ram(0.2, tpath) tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2)) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 201b3588..3dca9476 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -4,6 +4,7 @@ var XHR = XMLHttpRequest, img_re = /\.(a?png|avif|bmp|gif|heif|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov)(\?|$)/i; // please add translations in alphabetic order, but keep "eng" and "nor" first +// (lines ending with //m are machine translations) var Ls = { "eng": { "tt": "English", @@ -306,8 +307,8 @@ var Ls = { "mt_c2owa": "opus-weba, for iOS 17.5 and newer\">owa", "mt_c2caf": "opus-caf, for iOS 11 through 17\">caf", "mt_c2mp3": "use this on very old devices\">mp3", - "mt_c2flac": "best sound quality\">flac", - "mt_c2wav": "uncompressed playback\">wav", + "mt_c2flac": "best sound quality, but huge downloads\">flac", + "mt_c2wav": "uncompressed playback (even bigger)\">wav", "mt_c2ok": "nice, good choice", "mt_c2nd": "that's not the recommended output format for your device, but that's fine", "mt_c2ng": "your device does not seem to support this output format, but let's try anyways", @@ -936,6 +937,8 @@ var Ls = { "mt_c2owa": "opus-weba, for iOS 17.5 og nyere\">owa", "mt_c2caf": "opus-caf, for iOS 11 tilogmed 17\">caf", "mt_c2mp3": "bra valg for steinalder-utstyr (slår aldri feil)\">mp3", + "mt_c2flac": "gir best lydkvalitet, men eter nettet ditt\">flac", + "mt_c2wav": "helt rå lydstrøm (bruker enda mere data enn flac)\">wav", "mt_c2ok": "bra valg!", "mt_c2nd": "ikke det foretrukne valget for din enhet, men funker sikkert greit", "mt_c2ng": "ser virkelig ikke ut som enheten din takler dette formatet... men ok, vi prøver", @@ -1563,6 +1566,8 @@ var Ls = { "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 @@ -2190,6 +2195,8 @@ var Ls = { "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 große Downloads\">flac", //m + "mt_c2wav": "unkomprimierte Wiedergabe (noch größer)\">wav", //m "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", @@ -2817,6 +2824,8 @@ var Ls = { "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", @@ -3444,6 +3453,8 @@ var Ls = { "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", @@ -4071,6 +4082,8 @@ var Ls = { "mt_c2owa": "opus-weba, voor iOS 17.5 en nieuwer\">owa", "mt_c2caf": "opus-caf, voor iOS 11 tot en met iOS 17\">caf", "mt_c2mp3": "Gebruik dit hele oude toestellen\">mp3", + "mt_c2flac": "Beste geluidskwaliteit, maar grote downloads\">flac", //m + "mt_c2wav": "Ongemprimeerde weergave (nog groter)\">wav", //m "mt_c2ok": "Mooi, goede keuze", "mt_c2nd": "Dat is niet het aanbevolen uitvoerformaat voor uw apparaat, maar dat is prima", "mt_c2ng": "Uw apparaat lijkt dit uitvoerformaat niet te ondersteunen, maar we gaan het toch proberen", @@ -4698,6 +4711,8 @@ var Ls = { "mt_c2owa": "opus-weba, для iOS 17.5 и выше\">owa", "mt_c2caf": "opus-caf, для iOS 11-17\">caf", "mt_c2mp3": "для очень старых устройств\">mp3", + "mt_c2flac": "лучшее качество звука, но большие файлы\">flac", //m + "mt_c2wav": "не сжатое воспроизведение (ещё больше)\">wav", //m "mt_c2ok": "хороший выбор", "mt_c2nd": "это не рекомендованный вариант формата для вашего устройства, но сойдёт", "mt_c2ng": "не похоже, что ваше устройство поддерживает этот формат, но давайте попробуем и узнаем наверняка", @@ -5324,6 +5339,8 @@ var Ls = { "mt_c2owa": 'opus-weba, para iOS 17.5 y superior">owa', "mt_c2caf": 'opus-caf, para iOS 11 a 17">caf', "mt_c2mp3": 'usar en dispositivos muy antiguos">mp3', + "mt_c2flac": "la mejor calidad de sonido,$Npero descargas muy grandes\">flac", //m + "mt_c2wav": "reproducción sin comprimir (aún más grande)\">wav", //m "mt_c2ok": "bien, buena elección", "mt_c2nd": "ese no es el formato de salida recomendado para tu dispositivo, pero está bien", "mt_c2ng": "tu dispositivo no parece soportar este formato de salida, pero intentémoslo de todas formas", @@ -5951,6 +5968,8 @@ var Ls = { "mt_c2owa": "opus-weba, для iOS 17.5 і новіших\">owa", "mt_c2caf": "opus-caf, для iOS 11 до 17\">caf", "mt_c2mp3": "використовуйте це на дуже старих пристроях\">mp3", + "mt_c2flac": "найкраща якість звуку, але великі завантаження\">flac", //m + "mt_c2wav": "відтворення без стиснення (ще більше)\">wav", //m "mt_c2ok": "гарно, хороший вибір", "mt_c2nd": "це не рекомендований вихідний формат для вашого пристрою, але це нормально", "mt_c2ng": "ваш пристрій, здається, не підтримує цей вихідний формат, але давайте все одно спробуємо", @@ -6921,10 +6940,8 @@ var mpl = (function () { if (!have_acode) c = false; - else if (/\.flac$/i.exec(cs)) + else if (/\.(wav|flac)$/i.exec(cs)) c = r.ac_flac; - else if (/\.wav$/i.exec(cs)) - c = r.ac_wav; else if (/\.(aac|m4a)$/i.exec(cs)) c = r.ac_aac; else if (/\.(oga|ogg|opus)$/i.exec(cs) && (!can_ogg || mpl.ac2 == 'mp3')) @@ -6932,6 +6949,7 @@ var mpl = (function () { else if (re_au_native.exec(cs)) c = false; + // allow flac->flac (bitstream fixup) if (!c) return url; @@ -6949,9 +6967,7 @@ var mpl = (function () { } var dv = can_ogg ? 'opus' : - can_caf ? 'caf' : - can_mp3 ? 'mp3' : - can_flac ? 'flac' : 'wav', + can_caf ? 'caf' : 'mp3', fmts = ['opus', 'owa', 'caf', 'mp3', 'flac', 'wav'], btns = []; @@ -6963,7 +6979,6 @@ var mpl = (function () { if ((v == 'opus' && !can_ogg) || (v == 'caf' && !can_caf) || (v == 'owa' && !can_owa) || - (v == 'mp3' && !can_mp3) || (v == 'flac' && !can_flac)) toast.warn(15, L.mt_c2ng); @@ -6979,6 +6994,8 @@ var mpl = (function () { } if (!IPHONE) btns[1].style.display = btns[2].style.display = 'none'; + btns[4].style.display = have_c2flac ? '' : 'none'; + btns[5].style.display = have_c2wav ? '' : 'none'; if (v) swrite('acode2', v); @@ -7102,14 +7119,12 @@ var mpl = (function () { var za, can_ogg = true, can_owa = false, - can_mp3 = false, can_flac = false, can_caf = APPLE && !/ OS ([1-9]|1[01])_/.test(UA); try { za = new Audio(); can_ogg = za.canPlayType('audio/ogg; codecs=opus') === 'probably'; can_owa = za.canPlayType('audio/webm; codecs=opus') === 'probably'; - can_mp3 = za.canPlayType('audio/mpeg') === 'probably'; can_flac = za.canPlayType('audio/flac') === 'probably'; can_caf = za.canPlayType('audio/x-caf') && can_caf; //'maybe' } diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 44f315ff..bad3615f 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -1,4 +1,5 @@ // please add translations in alphabetic order, but keep "nor" and "eng" first +// (lines ending with //m are machine translations) var Ls = { "nor": { "a1": "oppdater", diff --git a/scripts/tl.js b/scripts/tl.js index e24d9451..97bf061d 100644 --- a/scripts/tl.js +++ b/scripts/tl.js @@ -315,6 +315,7 @@ var tl_browser = { "ct_qdel": 'when deleting files, only ask for confirmation once">qdel', "ct_dir1st": 'sort folders before files">📁 first', "ct_nsort": 'natural sort (for filenames with leading digits)">nsort', + "ct_utc": 'show all datetimes in UTC">UTC', "ct_readme": 'show README.md in folder listings">📜 readme', "ct_idxh": 'show index.html instead of folder listing">htm', "ct_sbars": 'show scrollbars">⟊', @@ -390,8 +391,8 @@ var tl_browser = { "mt_c2owa": "opus-weba, for iOS 17.5 and newer\">owa", "mt_c2caf": "opus-caf, for iOS 11 through 17\">caf", "mt_c2mp3": "use this on very old devices\">mp3", - "mt_c2flac": "best sound quality\">flac", - "mt_c2wav": "uncompressed playback\">wav", + "mt_c2flac": "best sound quality, but huge downloads\">flac", + "mt_c2wav": "uncompressed playback (even bigger)\">wav", "mt_c2ok": "nice, good choice", "mt_c2nd": "that's not the recommended output format for your device, but that's fine", "mt_c2ng": "your device does not seem to support this output format, but let's try anyways", From 66a5bf365bff16448b0843fd2fdda72939588fa0 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:33:08 +0000 Subject: [PATCH 10/66] fix ipv6 qrcode port; closes #449 --- copyparty/tcpsrv.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py index 65f343d0..b0f9391e 100644 --- a/copyparty/tcpsrv.py +++ b/copyparty/tcpsrv.py @@ -583,8 +583,7 @@ class TcpSrv(object): if not ip: return "" - if ":" in ip: - ip = "[{}]".format(ip) + hip = "[%s]" % (ip,) if ":" in ip else ip if self.args.http_only: https = "" @@ -596,7 +595,7 @@ class TcpSrv(object): ports = t1.get(ip, t2.get(ip, [])) dport = 443 if https else 80 port = "" if dport in ports or not ports else ":{}".format(ports[0]) - txt = "http{}://{}{}/{}".format(https, ip, port, self.args.qrl) + txt = "http{}://{}{}/{}".format(https, hip, port, self.args.qrl) btxt = txt.encode("utf-8") if PY2: From 153d240d0de06f0925d6bd5c3ead7b8e457a495d Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:35:33 +0000 Subject: [PATCH 11/66] mention the -nc option in the max-conn errormsg --- copyparty/httpsrv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/copyparty/httpsrv.py b/copyparty/httpsrv.py index 56638003..ddf5e7bc 100644 --- a/copyparty/httpsrv.py +++ b/copyparty/httpsrv.py @@ -324,7 +324,8 @@ class HttpSrv(object): spins = 0 while self.ncli >= self.nclimax: if not spins: - self.log(self.name, "at connection limit; waiting", 3) + t = "at connection limit (global-option 'nc'); waiting" + self.log(self.name, t, 3) spins += 1 time.sleep(0.1) From 7d3a5c1e977b260cefa3d080a752a5fd12119836 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:35:52 +0000 Subject: [PATCH 12/66] black --- bin/u2c.py | 2 +- copyparty/tcpsrv.py | 2 +- copyparty/th_srv.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/u2c.py b/bin/u2c.py index 85298730..e92c1e4e 100755 --- a/bin/u2c.py +++ b/bin/u2c.py @@ -52,7 +52,7 @@ if PY2: sys.dont_write_bytecode = True bytes = str - files_decoder = lambda s: unicode(s, 'utf8') + files_decoder = lambda s: unicode(s, "utf8") else: from urllib.parse import quote_from_bytes as quote from urllib.parse import unquote_to_bytes as unquote diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py index b0f9391e..53388c5e 100644 --- a/copyparty/tcpsrv.py +++ b/copyparty/tcpsrv.py @@ -583,7 +583,7 @@ class TcpSrv(object): if not ip: return "" - hip = "[%s]" % (ip,) if ":" in ip else ip + hip = "[%s]" % (ip,) if ":" in ip else ip if self.args.http_only: https = "" diff --git a/copyparty/th_srv.py b/copyparty/th_srv.py index f40d0a43..7b07376a 100644 --- a/copyparty/th_srv.py +++ b/copyparty/th_srv.py @@ -846,7 +846,7 @@ class ThumbSrv(object): tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2)) if "ac" not in tags: raise Exception("not audio") - + bits = tags[".bps"][1] if bits == 0.0: bits = tags[".bprs"][1] From d0499257c8c0a634a7a1fcaa3f1309008efab237 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:36:38 +0000 Subject: [PATCH 13/66] fix tests --- tests/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util.py b/tests/util.py index 42a47907..f555a37e 100644 --- a/tests/util.py +++ b/tests/util.py @@ -143,7 +143,7 @@ class Cfg(Namespace): def __init__(self, a=None, v=None, c=None, **ka0): ka = {} - ex = "chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" + ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" ka.update(**{k: False for k in ex.split()}) ex = "dav_inf dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash see_dots plain_ip" From e85a71070eb086a2cf39bb0202d8978b0bb5ef2d Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 21:42:26 +0000 Subject: [PATCH 14/66] docs: groups; closes #461 --- README.md | 6 ++++++ copyparty/__main__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93b6a464..46d691a0 100644 --- a/README.md +++ b/README.md @@ -513,12 +513,17 @@ anyone trying to bruteforce a password gets banned according to `--ban-pw`; defa 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` +* you can also `PRTY_CONFIG=foobar.conf python copyparty-sfx.py` (convenient in docker etc) + ```yaml [accounts] u1: p1 # create account "u1" with password "p1" u2: p2 # (note that comments must have u3: p3 # two spaces before the # sign) +[groups] + g1: u1, u2 # create a group + [/] # this URL will be mapped to... /srv # ...this folder on the server filesystem accs: @@ -528,6 +533,7 @@ and if you want to use config files instead of commandline args (good!) then her /mnt/music # which is mapped to this folder accs: r: u1, u2 # only these accounts can read, + r: @g1 # (exactly the same, just with a group instead) rw: u3 # and only u3 can read-write [/inc] diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 21bda508..9db3a4f5 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -578,7 +578,7 @@ def get_sects(): --grp takes groupname:username1,username2,... and groupnames can be used instead of usernames in -v - by prefixing the groupname with % + by prefixing the groupname with @ list of permissions: "r" (read): list folder contents, download files From 16bbcce51bb1720b7a0cabd2052584c953e2767e Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 22:10:33 +0000 Subject: [PATCH 15/66] videos can be folder thumbnails; closes #459 --- copyparty/up2k.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/copyparty/up2k.py b/copyparty/up2k.py index ae5ed07f..785d0a4f 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -86,7 +86,10 @@ if TYPE_CHECKING: from .svchub import SvcHub zsg = "avif,avifs,bmp,gif,heic,heics,heif,heifs,ico,j2p,j2k,jp2,jpeg,jpg,jpx,png,tga,tif,tiff,webp" -CV_EXTS = set(zsg.split(",")) +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 = "nohash noidx xdev xvol" VF_AFFECTS_INDEXING = set(zsg.split(" ")) @@ -1478,7 +1481,7 @@ class Up2k(object): unreg: list[str] = [] files: list[tuple[int, int, str]] = [] fat32 = True - cv = "" + cv = vcv = "" th_cvd = self.args.th_coversd th_cvds = self.args.th_coversd_set @@ -1573,25 +1576,24 @@ class Up2k(object): rsz += sz files.append((sz, lmod, iname)) - liname = iname.lower() - if ( - sz - and ( + if sz: + liname = iname.lower() + ext = liname.rsplit(".", 1)[-1] + if ( liname in th_cvds - or ( - not cv - and liname.rsplit(".", 1)[-1] in CV_EXTS - and not iname.startswith(".") - ) - ) - and ( + or (not cv and ext in ICV_EXTS and not iname.startswith(".")) + ) and ( not cv or liname not in th_cvds or cv.lower() not in th_cvds or th_cvd.index(liname) < th_cvd.index(cv.lower()) - ) - ): - cv = iname + ): + cv = iname + elif not vcv and ext in VCV_EXTS and not iname.startswith("."): + vcv = iname + + if not cv: + cv = vcv if not self.args.no_dirsz: tnf += len(files) From 39e55824961a8870aad56b77ff6b0c6d9cd8aa26 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 22:14:31 +0000 Subject: [PATCH 16/66] ignore browser-extension errors; closes #435 --- copyparty/web/util.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/copyparty/web/util.js b/copyparty/web/util.js index 94f73f24..929316e5 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -180,6 +180,9 @@ function vis_exh(msg, url, lineNo, columnNo, error) { if (!/\.js($|\?)/.exec(url)) return; // chrome debugger + if (url.indexOf('extension://') + 1) + return; + if (url.indexOf(' > eval') + 1 && !evalex_fatal) return; // md timer From 9db8037e39ea9330337a0aa5c52511432dc6a61e Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 22:24:36 +0000 Subject: [PATCH 17/66] remove old joke end of an era --- copyparty/__init__.py | 4 ---- copyparty/__main__.py | 2 +- copyparty/httpcli.py | 9 --------- copyparty/web/browser.css | 13 +------------ copyparty/web/dd/2.png | Bin 258 -> 0 bytes copyparty/web/dd/3.png | Bin 252 -> 0 bytes copyparty/web/dd/4.png | Bin 248 -> 0 bytes copyparty/web/dd/5.png | Bin 250 -> 0 bytes copyparty/web/dd/__init__.py | 0 docs/devnotes.md | 1 - pyproject.toml | 1 - scripts/copyparty-repack.sh | 8 ++++---- scripts/make-sfx.sh | 14 ++------------ scripts/sfx.ls | 6 ------ setup.py | 1 - 15 files changed, 8 insertions(+), 51 deletions(-) delete mode 100644 copyparty/web/dd/2.png delete mode 100644 copyparty/web/dd/3.png delete mode 100644 copyparty/web/dd/4.png delete mode 100644 copyparty/web/dd/5.png delete mode 100644 copyparty/web/dd/__init__.py diff --git a/copyparty/__init__.py b/copyparty/__init__.py index 86b7fe1e..d1630ba0 100644 --- a/copyparty/__init__.py +++ b/copyparty/__init__.py @@ -63,10 +63,6 @@ web/browser.js web/browser2.html web/cf.html web/copyparty.gif -web/dd/2.png -web/dd/3.png -web/dd/4.png -web/dd/5.png web/deps/busy.mp3 web/deps/easymde.css web/deps/easymde.js diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 9db3a4f5..9e406bea 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1567,7 +1567,7 @@ def add_ui(ap, retry): ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files/folders matching \033[33mREGEX\033[0m in file list. WARNING: Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)") ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable") ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)") - ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])") + ap2.add_argument("--mpmc", type=u, default="", help=argparse.SUPPRESS) ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]") ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html") ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index db1cbcb8..44087e1f 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -1196,15 +1196,6 @@ class HttpCli(object): self.reply(b"ssdp is disabled in server config", 404) return False - if self.vpath.startswith(".cpr/dd/") and self.args.mpmc: - if self.args.mpmc == ".": - raise Pebkac(404) - - loc = self.args.mpmc.rstrip("/") + self.vpath[self.vpath.rfind("/") :] - h = {"Location": loc, "Cache-Control": "max-age=39"} - self.reply(b"", 301, headers=h) - return True - if self.vpath == ".cpr/metrics": return self.conn.hsrv.metrics.tx(self) diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css index 35dbeeac..1f5a7da6 100644 --- a/copyparty/web/browser.css +++ b/copyparty/web/browser.css @@ -1113,18 +1113,7 @@ html.y #widget.open { top: -.12em; } #wtico { - cursor: url(dd/4.png), pointer; - animation: cursor 500ms; -} -#wtico:hover { - animation: cursor 500ms infinite; -} -@keyframes cursor { - 0% {cursor: url(dd/2.png), pointer} - 30% {cursor: url(dd/3.png), pointer} - 50% {cursor: url(dd/4.png), pointer} - 75% {cursor: url(dd/5.png), pointer} - 85% {cursor: url(dd/4.png), pointer} + cursor: pointer; } @keyframes spin { 100% {transform: rotate(360deg)} diff --git a/copyparty/web/dd/2.png b/copyparty/web/dd/2.png deleted file mode 100644 index 5f7509580fd235cfa30e0f9e06f20031bbf004d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVjv9yj0`Q6;vmizPZ!6K ziaBqmDGD8O5MX&8o)O~{*YHp|pkoiiapwvq!6)2;5ep0&)NY)aGo$OI+nS86;hSqi zqpRB=m)Z6(I@s)+@A-hs>GgN>W)TkY3vI!yQCnK9=QEuazMvRlvcSpp0mC8AFYDDO zGJRxvem70xF;m_4z5qqpQ>QciGxm!_%yTeQ*)$`p)H!2shQilJAH5q37`Jznbi_Cx yeY)IXPXl)VqxcKG1o1$wGkOc;yKZ_mW;EKDWPaALSh?;o$S0nzelF{r5}E)Z{$9cW diff --git a/copyparty/web/dd/3.png b/copyparty/web/dd/3.png deleted file mode 100644 index 524facc389c48bccf623fed592505335b93740d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVjv9yj0`Q6;vmjCPZ!6K ziaBqmF63o$6meOu{bi?dNW)Gy1??3K?ut_mNJcp%G$t^dZQL`{cSgbwm70%N@}BMY zRjc3lYE~i-!=sY@d!JtZeO$X)ghTv7gUAniM%{&r7;UQ-EfDZasJ9f>6wu!=^L(43 z-h;v$g1S*ot=nF+F8mzy;5*BzNhcP~^qJl=FP!%AFGrA91#U{NU;8=d#Wzp$Py9YFyj`&9{y!~Ul5VmF5BMCmPnf_gAtmwQQ6M{yE&Bp>r;?tB z3?=T9UNl(e$1i>W6y3wT?V8(v_hT(Q4(z-U1B`2{($xhGutr8x{I-FoAVHYr(FoB&z%w;j(g5As< jrbd~4?y?3K_!t=SUww`EuyW2Vko!Gd{an^LB{Ts50OL}6 diff --git a/copyparty/web/dd/5.png b/copyparty/web/dd/5.png deleted file mode 100644 index 3d1d181e31e8a78396654a4c66f10ac9beaff096..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVjv9yj0`Q6;vmi%PZ!6K ziaBqm?G|h{5O7(qoh0tS>UXC@k~QSP8Qu$x-UZ?&2lNfkJ)IKEDm~*NhhD|PviWIw zew&WJowR+1q(R;FSV_B%)`r~-;{UW0PBsWw>}TLtJj{4fXaU#Ex|t0EAH*x}uCMIo zIuXmhqUrl)#vS@B=hOpuICYn;%4^(n&LPm@dG~RBmOHFhlpZNQa?nc&spI&;y@Ek3 rpz#$`kznhAhfIGKTFepnAohdN_Hssf-jU-bARl Date: Sun, 3 Aug 2025 22:34:37 +0000 Subject: [PATCH 18/66] fix nosub with PUT uploads; closes #412 --- copyparty/httpcli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 44087e1f..9463e982 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -2074,16 +2074,16 @@ class HttpCli(object): rnd, lifetime, xbu, xau = self.upload_flags(vfs) lim = vfs.get_dbv(rem)[0].lim fdir = vfs.canonical(rem) - if lim: - fdir, rem = lim.all( - self.ip, rem, remains, vfs.realpath, fdir, self.conn.hsrv.broker - ) - fn = None if rem and not self.trailing_slash and not bos.path.isdir(fdir): fdir, fn = os.path.split(fdir) rem, _ = vsplit(rem) + if lim: + fdir, rem = lim.all( + self.ip, rem, remains, vfs.realpath, fdir, self.conn.hsrv.broker + ) + bos.makedirs(fdir, vf=vfs.flags) open_ka: dict[str, Any] = {"fun": open} From 848315c0091f66fe0f43dc5f2fe3babca16d3744 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 22:43:57 +0000 Subject: [PATCH 19/66] do not force d2d with default vfs; #295 fixes v1.18.3 regression --- copyparty/authsrv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 76a09ecd..afbc24ba 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -1713,7 +1713,8 @@ class AuthSrv(object): t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw" self.log(t, 1) axs = AXS() - vfs = VFS(self.log_func, absreal("."), "", "", axs, self.vf0()) + zvf = {"tcolor": self.args.tcolor} + vfs = VFS(self.log_func, absreal("."), "", "", axs, zvf) if not axs.uread: self.badcfg1 = True elif "" not in mount: From 6eaf8af15aba4937ff86edb22d9d28e09f335094 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 22:50:12 +0000 Subject: [PATCH 20/66] pypi: add extras-group "all"; closes #398 --- pyproject.toml | 8 ++++++++ setup.py | 1 + 2 files changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d1f59351..a48e6579 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,14 @@ classifiers = [ "Demo Server" = "https://a.ocv.me/pub/demo/" [project.optional-dependencies] +all = [ + "argon2-cffi", + "partftpy>=0.4.0", + "Pillow", + "pyftpdlib", + "pyopenssl", + "pyzmq", +] thumbnails = ["Pillow"] thumbnails2 = ["pyvips"] audiotags = ["mutagen"] diff --git a/setup.py b/setup.py index b7554e2f..ce5afb47 100755 --- a/setup.py +++ b/setup.py @@ -136,6 +136,7 @@ args = { ], "install_requires": ["jinja2"], "extras_require": { + "all": ["argon2-cffi", "partftpy>=0.4.0", "Pillow", "pyftpdlib", "pyopenssl", "pyzmq"], "thumbnails": ["Pillow"], "thumbnails2": ["pyvips"], "audiotags": ["mutagen"], From ae5eefc52845c1404c78f762d49e5ea073e71a1c Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 23:02:56 +0000 Subject: [PATCH 21/66] add sfx explanation; #345 --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 46d691a0..22d3a0d7 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,8 @@ made in Norway 🇳🇴 just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉 +> ℹ️ the sfx is a [self-extractor](https://github.com/9001/copyparty/issues/270) which unpacks an embedded `tar.gz` into `$TEMP` -- if this looks too scary, you can use the [zipapp](#zipapp) which has slightly worse performance + * 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) @@ -2859,7 +2861,7 @@ then again, if you are already into downloading shady binaries from the internet ## zipapp -another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz) has less features, is slow, requires python 3.7 or newer, worse compression, and more importantly is unable to benefit from more recent versions of jinja2 and such (which makes it less secure)... lots of drawbacks with this one really -- but it does not unpack any temporary files to disk, so it *may* just work if the regular sfx fails to start because the computer is messed up in certain funky ways, so it's worth a shot if all else fails +another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz) has less features, is slow, requires python 3.7 or newer, worse compression, and more importantly is unable to benefit from more recent versions of jinja2 and such (which makes it less secure)... lots of drawbacks with this one really -- but, unlike the sfx, it is a completely normal zipfile which does not unpack any temporary files to disk, so it *may* just work if the regular sfx fails to start because the computer is messed up in certain funky ways, so it's worth a shot if all else fails run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails From f9502c3df35a1c8eded8eb192b09fc11e8a7880d Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 23:27:53 +0000 Subject: [PATCH 22/66] add idp-cookie; for high-traffic / glitchy auth servers --- README.md | 2 ++ copyparty/__main__.py | 1 + copyparty/authsrv.py | 5 ++++- copyparty/httpcli.py | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 22d3a0d7..f7c27be8 100644 --- a/README.md +++ b/README.md @@ -1894,6 +1894,8 @@ you can disable the built-in password-based login system, and instead replace it * the regular config-defined users will be used as a fallback for requests which don't include a valid (trusted) IdP username header +* if your IdP-server is slow, consider `--idp-cookie` and let requests with the cookie `cppws` bypass the IdP; experimental sessions-based feature added for a party + some popular identity providers are [Authelia](https://www.authelia.com/) (config-file based) and [authentik](https://goauthentik.io/) (GUI-based, more complex) there is a [docker-compose example](./docs/examples/docker/idp-authelia-traefik) which is hopefully a good starting point (alternatively see [./docs/idp.md](./docs/idp.md) if you're the DIY type) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 9e406bea..d92089d0 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1150,6 +1150,7 @@ def add_auth(ap): 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)") + ap2.add_argument("--idp-cookie", metavar="S", type=int, default=0, help="generate a session-token for IdP users which is written to cookie \033[33mcppws\033[0m (or \033[33mcppwd\033[0m if plaintext), to reduce the load on the IdP server, lifetime \033[33mS\033[0m seconds.\n └─note: The expiration time is a client hint only; the actual lifetime of the session-token is infinite (until next restart with \033[33m--ses-db\033[0m wiped)") 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)") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index afbc24ba..44629e62 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -2869,7 +2869,10 @@ class AuthSrv(object): n = [] q = "insert into us values (?,?,?)" - for uname in self.acct: + accs = list(self.acct) + if self.args.idp_h_usr and self.args.idp_cookie: + accs.extend(self.idp_accs.keys()) + for uname in accs: if uname not in ases: sid = ub64enc(os.urandom(blen)).decode("ascii") cur.execute(q, (uname, sid, int(time.time()))) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 9463e982..d562485b 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -658,6 +658,9 @@ class HttpCli(object): self.pw = "" self.uname = idp_usr self.html_head += "\n" + zs = self.asrv.ases.get(idp_usr) + if zs: + self.set_idp_cookie(zs) else: self.log("unknown username: %r" % (idp_usr,), 1) @@ -3029,6 +3032,19 @@ class HttpCli(object): return dur > 0, msg + def set_idp_cookie(self, ases) -> None: + k = "cppws" if self.is_https else "cppwd" + ck = gencookie( + k, + ases, + self.args.R, + self.args.cookie_lax, + self.is_https, + self.args.idp_cookie, + "; HttpOnly", + ) + self.out_headers["Set-Cookie"] = ck + def handle_mkdir(self) -> bool: assert self.parser # !rm new_dir = self.parser.require("name", 512) From 40d56bb3f0b218389c230dfb808c622307a43cda Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 23:35:08 +0000 Subject: [PATCH 23/66] indicate play-as-audio for video files --- copyparty/web/browser.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 3dca9476..f1cf6562 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -6166,7 +6166,7 @@ var Ls = { "xhr403": "403: Доступ заборонено\n\nспробуйте натиснути F5, можливо ви вийшли з системи", "xhr0": "невідома (ймовірно втрачено з'єднання з сервером, або сервер офлайн)", - "cf_ok": "вибачте за це -- захист від DD" + "oS спрацював\n\nречі повинні відновитися приблизно через 30 сек\n\nякщо нічого не відбувається, натисніть F5 для перезавантаження сторінки", + "cf_ok": "вибачте за це -- захист від DD" + wah + "oS спрацював\n\nречі повинні відновитися приблизно через 30 сек\n\nякщо нічого не відбувається, натисніть F5 для перезавантаження сторінки", "tl_xe1": "не вдалося перелічити підпапки:\n\nпомилка ", "tl_xe2": "404: Папка не знайдена", "fl_xe1": "не вдалося перелічити файли в папці:\n\nпомилка ", @@ -7139,6 +7139,7 @@ mpl.init_ac2(); var re_m3u = /\.(m3u8?)$/i; var re_au_native = (can_ogg || have_acode) ? /\.(aac|flac|m4a|mp3|oga|ogg|opus|wav)$/i : /\.(aac|flac|m4a|mp3|wav)$/i, + re_au_vid = /\.(3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i, re_au_all = /\.(aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|itgz|itxz|itz|m4a|mdgz|mdxz|mdz|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|oga|ogg|okt|opus|ra|s3m|s3gz|s3xz|s3z|tak|tta|ulaw|wav|wma|wv|xm|xmgz|xmxz|xmz|xpk|3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i; @@ -7167,10 +7168,11 @@ function MPlayer() { fn = url.split('?')[0]; if (re_audio.exec(fn)) { - var tid = link.getAttribute('id'); + var tid = link.getAttribute('id'), + txt = re_au_vid.exec(fn) ? '(🎧)' : L.mb_play; r.order.push(tid); r.tracks[tid] = url; - tds[0].innerHTML = '' + L.mb_play + ''; + tds[0].innerHTML = '' + txt + ''; ebi('a' + tid).onclick = ev_play; clmod(trs[a], 'au', 1); } From 715f8424b303fe8163c2463727f682bf60322e3c Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 3 Aug 2025 23:42:51 +0000 Subject: [PATCH 24/66] tl cleanup --- copyparty/web/browser.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index f1cf6562..d7982c78 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3501,10 +3501,10 @@ var Ls = { "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 .PARTIAL. Premi ANNULLA o Escape per farlo.\n\nPremendo OK / Invio ignorerai questo avviso e continuerai a scaricare il file .PARTIAL 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_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", From d7e7e77f930f6887af8215a6d6a87400383031ca Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 4 Aug 2025 00:13:54 +0000 Subject: [PATCH 25/66] v1.18.10 --- copyparty/__version__.py | 4 +- docs/changelog.md | 43 ++++++++ docs/logo-sq.svg | 216 +++++++++++++++++++++++++++++++++++++++ docs/logo256.svg | 209 +++++++++++++++++++++++++++++++++++++ tests/util.py | 2 +- 5 files changed, 471 insertions(+), 3 deletions(-) create mode 100644 docs/logo-sq.svg create mode 100644 docs/logo256.svg diff --git a/copyparty/__version__.py b/copyparty/__version__.py index a82053fb..30bd3fd6 100644 --- a/copyparty/__version__.py +++ b/copyparty/__version__.py @@ -1,8 +1,8 @@ # coding: utf-8 -VERSION = (1, 18, 9) +VERSION = (1, 18, 10) CODENAME = "logtail" -BUILD_DT = (2025, 8, 1) +BUILD_DT = (2025, 8, 4) S_VERSION = ".".join(map(str, VERSION)) S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT) diff --git a/docs/changelog.md b/docs/changelog.md index 5e1d7717..3cc8bdf1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,46 @@ +▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ +# 2025-0801-2056 `v1.18.9` fix Denial-of-Service + +## ⚠️ ATTN: this release fixes a Denial-of-Service vuln + +[CVE-2025-54796](https://github.com/9001/copyparty/security/advisories/GHSA-5662-2rj7-f2v6): an unauthenticated user could make the server grind to a halt by accessing a particular URL + +## recent important news + +* [v1.18.9 (2025-08-01)](https://github.com/9001/copyparty/releases/tag/v1.18.9) fixed [CVE-2025-54796](https://github.com/9001/copyparty/security/advisories/GHSA-5662-2rj7-f2v6) (Denial-of-Service) +* [v1.15.0 (2024-09-08)](https://github.com/9001/copyparty/releases/tag/v1.15.0) changed upload deduplication to be default-disabled +* [v1.14.3 (2024-08-30)](https://github.com/9001/copyparty/releases/tag/v1.14.3) fixed a bug that was introduced in v1.13.8 (2024-08-13); this bug could lead to **data loss** -- see the v1.14.3 release-notes for details + +## 🧪 new features + +* #310 translated to Spanish (thx @herruzo99!) a1dfd0be +* #350 translated to Ukrainian (thx @MrMebelMan!) fea45e45 +* #321 translated to Russian (thx @A1Asriel!) 0b05c726 +* #381 translated to Finnish (thx @icxes and @Permik!) 7ecedb2c + * haha it says surf +* #312 add option to use localtime in the UI ad23b253 +* #386 initial packaging for debian (thx @Beethoven-n!) 3c6f0b17 + +## 🩹 bugfixes + +* CVE-2025-54796 / GHSA-5662-2rj7-f2v6 09910ba8 +* #347 fix upload-abort when uploading to a share 6d6d79fc +* fix xiu backlog dropping on restart 3222ba3a +* #375 fix crash on really old versions of python2.7 (thx @bb!) b69d5901 +* #388 another python2.7 fix: improve unicode support in u2c (thx @KevinXuxuxu!) 9c197535 +* log creator of new/blank markdown docs d0d2f206 +* #400 config didn't support indenting with tabs c1604288 + +## 🔧 other changes + +* `ack` was changed to `continue` 4fa7be2a + +## 🌠 fun facts + +* the translations have made the sfx size balloon from 766 to 845 KiB in under a week... nice! keep em coming :tada: + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ # 2025-0731-0833 `v1.18.8` sfx hotfix diff --git a/docs/logo-sq.svg b/docs/logo-sq.svg new file mode 100644 index 00000000..cca66519 --- /dev/null +++ b/docs/logo-sq.svg @@ -0,0 +1,216 @@ + + + + copyparty_logo + + + + + + + + + + + + image/svg+xml + + copyparty_logo + github.com/9001/copyparty + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo256.svg b/docs/logo256.svg new file mode 100644 index 00000000..8fdb2782 --- /dev/null +++ b/docs/logo256.svg @@ -0,0 +1,209 @@ + + + copyparty_logo + + + + + + + + + + + + image/svg+xml + + copyparty_logo + github.com/9001/copyparty + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/util.py b/tests/util.py index f555a37e..ea9bfeb9 100644 --- a/tests/util.py +++ b/tests/util.py @@ -161,7 +161,7 @@ class Cfg(Namespace): ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who" ka.update(**{k: 9 for k in ex.split()}) - ex = "db_act forget_ip idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" + ex = "db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" ka.update(**{k: 0 for k in ex.split()}) ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR" From d4397e7217c88c9b201666c5062dd1f60e4d432c Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 4 Aug 2025 00:39:26 +0000 Subject: [PATCH 26/66] update pkgs to 1.18.10 --- contrib/package/arch/PKGBUILD | 4 ++-- contrib/package/makedeb-mpr/PKGBUILD | 4 ++-- contrib/package/nix/copyparty/pin.json | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contrib/package/arch/PKGBUILD b/contrib/package/arch/PKGBUILD index 40c0b62b..9efb5c41 100644 --- a/contrib/package/arch/PKGBUILD +++ b/contrib/package/arch/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: icxes pkgname=copyparty -pkgver="1.18.9" +pkgver="1.18.10" pkgrel=1 pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++" arch=("any") @@ -22,7 +22,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=("d5d33b50d6717e52427956beb1687061a6f28b467997506505151e3ae18c58e5") +sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99") build() { cd "${srcdir}/${pkgname}-${pkgver}" diff --git a/contrib/package/makedeb-mpr/PKGBUILD b/contrib/package/makedeb-mpr/PKGBUILD index 227fc4cf..f16e5459 100644 --- a/contrib/package/makedeb-mpr/PKGBUILD +++ b/contrib/package/makedeb-mpr/PKGBUILD @@ -2,7 +2,7 @@ pkgname=copyparty -pkgver=1.18.9 +pkgver=1.18.10 pkgrel=1 pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++" arch=("any") @@ -20,7 +20,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag ) source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") backup=("/etc/${pkgname}.d/init" ) -sha256sums=("d5d33b50d6717e52427956beb1687061a6f28b467997506505151e3ae18c58e5") +sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99") build() { cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web" diff --git a/contrib/package/nix/copyparty/pin.json b/contrib/package/nix/copyparty/pin.json index 734dec31..70657f2c 100644 --- a/contrib/package/nix/copyparty/pin.json +++ b/contrib/package/nix/copyparty/pin.json @@ -1,5 +1,5 @@ { - "url": "https://github.com/9001/copyparty/releases/download/v1.18.9/copyparty-sfx.py", - "version": "1.18.9", - "hash": "sha256-R1OVx4f8GERAG80ZcHAIP6HK2TlBbKJZpvnJmJbGPRY=" + "url": "https://github.com/9001/copyparty/releases/download/v1.18.10/copyparty-sfx.py", + "version": "1.18.10", + "hash": "sha256-2FdQ5aCwNdZ5Jy9mn8rr8g41+QHT5tsEc+GeAKvhGeg=" } \ No newline at end of file From 8c000fd68353ff087ea2208eb90ba9fb61605eef Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 4 Aug 2025 00:40:27 +0000 Subject: [PATCH 27/66] cleanup --- README.md | 2 +- scripts/prep.sh | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f7c27be8..9746581b 100644 --- a/README.md +++ b/README.md @@ -1229,7 +1229,7 @@ using arguments or config files, or a mix of both: **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. * if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help` -* or see this (probably outdated): https://ocv.me/copyparty/helptext.html +* or see this: https://ocv.me/copyparty/helptext.html * or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt diff --git a/scripts/prep.sh b/scripts/prep.sh index a4c8a132..d522371e 100755 --- a/scripts/prep.sh +++ b/scripts/prep.sh @@ -29,15 +29,11 @@ update_mpr_pkgbuild() { sha=$(sha256sum "$self/../dist/copyparty-$ver.tar.gz" | awk '{print$1}') - # awk -v ver=$ver -v sha=$sha ' - # /^pkgver=/{sub(/[0-9\.]+/,ver)}; - # /^sha256sums=/{sub(/[0-9a-f]{64}/,sha)}; - # 1' PKGBUILD >a - # mv a PKGBUILD - # TODO: check if this still works. if so, remove the following 2 lines: - - sed -s -i "s/pkgver=\"\"/pkgver=\"$ver\"/" PKGBUILD - sed -s -i "s/sha256sums=(\".*\")/sha256sums=(\"$sha\")/" PKGBUILD + awk -v ver=$ver -v sha=$sha ' + /^pkgver=/{sub(/[0-9\.]+/,ver)}; + /^sha256sums=/{sub(/[0-9a-f]{64}/,sha)}; + 1' PKGBUILD >a + mv a PKGBUILD rm -rf x } From 0df1901fc0376ff751a8c0db7d28251f8935ccf6 Mon Sep 17 00:00:00 2001 From: geekalaa Date: Mon, 4 Aug 2025 15:46:03 +0100 Subject: [PATCH 28/66] fix: add missing L. prefix for un_clip localization string Fixes ReferenceError when copying links from recently uploaded files. The un_clip localization string was missing the L. prefix in up2k.js. Fixes #467 --- copyparty/web/up2k.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 2f588446..31ed1d6a 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -1595,7 +1595,7 @@ function up2k_init(subtle) { ev(e); var txt = linklist(); cliptxt(txt + '\n', function () { - toast.inf(5, un_clip.format(txt.split('\n').length)); + toast.inf(5, L.un_clip.format(txt.split('\n').length)); }); }; From c2ac57a2a8a48afcd916384102a2875f15c8b6c7 Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 4 Aug 2025 22:56:30 +0000 Subject: [PATCH 29/66] improve helptext for multi-value options (#475) --- copyparty/__main__.py | 122 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index d92089d0..3bb8c69e 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -993,18 +993,18 @@ def build_flags_desc(): def add_general(ap, nc, srvname): - ap2 = ap.add_argument_group('general options') - ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="add config file") + ap2 = ap.add_argument_group("general options") + ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="\033[34mREPEATABLE:\033[0m add config file") ap2.add_argument("-nc", metavar="NUM", type=int, default=nc, help="max num clients") ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores, 0=all") - ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]") - ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts") - ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]") + ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]") + ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts") + ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]") ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)") ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m") ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]") ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)") - ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]") + ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="\033[34mREPEATABLE:\033[0m map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]") ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit") ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)") ap2.add_argument("--license", action="store_true", help="show licenses and exit") @@ -1012,7 +1012,7 @@ def add_general(ap, nc, srvname): def add_qr(ap, tty): - ap2 = ap.add_argument_group('qr options') + ap2 = ap.add_argument_group("qr options") ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup") ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup") ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]") @@ -1034,7 +1034,7 @@ def add_fs(ap): def add_share(ap): db_path = os.path.join(E.cfg, "shares.db") - ap2 = ap.add_argument_group('share-url options') + ap2 = ap.add_argument_group("share-url options") ap2.add_argument("--shr", metavar="DIR", type=u, default="", help="toplevel virtual folder for shared files/folders, for example [\033[32m/share\033[0m]") ap2.add_argument("--shr-db", metavar="FILE", type=u, default=db_path, help="database to store shares in") ap2.add_argument("--shr-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to view/delete any share") @@ -1043,7 +1043,7 @@ def add_share(ap): def add_upload(ap): - ap2 = ap.add_argument_group('upload options') + ap2 = ap.add_argument_group("upload options") ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m") ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip") ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)") @@ -1085,14 +1085,14 @@ def add_upload(ap): def add_network(ap): - ap2 = ap.add_argument_group('network options') - ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6") + ap2 = ap.add_argument_group("network options") + ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (comma-separated list; see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6") ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to listen on (comma/range); ignored for unix-sockets") ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)") ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=1, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m2\033[0m]=outermost-proxy, [\033[32m3\033[0m]=second-proxy, [\033[32m-1\033[0m]=closest-proxy") ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from") - ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="comma-separated list of trusted reverse-proxy CIDRs; only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)") - ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") + ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)") + ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]") if ANYWIN: ap2.add_argument("--reuseaddr", action="store_true", help="set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances") @@ -1110,7 +1110,7 @@ def add_network(ap): def add_tls(ap, cert_path): - ap2 = ap.add_argument_group('SSL/TLS options') + ap2 = ap.add_argument_group("SSL/TLS options") ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext") ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls") ap2.add_argument("--cert", metavar="PATH", type=u, default=cert_path, help="path to file containing a concatenation of TLS key and certificate chain") @@ -1122,7 +1122,7 @@ def add_tls(ap, cert_path): def add_cert(ap, cert_path): cert_dir = os.path.dirname(cert_path) - ap2 = ap.add_argument_group('TLS certificate generator options') + ap2 = ap.add_argument_group("TLS certificate generator options") ap2.add_argument("--no-crt", action="store_true", help="disable automatic certificate creation") ap2.add_argument("--crt-ns", metavar="N,N", type=u, default="", help="comma-separated list of FQDNs (domains) to add into the certificate") ap2.add_argument("--crt-exact", action="store_true", help="do not add wildcard entries for each \033[33m--crt-ns\033[0m") @@ -1142,7 +1142,7 @@ def add_cert(ap, cert_path): def add_auth(ap): idp_db = os.path.join(E.cfg, "idp.db") ses_db = os.path.join(E.cfg, "sessions.db") - ap2 = ap.add_argument_group('IdP / identity provider / user authentication options') + ap2 = ap.add_argument_group("IdP / identity provider / user authentication options") ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks if the request-header \033[33mHN\033[0m contains a username to associate the request with (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy") ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control") ap2.add_argument("--idp-h-key", metavar="HN", type=u, default="", help="optional but recommended safeguard; your reverse-proxy will insert a secret header named \033[33mHN\033[0m into all requests, and the other IdP headers will be ignored if this header is not present") @@ -1156,14 +1156,14 @@ def add_auth(ap): ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)") ap2.add_argument("--ses-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)") ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies") - ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]") + ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="\033[34mREPEATABLE:\033[0m users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]") def add_chpw(ap): db_path = os.path.join(E.cfg, "chpw.json") - ap2 = ap.add_argument_group('user-changeable passwords options') + ap2 = ap.add_argument_group("user-changeable passwords options") ap2.add_argument("--chpw", action="store_true", help="allow users to change their own passwords") - ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="do not allow password-changes for this comma-separated list of usernames") + ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="\033[34mREPEATABLE:\033[0m do not allow password-changes for this comma-separated list of usernames") ap2.add_argument("--chpw-db", metavar="PATH", type=u, default=db_path, help="where to store the passwords database (if you run multiple copyparty instances, make sure they use different DBs)") ap2.add_argument("--chpw-len", metavar="N", type=int, default=8, help="minimum password length") ap2.add_argument("--chpw-v", metavar="LVL", type=int, default=2, help="verbosity of summary on config load [\033[32m0\033[0m] = nothing at all, [\033[32m1\033[0m] = number of users, [\033[32m2\033[0m] = list users with default-pw, [\033[32m3\033[0m] = list all users") @@ -1212,12 +1212,12 @@ def add_zc_ssdp(ap): def add_ftp(ap): - ap2 = ap.add_argument_group('FTP options (TCP only)') + ap2 = ap.add_argument_group("FTP options (TCP only)") ap2.add_argument("--ftp", metavar="PORT", type=int, default=0, help="enable FTP server on \033[33mPORT\033[0m, for example \033[32m3921") ap2.add_argument("--ftps", metavar="PORT", type=int, default=0, help="enable FTPS server on \033[33mPORT\033[0m, for example \033[32m3990") ap2.add_argument("--ftpv", action="store_true", help="verbose") ap2.add_argument("--ftp4", action="store_true", help="only listen on IPv4") - ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") + ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") ap2.add_argument("--ftp-no-ow", action="store_true", help="if target file exists, reject upload instead of overwrite") ap2.add_argument("--ftp-wt", metavar="SEC", type=int, default=7, help="grace period for resuming interrupted uploads (any client can write to any file last-modified more recently than \033[33mSEC\033[0m seconds ago)") ap2.add_argument("--ftp-nat", metavar="ADDR", type=u, default="", help="the NAT address to use for passive connections") @@ -1225,7 +1225,7 @@ def add_ftp(ap): def add_webdav(ap): - ap2 = ap.add_argument_group('WebDAV options') + ap2 = ap.add_argument_group("WebDAV options") ap2.add_argument("--daw", action="store_true", help="enable full write support, even if client may not be webdav. \033[1;31mWARNING:\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)") ap2.add_argument("--dav-inf", action="store_true", help="allow depth:infinite requests (recursive file listing); extremely server-heavy but required for spec compliance -- luckily few clients rely on this") ap2.add_argument("--dav-mac", action="store_true", help="disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS)") @@ -1235,7 +1235,7 @@ def add_webdav(ap): def add_tftp(ap): - ap2 = ap.add_argument_group('TFTP options (UDP only)') + ap2 = ap.add_argument_group("TFTP options (UDP only)") ap2.add_argument("--tftp", metavar="PORT", type=int, default=0, help="enable TFTP server on \033[33mPORT\033[0m, for example \033[32m69 \033[0mor \033[32m3969") ap2.add_argument("--tftp4", action="store_true", help="only listen on IPv4") ap2.add_argument("--tftpv", action="store_true", help="verbose") @@ -1243,12 +1243,12 @@ def add_tftp(ap): ap2.add_argument("--tftp-no-fast", action="store_true", help="debug: disable optimizations") ap2.add_argument("--tftp-lsf", metavar="PTN", type=u, default="\\.?(dir|ls)(\\.txt)?", help="return a directory listing if a file with this name is requested and it does not exist; defaults matches .ls, dir, .dir.txt, ls.txt, ...") ap2.add_argument("--tftp-nols", action="store_true", help="if someone tries to download a directory, return an error instead of showing its directory listing") - ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") + ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]") ap2.add_argument("--tftp-pr", metavar="P-P", type=u, default="", help="the range of UDP ports to use for data transfer, for example \033[32m12000-13000") def add_smb(ap): - ap2 = ap.add_argument_group('SMB/CIFS options') + ap2 = ap.add_argument_group("SMB/CIFS options") ap2.add_argument("--smb", action="store_true", help="enable smb (read-only) -- this requires running copyparty as root on linux and macos unless \033[33m--smb-port\033[0m is set above 1024 and your OS does port-forwarding from 445 to that.\n\033[1;31mWARNING:\033[0m this protocol is DANGEROUS and buggy! Never expose to the internet!") ap2.add_argument("--smbw", action="store_true", help="enable write support (please dont)") ap2.add_argument("--smb1", action="store_true", help="disable SMBv2, only enable SMBv1 (CIFS)") @@ -1262,30 +1262,30 @@ def add_smb(ap): def add_handlers(ap): - ap2 = ap.add_argument_group('handlers (see --help-handlers)') - ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="handle 404s by executing \033[33mPY\033[0m file") - ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="handle 403s by executing \033[33mPY\033[0m file") + ap2 = ap.add_argument_group("handlers (see --help-handlers)") + ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 404s by executing \033[33mPY\033[0m file") + ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 403s by executing \033[33mPY\033[0m file") ap2.add_argument("--hot-handlers", action="store_true", help="recompile handlers on each request -- expensive but convenient when hacking on stuff") def add_hooks(ap): - ap2 = ap.add_argument_group('event hooks (see --help-hooks)') - ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file upload starts") - ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file upload finishes") - ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after all uploads finish and volume is idle") - ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file copy") - ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file copy") - ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file move/rename") - ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file move/rename") - ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file delete") - ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file delete") - ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m on message") - ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)") + ap2 = ap.add_argument_group("event hooks (see --help-hooks)") + ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file upload starts") + ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file upload finishes") + ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after all uploads finish and volume is idle") + ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file copy") + ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file copy") + ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file move/rename") + ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file move/rename") + ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file delete") + ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file delete") + ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m on message") + ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)") ap2.add_argument("--hook-v", action="store_true", help="verbose hooks") def add_stats(ap): - ap2 = ap.add_argument_group('grafana/prometheus metrics endpoint') + ap2 = ap.add_argument_group("grafana/prometheus metrics endpoint") ap2.add_argument("--stats", action="store_true", help="enable openmetrics at /.cpr/metrics for admin accounts") ap2.add_argument("--nos-hdd", action="store_true", help="disable disk-space metrics (used/free space)") ap2.add_argument("--nos-vol", action="store_true", help="disable volume size metrics (num files, total bytes, vmaxb/vmaxn)") @@ -1295,7 +1295,7 @@ def add_stats(ap): def add_yolo(ap): - ap2 = ap.add_argument_group('yolo options') + ap2 = ap.add_argument_group("yolo options") ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests") ap2.add_argument("--cookie-lax", action="store_true", help="allow cookies from other domains (if you follow a link from another website into your server, you will arrive logged-in); this reduces protection against CSRF") ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET") @@ -1303,7 +1303,7 @@ def add_yolo(ap): def add_optouts(ap): - ap2 = ap.add_argument_group('opt-outs') + ap2 = ap.add_argument_group("opt-outs") ap2.add_argument("-nw", action="store_true", help="never write anything to disk (debug/benchmark)") ap2.add_argument("--keep-qem", action="store_true", help="do not disable quick-edit-mode on windows (it is disabled to avoid accidental text selection in the terminal window, as this would pause execution)") ap2.add_argument("--no-dav", action="store_true", help="disable webdav support") @@ -1329,7 +1329,7 @@ def add_optouts(ap): def add_safety(ap): - ap2 = ap.add_argument_group('safety options') + ap2 = ap.add_argument_group("safety options") ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js") ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih") ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r") @@ -1360,7 +1360,7 @@ def add_safety(ap): def add_salt(ap, fk_salt, dk_salt, ah_salt): - ap2 = ap.add_argument_group('salting options') + ap2 = ap.add_argument_group("salting options") ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)") ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)") ap2.add_argument("--ah-gen", metavar="PW", type=u, default="", help="generate hashed password for \033[33mPW\033[0m, or read passwords from STDIN if \033[33mPW\033[0m is [\033[32m-\033[0m]") @@ -1374,14 +1374,14 @@ def add_salt(ap, fk_salt, dk_salt, ah_salt): def add_shutdown(ap): - ap2 = ap.add_argument_group('shutdown options') + ap2 = ap.add_argument_group("shutdown options") ap2.add_argument("--ign-ebind", action="store_true", help="continue running even if it's impossible to listen on some of the requested endpoints") ap2.add_argument("--ign-ebind-all", action="store_true", help="continue running even if it's impossible to receive connections at all") ap2.add_argument("--exit", metavar="WHEN", type=u, default="", help="shutdown after \033[33mWHEN\033[0m has finished; [\033[32mcfg\033[0m] config parsing, [\033[32midx\033[0m] volscan + multimedia indexing") def add_logging(ap): - ap2 = ap.add_argument_group('logging options') + ap2 = ap.add_argument_group("logging options") ap2.add_argument("-q", action="store_true", help="quiet; disable most STDOUT messages") ap2.add_argument("-lo", metavar="PATH", type=u, default="", help="logfile, example: \033[32mcpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz\033[0m (NB: some errors may appear on STDOUT only)") ap2.add_argument("--no-ansi", action="store_true", default=not VT100, help="disable colors; same as environment-variable NO_COLOR") @@ -1399,7 +1399,7 @@ def add_logging(ap): def add_admin(ap): - ap2 = ap.add_argument_group('admin panel options') + ap2 = ap.add_argument_group("admin panel options") ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)") ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)") ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks)") @@ -1413,7 +1413,7 @@ def add_admin(ap): def add_thumbnail(ap): th_ram = (RAM_AVAIL or RAM_TOTAL or 9) * 0.6 th_ram = int(max(min(th_ram, 6), 0.3) * 10) / 10 - ap2 = ap.add_argument_group('thumbnail options') + ap2 = ap.add_argument_group("thumbnail options") ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails (volflag=dthumb)") ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails (volflag=dvthumb)") ap2.add_argument("--no-athumb", action="store_true", help="disable audio thumbnails (spectrograms) (volflag=dathumb)") @@ -1445,7 +1445,7 @@ def add_thumbnail(ap): def add_transcoding(ap): - ap2 = ap.add_argument_group('transcoding options') + ap2 = ap.add_argument_group("transcoding options") ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable") ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable") ap2.add_argument("--allow-wav", action="store_true", help="allow transcoding to wav (lossless, uncompressed)") @@ -1458,7 +1458,7 @@ def add_transcoding(ap): def add_tail(ap): - ap2 = ap.add_argument_group('tailing options (realtime streaming of a growing file)') + ap2 = ap.add_argument_group("tailing options (realtime streaming of a growing file)") ap2.add_argument("--tail-who", metavar="LVL", type=int, default=2, help="who can tail? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=authenticated-with-read-access, [\033[32m3\033[0m]=everyone-with-read-access (volflag=tail_who)") ap2.add_argument("--tail-cmax", metavar="N", type=int, default=64, help="do not allow starting a new tail if more than \033[33mN\033[0m active downloads") ap2.add_argument("--tail-tmax", metavar="SEC", type=float, default=0, help="terminate connection after \033[33mSEC\033[0m seconds; [\033[32m0\033[0m]=never (volflag=tail_tmax)") @@ -1468,7 +1468,7 @@ def add_tail(ap): def add_rss(ap): - ap2 = ap.add_argument_group('RSS options') + ap2 = ap.add_argument_group("RSS options") ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)") ap2.add_argument("--rss-nf", metavar="HITS", type=int, default=250, help="default number of files to return (url-param 'nf')") ap2.add_argument("--rss-fext", metavar="E,E", type=u, default="", help="default list of file extensions to include (url-param 'fext'); blank=all") @@ -1477,7 +1477,7 @@ def add_rss(ap): def add_db_general(ap, hcores): noidx = APPLESAN_TXT if MACOS else "" - ap2 = ap.add_argument_group('general db options') + ap2 = ap.add_argument_group("general db options") ap2.add_argument("-e2d", action="store_true", help="enable up2k database; this enables file search, upload-undo, improves deduplication") ap2.add_argument("-e2ds", action="store_true", help="scan writable folders for new files on startup; sets \033[33m-e2d\033[0m") ap2.add_argument("-e2dsa", action="store_true", help="scans all folders on startup; sets \033[33m-e2ds\033[0m") @@ -1506,7 +1506,7 @@ def add_db_general(ap, hcores): def add_db_metadata(ap): - ap2 = ap.add_argument_group('metadata db options') + ap2 = ap.add_argument_group("metadata db options") ap2.add_argument("-e2t", action="store_true", help="enable metadata indexing; makes it possible to search for artist/title/codec/resolution/...") ap2.add_argument("-e2ts", action="store_true", help="scan newly discovered files for metadata on startup; sets \033[33m-e2t\033[0m") ap2.add_argument("-e2tsr", action="store_true", help="delete all metadata from DB and do a full rescan; sets \033[33m-e2ts\033[0m") @@ -1516,14 +1516,14 @@ def add_db_metadata(ap): ap2.add_argument("--mtag-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for tag scanning") ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such") ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/FFprobe parsers") - ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping") + ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add/replace metadata mapping") ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE) ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as \033[33m-mte\033[0m", default=DEF_MTH) - ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file") + ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="\033[34mREPEATABLE:\033[0m read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file") def add_txt(ap): - ap2 = ap.add_argument_group('textfile options') + ap2 = ap.add_argument_group("textfile options") ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)") ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="the textfile editor will check for serverside changes every \033[33mSEC\033[0m seconds") ap2.add_argument("-emp", action="store_true", help="enable markdown plugins -- neat but dangerous, big XSS risk") @@ -1534,7 +1534,7 @@ def add_txt(ap): def add_og(ap): - ap2 = ap.add_argument_group('og / open graph / discord-embed options') + ap2 = ap.add_argument_group("og / open graph / discord-embed options") ap2.add_argument("--og", action="store_true", help="disable hotlinking and return an html document instead; this is required by open-graph, but can also be useful on its own (volflag=og)") ap2.add_argument("--og-ua", metavar="RE", type=u, default="", help="only disable hotlinking / engage OG behavior if the useragent matches regex \033[33mRE\033[0m (volflag=og_ua)") ap2.add_argument("--og-tpl", metavar="PATH", type=u, default="", help="do not return the regular copyparty html, but instead load the jinja2 template at \033[33mPATH\033[0m (if path contains 'EXT' then EXT will be replaced with the requested file's extension) (volflag=og_tpl)") @@ -1552,7 +1552,7 @@ def add_og(ap): def add_ui(ap, retry): - ap2 = ap.add_argument_group('ui options') + ap2 = ap.add_argument_group("ui options") ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)") ap2.add_argument("--gsel", action="store_true", help="select files in grid by ctrl-click (volflag=gsel)") ap2.add_argument("--localtime", action="store_true", help="default to local timezone instead of UTC") @@ -1567,7 +1567,7 @@ def add_ui(ap, retry): ap2.add_argument("--qdel", metavar="LVL", type=int, default=2, help="number of confirmations to show when deleting files (2/1/0)") ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files/folders matching \033[33mREGEX\033[0m in file list. WARNING: Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)") ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable") - ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)") + ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="\033[34mREPEATABLE:\033[0m use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)") ap2.add_argument("--mpmc", type=u, default="", help=argparse.SUPPRESS) ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]") ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html") @@ -1593,7 +1593,7 @@ def add_ui(ap, retry): def add_debug(ap): - ap2 = ap.add_argument_group('debug options') + ap2 = ap.add_argument_group("debug options") ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)") ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)") ap2.add_argument("--deps", action="store_true", help="list information about detected optional dependencies") From b664ebb01f28094749e233ac70795ccd11fed253 Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 4 Aug 2025 22:56:37 +0000 Subject: [PATCH 30/66] add chungus.conf (#475) --- docs/chungus.conf | 2138 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2138 insertions(+) create mode 100644 docs/chungus.conf diff --git a/docs/chungus.conf b/docs/chungus.conf new file mode 100644 index 00000000..7ac7ba9a --- /dev/null +++ b/docs/chungus.conf @@ -0,0 +1,2138 @@ +# not actually YAML but lets pretend: +# -*- mode: yaml -*- +# vim: ft=yaml: + + +## this config-file does not make any sense at all, and will not work anywhere +## +## it is a nearly-complete example of every config option and how each can be used, +## but will NOT be maintained, it's just to get a feel for how the config works +## +## this file was initially generated by and based on: +## cat copyparty/__main__.py | awk -F\" -vp1=$(printf %090d 0) '/arse.SUPPRE/{next}/add_argument_group/{printf"\n ###%s\\\n ###// %s \\\\%s\n",p1,$2,p1};{m=""}/metavar=/{m=": "$4}/add_argument\(/{h=$0;sub(/.*, help="/,"",h);sub(/"\)$/,"",h);k=$2;sub(/^-+/,"",k);printf"\n # %s\n %s%s\n",h,k,m}' | sed -r 's/^( ###\/\/ .{88})0+/\1\\/;s/([^#]{40}) +/\1/;s/\\033\[[^m]*[0-9]m//g;s/ \(volflag=([^)]+)\)$/\n # 📂 also available as volflag "\1"/' | xsel -ib +## grep -A9001 ^flagcats copyparty/cfg.py | grep -B9001 ^flagdescs | awk -F\" -vp1=$(printf %090d 0) '/^ "/{printf"\n ###%s\\\n ###// %s \\\\%s\n",p1,$2,p1};/^ [^ ]/{k=$0;h=$0;sub(/^ +./,"",k);sub(/.: .*/,"",k);sub(/[^:]+: ./,"",h);sub(/.,$/,"",h);sub(/=/,": ",k);printf"\n # %s\n %s\n",h,k}' | sed -r 's/^( ###\/\/ .{88})0+/\1\\/;s/([^#]{40}) +/\1/' | xsel -ib + + +[global] + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// general options \\0000000000000000000000000000000000000000000000000000000000000000000000\ + + # REPEATABLE: add a config file; add multiple by repeating the option + c: /etc/some.conf + c: /etc/another.conf + + # max num clients; will not accept more http/https connections at this point + nc: 1024 + + # max num cpu cores, 0=all, 1=default=recommended + j: 4 + + # enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files + # 📂 also available as volflag "dots" + ed + + # how to handle url-form POSTs; see --help-urlform + urlform: save,get + + # server terminal title, for example [$ip-10.1.2.] or [$ip-] + wintitle: $ip-10.1.2. + + # server name (displayed topleft in browser and in mDNS) + name: mogra + + # REPEATABLE: map file EXTension to MIMEtype, for example [jpg=image/jpeg] + mime: qoi=image/x-qoi + mime: adf=application/x-amiga-disk-format + + # list default mimetype mapping and exit + mimes + + # do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower + # 📂 also available as volflag "rmagic" + rmagic + + # show licenses and exit + license + + # show versions and exit + version + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// qr options \\000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # show http:// QR-code on startup + qr + + # show https:// QR-code on startup + qrs + + # location to include in the url, for example [priv/?pw=hunter2] + qrl: uploads/?pw=okletsgo # hint + + # select IP which starts with PREFIX; [.] to force default IP when mDNS URL would have been used instead + qri: 192.168. # hint + + # foreground; try [0] if the qr-code is unreadable + qr-fg: 46 # hint; default=0=black + + # background (white=255) + qr-bg: 92 # hint; default=229=parchment + + # padding (spec says 4 or more, but 1 is usually fine) + qrp: 2 # hint + + # [1]=1x, [2]=2x, [0]=auto (try [2] on broken fonts) + qrz: 2 # hint + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// filesystem options \\0000000000000000000000000000000000000000000000000000000000000000000\ + + # if a file cannot be deleted because it is busy, continue trying for T seconds, retry every R seconds; disable with 0/0 + # 📂 also available as volflag "rm_retry" + rm-retry: 15/0.1 # default on windows; 0 on unix + + # if a file cannot be renamed because it is busy, continue trying for T seconds, retry every R seconds; disable with 0/0 + # 📂 also available as volflag "mv_retry" + mv-retry: 15/0.1 # default on windows; 0 on unix + + # file I/O buffer-size; if your volumes are on a network drive, try increasing to 524288 or even 4194304 (and let me know if that improves your performance) + iobuf: 262144 # default + + # rebuild mountpoint cache every SEC to keep track of sparse-files support; keep low on servers with removable media + mtab-age: 60 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// share-url options \\00000000000000000000000000000000000000000000000000000000000000000000\ + + # toplevel virtual folder for shared files/folders, for example [/share] + shr: /shares # hint; default is unset + + # database to store shares in + shr-db: $XDG_CONFIG_PATH/.copyparty/shares.db # default (and yes, $ENV will expand in configs) + + # comma-separated list of users allowed to view/delete any share + shr-adm: ame,same # hint + + # shares can be revived by their owner if they expired less than MIN minutes ago; [60]=hour, [1440]=day, [10080]=week + shr-rt: 1440 # default + + # debug + shr-v + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// upload options \\00000000000000000000000000000000000000000000000000000000000000000000000\ + + # dotfile incomplete uploads, hiding them from clients unless -ed + dotpart + + # when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip + plain-ip + + # filename for nameless uploads (when uploader doesn't provide a name); default is [put-UNIXTIME-IP.bin] (the .6f means six decimal places) + # 📂 also available as volflag "put_name" + put-name: put-{now.6f}-{cip}.bin # default + + # default checksum-hasher for PUT/WebDAV uploads: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s + # 📂 also available as volflag "put_ck" + put-ck: sha512 # default + + # default checksum-hasher for bup/basic-uploader: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s + # 📂 also available as volflag "bup_ck" + bup-ck: sha512 # default + + # grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled, default=12h + unpost: 43200 # default (12h) + + # clients can abort incomplete uploads by using the unpost tab (requires -e2d). [0] = never allowed (disable feature), [1] = allow if client has the same IP as the upload AND is using the same account, [2] = just check the IP, [3] = just check account-name + # 📂 also available as volflag "u2abort" + u2abort: 1 # default + + # file write grace period (any client can write to a blank file last-modified more recently than SEC seconds ago) + blank-wt: 300 # default + + # max number of uploads to keep in memory when running without -e2d; roughly 1 MiB RAM per 600 + reg-cap: 38400 # default + + # disable file-handle pooling -- instead, repeatedly close and reopen files during upload (bad idea to enable this on windows and/or cow filesystems) + no-fpool + + # force file-handle pooling, even when it might be dangerous (multiprocessing, filesystems lacking sparse-files support, ...) + use-fpool + + # unix file permissions to use when creating files; default is probably 644 (OS-decided), see --help-chmod. Examples: [644] = owner-RW + all-R, [755] = owner-RWX + all-RX, [777] = full-yolo + # 📂 also available as volflag "chmod_f" + chmod-f: 644 # hint; default is unset + + # unix file permissions to use when creating directories; see --help-chmod. Examples: [755] = owner-RW + all-R, [777] = full-yolo + # 📂 also available as volflag "chmod_d" + chmod-d: 755 # default + + # unix user-id to chown new files/folders to; default = -1 = do-not-change + # 📂 also available as volflag "uid" + uid: 1000 # hint + + # unix group-id to chown new files/folders to; default = -1 = do-not-change + # 📂 also available as volflag "gid" + gid: 573 # hint + + # enable symlink-based upload deduplication + # 📂 also available as volflag "dedup" + dedup + + # how careful to be when deduplicating files; [1] = just verify the filesize, [50] = verify file contents have not been altered + # 📂 also available as volflag "safededup" + safe-dedup: 50 # default + + # enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) + # 📂 also available as volflag "hardlink" + hardlink + + # do not fallback to symlinks when a hardlink cannot be made + # 📂 also available as volflag "hardlinkonly" + hardlink-only + + # enable reflink-based dedup; will fallback on full copies when that is impossible (non-CoW filesystem) + # 📂 also available as volflag "reflink" + reflink + + # reject duplicate files during upload; only matches within the same volume + # 📂 also available as volflag "nodupe" + no-dupe + + # do not use existing data on disk to satisfy dupe uploads; reduces server HDD reads in exchange for much more network load + # 📂 also available as volflag "noclone" + no-clone + + # disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually + no-snap + + # write upload state to ./hist/up2k.snap every SEC seconds; allows resuming incomplete uploads after a server crash + snap-wri: 300 # default + + # forget unfinished uploads after MIN minutes; impossible to resume them after that (360=6h, 1440=24h) + snap-drop: 1440 # default + + # how to timestamp uploaded files; [c]=client-last-modified, [u]=upload-time, [fc]=force-c, [fu]=force-u + # 📂 also available as volflag "u2ts" + u2ts: c # default + + # force randomized filenames, --nrand chars long + # 📂 also available as volflag "rand" + rand + + # randomized filenames length + # 📂 also available as volflag "nrand" + nrand: 9 # default + + # enable filetype detection on nameless uploads + # 📂 also available as volflag "magic" + magic + + # ensure GiB free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [256m], [4], [2T] + # 📂 also available as volflag "df" + df: 4 # hint; default=0 + + # windows-only: minimum size of incoming uploads through up2k before they are made into sparse files + sparse: 4 # default + + # configure turbo-mode in up2k client; [-1] = forbidden/always-off, [0] = default-off and warn if enabled, [1] = default-off, [2] = on, [3] = on and disable datecheck + turbo: 0 # default + + # when to use a wasm-hasher instead of the browser's builtin; faster on chrome, but buggy in older chrome versions. [0] = only when necessary (non-https), [1] = always (all browsers), [2] = always on chrome/firefox, [3] = always on chrome, [N] = chrome-version N and newer (recommendation: 137) + nosubtle: 0 # default + + # web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed + u2j: 2 # default + + # web-client: default upload chunksize (MiB); sets min,default,max in the settings gui. Each HTTP POST will aim for default, and never exceed max. Cloudflare max is 96. Big values are good for cross-atlantic but may increase HDD fragmentation on some FS. Disable this optimization with [1,1,1] + u2sz: 1,64,96 # default + + # web-client: default setting for when to replace/overwrite existing files; [0]=never, [1]=if-client-newer, [2]=always + # 📂 also available as volflag "u2ow" + u2ow: 0 # default + + # upload order; [s]=smallest-first, [n]=alphabetical, [fs]=force-s, [fn]=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine + u2sort: s # default + + # write POST reports to textfiles in working-directory + write-uplog + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// network options \\0000000000000000000000000000000000000000000000000000000000000000000000\ + + # IPs and/or unix-sockets to listen on, COMMA-SEPARATED LIST (see --help-bind). Default: all IPv4 and IPv6 + i: 192.168.0.1,::1,unix:770:www:/dev/shm/party.sock # hint; default=:: + + # ports to listen on (comma/range); ignored for unix-sockets + p: 3923,4001-4005 # hint; default=3923 + + # include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients) + ll + + # which ip to associate clients with; [0]=tcp, [1]=origin (first x-fwd, unsafe), [2]=outermost-proxy, [3]=second-proxy, [-1]=closest-proxy + rproxy: 1 # default + + # if reverse-proxied, which http header to read the client's real ip from + xff-hdr: x-forwarded-for # default + + # list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (--xff-hdr) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [lan] to allow all LAN / private / non-internet IPs. Can be disabled with [any] if you are behind cloudflare (or similar) and are using --xff-hdr=cf-connecting-ip (or similar) + xff-src: 127.0.0.0/8, ::1/128 # default + + # only accept connections from IP-addresses inside CIDR (comma-separated); examples: [lan] or [10.89.0.0/16, 192.168.33.0/24] + ipa: 10.89.0.0/16, 192.168.33.0/24 # hint; default is unset + + # if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [/foo/bar] + rp-loc: /files # hint; default is unset + + # set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances + reuseaddr + + # allow listening on IPs which do not yet exist, for example if the network interfaces haven't finished going up. Only makes sense for IPs other than '0.0.0.0', '127.0.0.1', '::', and '::1'. May require running as root (unless net.ipv6.ip_nonlocal_bind) + freebind + + # write list of listening-on ip:port to textfile at PATH when http-servers have started + wr-h-eps: /dev/shm/listening-on.txt # hint; default is unset + + # write list of accessible-on ip:port to textfile at PATH when http-servers have started + wr-h-aon: /dev/shm/accessible-on.txt # hint; default is unset + + # socket timeout (read request header) + s-thead: 120 # default + + # socket timeout (read/write request/response bodies). Use 60 on fast servers (default is extremely safe). Disable with 0 if reverse-proxied for a 2% speed boost + s-tbody: 128 # default + + # socket read size in bytes (indirectly affects filesystem writes; recommendation: keep equal-to or lower-than --iobuf) + s-rd-sz: 262144 # default + + # socket write size in bytes + s-wr-sz: 262144 # default + + # debug: socket write delay in seconds + s-wr-slp: 0 # default + + # debug: response delay in seconds + rsp-slp: 0 # default + + # debug: response delay, random duration 0..SEC + rsp-jtr: 0 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// SSL/TLS options \\0000000000000000000000000000000000000000000000000000000000000000000000\ + + # disable ssl/tls -- force plaintext + http-only + + # disable plaintext -- force tls + https-only + + # path to file containing a concatenation of TLS key and certificate chain + cert: $XDG_CONFIG_PATH/.copyparty/cert.pem # default + + # set allowed ssl/tls versions; [help] shows available versions; default is what your python version considers safe + ssl-ver: ssl3,tls10 # hint; default is unset + + # set allowed ssl/tls ciphers; [help] shows available ciphers + ciphers: xtea,rot13 # hint; default is unset + + # dump some tls info + ssl-dbg + + # log master secrets for later decryption in wireshark + ssl-log: /mnt/stash/gotem.log # hint; default is unset + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// TLS certificate generator options \\0000000000000000000000000000000000000000000000000000\ + + # disable automatic certificate creation + no-crt + + # comma-separated list of FQDNs (domains) to add into the certificate + crt-ns: example.com,fileshare.nasa.gov + + # do not add wildcard entries for each --crt-ns + crt-exact + + # do not add autodetected IP addresses into cert + crt-noip + + # do not add 127.0.0.1 / localhost into cert + crt-nolo + + # do not add mDNS names / hostname into cert + crt-nohn + + # where to save the CA cert + crt-dir: $XDG_CONFIG_PATH/.copyparty/ # default + + # ca-certificate expiration time in days + crt-cdays: 3650 # default + + # server-cert expiration time in days + crt-sdays: 365 # default + + # CA/server-cert common-name + crt-cn: partyco # default + + # override CA name + crt-cnc: --crt-cn # default = copy the above + + # override server-cert name + crt-cns: --crt-cnc # default = copy the above + + # backdate in hours + crt-back: 72 # default + + # algorithm and keysize; one of these: ecdsa-256 rsa-4096 rsa-2048 + crt-alg: ecdsa-256 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// IdP / identity provider / user authentication options \\00000000000000000000000000000000\ + + # bypass the copyparty authentication checks if the request-header HN contains a username to associate the request with (for use with authentik/oauth/...) + # └─WARNING: if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy + idp-h-usr: idp-username # hint; default is unset + + # assume the request-header HN contains the groupname of the requesting user; can be referenced in config files for group-based access control + idp-h-grp: idp-groups # hint; default is unset + + # optional but recommended safeguard; your reverse-proxy will insert a secret header named HN into all requests, and the other IdP headers will be ignored if this header is not present + idp-h-key: supersecretmagicword # hint; default is unset + + # if there are multiple groups in --idp-h-grp, they are separated by one of the characters in RE + idp-gsep: |:;+, # default + + # where to store the known IdP users/groups (if you run multiple copyparty instances, make sure they use different DBs) + idp-db: $XDG_CONFIG_PATH/.copyparty/idp.db # default + + # how to use --idp-db; [0] = entirely disable, [1] = write-only (effectively disabled), [2] = remember users, [3] = remember users and groups. + # └─NOTE: 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 + idp-store: 1 # default + + # comma-separated list of users allowed to use /?idp (the cache management UI) + idp-adm: ben,jerry # hint; default is unset + + # generate a session-token for IdP users which is written to cookie cppws (or cppwd if plaintext), to reduce the load on the IdP server, lifetime S seconds. + # └─note: The expiration time is a client hint only; the actual lifetime of the session-token is infinite (until next restart with --ses-db wiped) + idp-cookie: 600 # hint; default=0=disabled + + # disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app + no-bauth + + # keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins + bauth-last + + # where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs) + ses-db: $XDG_CONFIG_PATH/.copyparty/sessions.db # default + + # session key length; default is 120 bits ((20//4)*4*6) + ses-len: 20 + + # disable sessions; use plaintext passwords in cookies + no-ses + + # REPEATABLE: users with IP matching CIDR are auto-authenticated as username USR; example: [172.16.24.0/24=dave] + ipu: CIDR=USR # placeholder + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// user-changeable passwords options \\0000000000000000000000000000000000000000000000000000\ + + # allow users to change their own passwords + chpw + + # REPEATABLE: do not allow password-changes for this comma-separated list of usernames + chpw-no: ole,dole,doffen # hint; default is unset + + # where to store the passwords database (if you run multiple copyparty instances, make sure they use different DBs) + chpw-db: $XDG_CONFIG_PATH/.copyparty/chpw.json + + # minimum password length + chpw-len: 8 # default + + # verbosity of summary on config load [0] = nothing at all, [1] = number of users, [2] = list users with default-pw, [3] = list all users + chpw-v: 2 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// Zeroconf options \\000000000000000000000000000000000000000000000000000000000000000000000\ + + # enable all zeroconf backends (mdns, ssdp) + z + + # enable zeroconf ONLY on the comma-separated list of subnets and/or interface names/indexes + # └─example: eth0, wlo1, virhost0, 192.168.123.0/24, fd00:fda::/96 + z-on: NETS # placeholder; default is unset + + # disable zeroconf on the comma-separated list of subnets and/or interface names/indexes + z-off: NETS # placeholder; default is unset + + # check for network changes every SEC seconds (0=disable) + z-chk: 10 # default + + # verbose all zeroconf backends + zv + + # rejoin multicast groups every SEC seconds (workaround for some switches/routers which cause mDNS to suddenly stop working after some time); try [300] or [180] + # └─note: can be due to firewalls; make sure UDP port 5353 is open in both directions (on clients too) + mc-hop: 0 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// Zeroconf-mDNS options; also see --help-zm \\00000000000000000000000000000000000000000000\ + + # announce the enabled protocols over mDNS (multicast DNS-SD) -- compatible with KDE, gnome, macOS, ... + zm + + # enable mDNS ONLY on the comma-separated list of subnets and/or interface names/indexes + zm-on: NETS # placeholder; default is unset + + # disable mDNS on the comma-separated list of subnets and/or interface names/indexes + zm-off: NETS # placeholder; default is unset + + # IPv4 only -- try this if some clients can't connect + zm4 + + # IPv6 only + zm6 + + # verbose mdns + zmv + + # verboser mdns + zmvv + + # mute parser errors (invalid incoming MDNS packets) + zm-no-pe + + # disable workaround for avahi-bug #379 (corruption in Avahi's mDNS reflection feature) + zm-nwa-1 + + # list of services to announce -- d=webdav h=http f=ftp s=smb -- lowercase=plaintext uppercase=TLS -- default: all enabled services except http/https (Ddfs if --ftp and --smb is set, Dd otherwise) + zms: dhf # probably default + + # link a specific folder for webdav shares + zm-ld: /public/stuff # hint; default is unset (webroot) + + # link a specific folder for http shares + zm-lh: /public/stuff # hint; default is unset (webroot) + + # link a specific folder for ftp shares + zm-lf: /public/stuff # hint; default is unset (webroot) + + # link a specific folder for smb shares + zm-ls: /public/stuff # hint; default is unset (webroot) + + # merge NICs which share subnets; assume that same subnet means same network + zm-mnic + + # merge subnets on each NIC -- always enabled for ipv6 -- reduces network load, but gnome-gvfs clients may stop working, and clients cannot be in subnets that the server is not + zm-msub + + # disable NSEC replies -- try this if some clients don't see copyparty + zm-noneg + + # send unsolicited announce every SEC; useful if clients have IPs in a subnet which doesn't overlap with the server, or to avoid some firewall issues + zm-spam: 0 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// Zeroconf-SSDP options \\0000000000000000000000000000000000000000000000000000000000000000\ + + # announce the enabled protocols over SSDP -- compatible with Windows + zs + + # enable SSDP ONLY on the comma-separated list of subnets and/or interface names/indexes + zs-on: NETS # placeholder; default is unset + + # disable SSDP on the comma-separated list of subnets and/or interface names/indexes + zs-off: NETS # placeholder; default is unset + + # verbose SSDP + zsv + + # location to include in the url (or a complete external URL), for example [priv/?pw=hunter2] (goes directly to /priv/ with password hunter2) or [?hc=priv&pw=hunter2] (shows mounting options for /priv/ with password) + zsl: /?hc # default + + # USN (device identifier) to announce + zsid: UUID # placeholder; default is an autogenerated UUID + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// FTP options (TCP only) \\000000000000000000000000000000000000000000000000000000000000000\ + + # enable FTP server on PORT, for example 3921 + ftp: 3921 # hint; default is unset + + # enable FTPS server on PORT, for example 3990 + ftps: 3990 # hint; default is unset + + # verbose + ftpv + + # only listen on IPv4 + ftp4 + + # only accept connections from IP-addresses inside CIDR (comma-separated); specify [any] to disable inheriting --ipa. Examples: [lan] or [10.89.0.0/16, 192.168.33.0/24] + ftp-ipa: CIDR # placeholder + + # if target file exists, reject upload instead of overwrite + ftp-no-ow + + # grace period for resuming interrupted uploads (any client can write to any file last-modified more recently than SEC seconds ago) + ftp-wt: 7 # default + + # the NAT address to use for passive connections + ftp-nat: 192.168.1.13 # hint; default is unset + + # the range of TCP ports to use for passive connections, for example 12000-13000 + ftp-pr: 12000-12099 # hint; default is unset + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// WebDAV options \\00000000000000000000000000000000000000000000000000000000000000000000000\ + + # enable full write support, even if client may not be webdav. WARNING: This has side-effects -- PUT-operations will now OVERWRITE existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client) + daw + + # allow depth:infinite requests (recursive file listing); extremely server-heavy but required for spec compliance -- luckily few clients rely on this + dav-inf + + # disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS) + dav-mac + + # show symlink-destination's lastmodified instead of the link itself; always enabled for recursive listings + # 📂 also available as volflag "davrt" + dav-rt + + # force auth for all folders (required by davfs2 when only some folders are world-readable) + # 📂 also available as volflag "davauth" + dav-auth + + # regex of tricky user-agents which expect 401 from GET requests; disable with [no] or blank + dav-ua1: kioworker/ # default (KDE) + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// TFTP options (UDP only) \\00000000000000000000000000000000000000000000000000000000000000\ + + # enable TFTP server on PORT, for example 69 or 3969 + tftp: 3969 # hint; default is unset + + # only listen on IPv4 + tftp4 + + # verbose + tftpv + + # verboser + tftpvv + + # debug: disable optimizations + tftp-no-fast + + # 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, ... + tftp-lsf: \.?(dir|ls)(\.txt)? # default + + # if someone tries to download a directory, return an error instead of showing its directory listing + tftp-nols + + # only accept connections from IP-addresses inside CIDR (comma-separated); specify [any] to disable inheriting --ipa. Examples: [lan] or [10.89.0.0/16, 192.168.33.0/24] + tftp-ipa: CIDR # placeholder + + # the range of UDP ports to use for data transfer, for example 12000-13000 + tftp-pr: 12100-12199 # hint; default is unset + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// SMB/CIFS options \\000000000000000000000000000000000000000000000000000000000000000000000\ + + # enable smb (read-only) -- this requires running copyparty as root on linux and macos unless --smb-port is set above 1024 and your OS does port-forwarding from 445 to that. + # └─WARNING: this protocol is DANGEROUS and buggy! Never expose to the internet! + smb + + # enable write support (please dont) + smbw + + # disable SMBv2, only enable SMBv1 (CIFS) + smb1 + + # port to listen on -- if you change this value, you must NAT from TCP:445 to this port using iptables or similar + smb-port: 445 # default + + # truncate directory listings to 64kB (~400 files); avoids impacket-0.11 bug, fixes impacket-0.12 performance + smb-nwa-1 + + # disable impacket workaround for filecopy globs + smb-nwa-2 + + # small performance boost: disable per-account permissions, enables account coalescing instead (if one user has write/delete-access, then everyone does) + smba + + # verbose + smbv + + # verboser + smbvv + + # verbosest + smbvvv + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// handlers (see --help-handlers) \\0000000000000000000000000000000000000000000000000000000\ + + # REPEATABLE: handle 404s by executing PY file + on404: ~/bin/on404.py # hint; default is unset + on404: ~/bin/on404season2.py + + # REPEATABLE: handle 403s by executing PY file + on403: ~/bin/on403.py # hint; default is unset + + # recompile handlers on each request -- expensive but convenient when hacking on stuff + hot-handlers + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// event hooks (see --help-hooks) \\0000000000000000000000000000000000000000000000000000000\ + + # REPEATABLE: execute CMD before a file upload starts + xbu: ~/bin/execute-before-upload.py # hint; default is unset + + # REPEATABLE: execute CMD after a file upload finishes + xau: ~/bin/execute-after-upload.py # hint; default is unset + + # REPEATABLE: execute CMD after all uploads finish and volume is idle + xiu: ~/bin/execute-idle-upload.py # hint; default is unset + + # REPEATABLE: execute CMD before a file copy + xbc: ~/bin/execute-before-copy.py # hint; default is unset + + # REPEATABLE: execute CMD after a file copy + xac: ~/bin/execute-after-copy.py # hint; default is unset + + # REPEATABLE: execute CMD before a file move/rename + xbr: ~/bin/execute-before-rename.py # hint; default is unset + + # REPEATABLE: execute CMD after a file move/rename + xar: ~/bin/execute-after-rename.py # hint; default is unset + + # REPEATABLE: execute CMD before a file delete + xbd: ~/bin/execute-before-delete.py # hint; default is unset + + # REPEATABLE: execute CMD after a file delete + xad: ~/bin/execute-after-delete.py # hint; default is unset + + # REPEATABLE: execute CMD on message + xm: ~/bin/execute-on-message.py # hint; default is unset + + # REPEATABLE: execute CMD if someone gets banned (pw/404/403/url) + xban: ~/bin/execute-on-ban.py # hint; default is unset + + # verbose hooks + hook-v + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// grafana/prometheus metrics endpoint \\00000000000000000000000000000000000000000000000000\ + + # enable openmetrics at /.cpr/metrics for admin accounts + stats + + # disable disk-space metrics (used/free space) + nos-hdd + + # disable volume size metrics (num files, total bytes, vmaxb/vmaxn) + nos-vol + + # disable volume state metrics (indexing, analyzing, activity) + nos-vst + + # disable dupe-files metrics (good idea; very slow) + nos-dup + + # disable unfinished-uploads metrics + nos-unf + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// yolo options \\0000000000000000000000000000000000000000000000000000000000000000000000000\ + + # disable csrf protections; let other domains/sites impersonate you through cross-site requests + allow-csrf + + # allow cookies from other domains (if you follow a link from another website into your server, you will arrive logged-in); this reduces protection against CSRF + cookie-lax + + # permit ?move=[...] and ?delete as GET + getmod + + # allow users with write-only access to upload logues and readmes without adding the _wo_ filename prefix + # 📂 also available as volflag "wo_up_readme" + wo-up-readme + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// opt-outs \\00000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # never write anything to disk (debug/benchmark) + nw + + # do not disable quick-edit-mode on windows (it is disabled to avoid accidental text selection in the terminal window, as this would pause execution) + keep-qem + + # disable webdav support + no-dav + + # disable delete operations + no-del + + # disable move/rename operations + no-mv + + # disable copy operations + no-cp + + # no title hostname; don't show --name in + nth + + # no info hostname -- don't show in UI + nih + + # no info disk-usage -- don't show in UI + nid + + # no powered-by-copyparty branding in UI + nb + + # reject download-as-zip if more than N files in total; optionally takes a unit suffix: [256], [9K], [4G] + # 📂 also available as volflag "zipmaxn" + zipmaxn: N # placeholder; default is unset + + # reject download-as-zip if total download size exceeds SZ bytes; optionally takes a unit suffix: [256M], [4G], [2T] + # 📂 also available as volflag "zipmaxs" + zipmaxs: SZ # placeholder; default is unset + + # custom errormessage when download size exceeds max + # 📂 also available as volflag "zipmaxt" + zipmaxt: TXT # placeholder; default is unset + + # authenticated users bypass the zip size limit + # 📂 also available as volflag "zipmaxu" + zipmaxu + + # who can download as zip/tar? [0]=nobody, [1]=admins, [2]=authenticated-with-read-access, [3]=everyone-with-read-access (volflag=zip_who) + # └─WARNING: if a nested volume has a more restrictive value than a parent volume, then this will be ignored if the download is initiated from the parent, more lenient volume + zip-who: 3 # default + + # regex of user-agents to reject from download-as-zip/tar; disable with [no] or blank + ua-nozip: Barkrowler|bingbot|BLEXBot|Googlebot|GoogleOther|GPTBot|PetalBot|SeekportBot|SemrushBot|YandexBot # default + + # disable download as zip/tar; same as --zip-who=0 + no-zip + + # disable download as compressed tar (?tar=gz, ?tar=bz2, ?tar=xz, ?tar=gz:9, ...) + no-tarcmp + + # do not allow clients (or server config) to schedule an upload to be deleted after a given time + no-lifetime + + # disable race-the-beam (lockstep download of files which are currently being uploaded) + # 📂 also available as volflag "nopipe" + no-pipe + + # disable streaming a growing files with ?tail + # 📂 also available as volflag "notail" + no-tail + + # do not write uploader-IP into the database; will also disable unpost, you may want --forget-ip instead + # 📂 also available as volflag "no_db_ip" + no-db-ip + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// safety options \\00000000000000000000000000000000000000000000000000000000000000000000000\ + + # increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers. + # └─Alias of --dotpart --no-thumb --no-mtag-ff --no-robots --force-js + s + + # further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s. + # └─Alias of -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih + ss + + # further increase safety: Enable logging to disk, scan for dangerous symlinks. + # └─Alias of -ss --no-dav --no-logues --no-readme -lo=cpp-%Y-%m%d-%H%M%S.txt.xz --ls=**,*,ln,p,r + sss + + # do a sanity/safety check of all volumes on startup; arguments USER,VOL,FLAGS (see --help-ls); example [**,*,ln,p,r] + ls: **,*,ln,p,r # hint; default is unset + + # never follow symlinks leaving the volume root, unless the link is into another volume where the user has similar access + # 📂 also available as volflag "xvol" + xvol + + # stay within the filesystem of the volume root; do not descend into other devices (symlink or bind-mount to another HDD, ...) + # 📂 also available as volflag "xdev" + xdev + + # disallow moving dotfiles; makes it impossible to move folders containing dotfiles + no-dot-mv + + # disallow renaming dotfiles; makes it impossible to turn something into a dotfile + no-dot-ren + + # disable rendering .prologue/.epilogue.html into directory listings + no-logues + + # disable rendering readme/preadme.md into directory listings + no-readme + + # send 404 instead of 403 (security through ambiguity, very enterprise) + vague-403 + + # don't send folder listings as HTML, force clients to use the embedded json instead -- slight protection against misbehaving search engines which ignore --no-robots + force-js + + # adds http and html headers asking search engines to not index anything + # 📂 also available as volflag "norobots" + no-robots + + # logout clients after H hours of inactivity; [0.0028]=10sec, [0.1]=6min, [24]=day, [168]=week, [720]=month, [8760]=year) + logout: 8086 # default + + # more than N wrong passwords in W minutes = ban for B minutes; disable with [no] + ban-pw: 9,60,1440 # default + + # more than N password-changes in W minutes = ban for B minutes; disable with [no] + ban-pwc: 5,60,1440 # default + + # hitting more than N 404's in W minutes = ban for B minutes; only affects users who cannot see directory listings because their access is either g/G/h + ban-404: 50,60,1440 # default + + # hitting more than N 403's in W minutes = ban for B minutes; [1440]=day, [10080]=week, [43200]=month + ban-403: 9,2,1440 # default + + # hitting more than N 422's in W minutes = ban for B minutes (invalid requests, attempted exploits ++) + ban-422: 9,2,1440 # default + + # hitting more than N sus URL's in W minutes = ban for B minutes; applies only to permissions g/G/h (decent replacement for --ban-404 if that can't be used) + ban-url: 9,2,1440 # default + + # URLs which are considered sus / eligible for banning; disable with blank or [no] + sus-urls: \.php$|(^|/)wp-(admin|content|includes)/ # default + + # harmless URLs ignored from 404-bans; disable with blank or [no] + nonsus-urls: ^(favicon\.ico|robots\.txt)$|^apple-touch-icon|^\.well-known # default + + # 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 + early-ban + + # if a client maxes out the server connection limit, downgrade it from connection:keep-alive to connection:close for MIN minutes (and also kill its active connections) -- disable with 0 + aclose: 10 # default + + # if a client maxes out the server connection limit without sending headers, ban it for B minutes; disable with [0] + loris: 60 # default + + # Access-Control-Allow-Origin; list of origins (domains/IPs without port) to accept requests from; [https://1.2.3.4]. Default [*] allows requests from all sites but removes cookies and http-auth; only ?pw=hunter2 survives + acao: * # default + + # Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like --acao's description) + acam: GET,HEAD # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// salting options \\0000000000000000000000000000000000000000000000000000000000000000000000\ + + # account-pw hashing algorithm; one of these, best to worst: argon2 scrypt sha2 none (each optionally followed by alg-specific comma-sep. config) + ah-alg: argon2 # hint; default is unset + + # account-pw salt; ignored if --ah-alg is none (default) + ah-salt: shangalabangala # hint; default is autogenerated and stored in $XDG_CONFIG_PATH/.copyparty/ + + # generate hashed password for PW, or read passwords from STDIN if PW is [-] + ah-gen: PW # placeholder + + # launch an interactive shell which hashes passwords without ever storing or displaying the original passwords + ah-cli + + # per-file accesskey salt; used to generate unpredictable URLs for hidden files + fk-salt: shangalabangala # hint; default is autogenerated and stored in $XDG_CONFIG_PATH/.copyparty/ + + # per-directory accesskey salt; used to generate unpredictable URLs to share folders with users who only have the 'get' permission + dk-salt: shangalabangala # hint; default is autogenerated and stored in $XDG_CONFIG_PATH/.copyparty/ + + # up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do) + warksalt: hunter2 # default + + # on startup, print the effective value of --ah-salt (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified) + show-ah-salt + + # on startup, print the effective value of --fk-salt (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified) + show-fk-salt + + # on startup, print the effective value of --dk-salt (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified) + show-dk-salt + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// shutdown options \\000000000000000000000000000000000000000000000000000000000000000000000\ + + # continue running even if it's impossible to listen on some of the requested endpoints + ign-ebind + + # continue running even if it's impossible to receive connections at all + ign-ebind-all + + # shutdown after WHEN has finished; [cfg] config parsing, [idx] volscan + multimedia indexing + exit: WHEN # placeholder; default is unset + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// logging options \\0000000000000000000000000000000000000000000000000000000000000000000000\ + + # quiet; disable most STDOUT messages + q + + # logfile, example: cpp-%Y-%m%d-%H%M%S.txt.xz (NB: some errors may appear on STDOUT only) + lo: PATH # placeholder + + # disable colors; same as environment-variable NO_COLOR + no-ansi + + # force colors; overrides environment-variable NO_COLOR + ansi + + # don't flush the logfile after each write; tiny bit faster + no-logflush + + # do not list volumes and permissions on startup + no-voldump + + # do not use local timezone; assume the TZ env-var is UTC (tiny bit faster) + log-utc + + # timestamp resolution / number of timestamp decimals + log-tdec: 3 # default + + # log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed + log-badpwd: 1 # default + + # debug: print tcp-server msgs + log-conn + + # debug: print http-server threadpool scaling + log-htp + + # print request HEADER; [*]=all + ihead: user-agent # hint; default is unset + + # print response HEADER; [*]=all + ohead: set-cooke # hint; default is unset + + # dont log URLs matching regex RE + lf-url: ^/\.cpr/|[?&]th=[wjp]|/\.(_|ql_|DS_Store$|localized$) # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// admin panel options \\000000000000000000000000000000000000000000000000000000000000000000\ + + # disable ?reload=cfg (reload users/volumes/volflags from config file) + no-reload + + # disable ?scan (volume reindexing) + no-rescan + + # disable ?stack (list all stacks) + no-stack + + # disable ?ru (list of recent uploads) + no-ups-page + + # don't show list of incoming files in controlpanel + no-up-list + + # who can see active downloads in the controlpanel? [0]=nobody, [1]=admins, [2]=everyone + dl-list: 2 # default + + # who can see recent uploads on the ?ru page? [0]=nobody, [1]=admins, [2]=everyone + # 📂 also available as volflag "ups_who" + ups-who: 2 # default + + # let everyone see upload timestamps on the ?ru page, not just admins + ups-when + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// thumbnail options \\00000000000000000000000000000000000000000000000000000000000000000000\ + + # disable all thumbnails + # 📂 also available as volflag "dthumb" + no-thumb + + # disable video thumbnails + # 📂 also available as volflag "dvthumb" + no-vthumb + + # disable audio thumbnails (spectrograms) + # 📂 also available as volflag "dathumb" + no-athumb + + # thumbnail res + # 📂 also available as volflag "thsize" + th-size: 320x256 # default + + # num cpu cores to use for generating thumbnails + th-mt: 4 # hint; default is autodetect + + # conversion timeout in seconds + # 📂 also available as volflag "convt" + th-convt: 60 # default + + # max memory usage (GiB) permitted by thumbnailer; not very accurate + th-ram-max: 3 # hint; default is 60% of free ram at startup (some conditions apply) + + # crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [y]=crop, [n]=nocrop, [fy]=force-y, [fn]=force-n + # 📂 also available as volflag "crop" + th-crop: y # default + + # show thumbs at 3x resolution; client can override in UI unless force. [y]=yes, [n]=no, [fy]=force-yes, [fn]=force-no + # 📂 also available as volflag "th3x" + th-x3: n # default + + # image decoders, in order of preference + th-dec: vips,pil,ff # default + + # disable jpg output + th-no-jpg + + # disable webp output + th-no-webp + + # force jpg output for video thumbs (avoids issues on some FFmpeg builds) + th-ff-jpg + + # use swresample instead of soxr for audio thumbs (faster, lower accuracy, avoids issues on some FFmpeg builds) + th-ff-swr + + # activity labeling cooldown -- avoids doing keepalive pokes (updating the mtime) on thumbnail folders more often than SEC seconds + th-poke: 300 # default + + # cleanup interval; 0=disabled + th-clean: 43200 # default + + # max folder age -- folders which haven't been poked for longer than --th-poke seconds will get deleted every --th-clean seconds + th-maxage: 604800 # default + + # folder thumbnails to stat/look for; enabling -e2d will make these case-insensitive, and try them as dotfiles (.folder.jpg), and also automatically select thumbnails for all folders that contain pics, even if none match this pattern + th-covers: folder.png,folder.jpg,cover.png,cover.jpg # default + + # image formats to decode using pillow + th-r-pil: a,very,long,list,of,file,extensions # hint + + # image formats to decode using pyvips + th-r-vips: a,very,long,list,of,file,extensions # hint + + # image formats to decode using ffmpeg + th-r-ffi: a,very,long,list,of,file,extensions # hint + + # video formats to decode using ffmpeg + th-r-ffv: a,very,long,list,of,file,extensions # hint + + # audio formats to decode using ffmpeg + th-r-ffa: a,very,long,list,of,file,extensions # hint + + # audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms) + th-spec-cnv: a,very,long,list,of,file,extensions # hint + + # audio/image formats to decompress before passing to ffmpeg + au-unpk: mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, and so on + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// transcoding options \\000000000000000000000000000000000000000000000000000000000000000000\ + + # target bitrate for transcoding to opus; set 0 to disable + q-opus: 128 # default + + # target quality for transcoding to mp3, for example [192k] (CBR) or [q0] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable + q-mp3: q2 # default + + # allow transcoding to wav (lossless, uncompressed) + allow-wav + + # allow transcoding to flac (lossless, compressed) + allow-flac + + # disable transcoding to caf-opus (affects iOS v12~v17), will use mp3 instead + no-caf + + # disable transcoding to webm-opus (iOS v18 and later), will use mp3 instead + no-owa + + # disable audio transcoding + no-acode + + # disable batch audio transcoding by folder download (zip/tar) + no-bacode + + # delete cached transcode output after SEC seconds + ac-maxage: 86400 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// tailing options (realtime streaming of a growing file) \\0000000000000000000000000000000\ + + # who can tail? [0]=nobody, [1]=admins, [2]=authenticated-with-read-access, [3]=everyone-with-read-access + # 📂 also available as volflag "tail_who" + tail-who: 2 # default + + # do not allow starting a new tail if more than N active downloads + tail-cmax: 64 # default + + # terminate connection after SEC seconds; [0]=never + # 📂 also available as volflag "tail_tmax" + tail-tmax: 0 # default + + # check for new data every SEC seconds + # 📂 also available as volflag "tail_rate" + tail-rate: 0.2 # default + + # send a zerobyte if connection is idle for SEC seconds to prevent disconnect + tail-ka: 3 # default + + # check if file was replaced (new fd) if idle for SEC seconds + # 📂 also available as volflag "tail_fd" + tail-fd: 1 # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// RSS options \\00000000000000000000000000000000000000000000000000000000000000000000000000\ + + # enable RSS output (experimental) + # 📂 also available as volflag "rss" + rss + + # default number of files to return (url-param 'nf') + rss-nf: 250 # default + + # default list of file extensions to include (url-param 'fext'); blank=all + rss-fext: mp3,opus # hint; default is unset + + # default sort order (url-param 'sort'); [m]=last-modified [u]=upload-time [n]=filename [s]=filesize; Uppercase=oldest-first. Note that upload-time is 0 for non-uploaded files + rss-sort: m # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// general db options \\0000000000000000000000000000000000000000000000000000000000000000000\ + + # enable up2k database; this enables file search, upload-undo, improves deduplication + e2d + + # scan writable folders for new files on startup; sets -e2d + e2ds + + # scans all folders on startup; sets -e2ds + e2dsa + + # verify file integrity; rehash all files and compare with db + e2v + + # on hash mismatch: update the database with the new hash + e2vu + + # on hash mismatch: panic and quit copyparty + e2vp + + # where to store volume data (db, thumbs); default is a folder named ".hist" inside each volume + # 📂 also available as volflag "hist" + hist: PATH # placeholder; default is unset + + # override where the volume databases are to be placed; default is the same as --hist + # 📂 also available as volflag "dbpath" + dbpath: PATH # placeholder; default is unset + + # regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans + # 📂 also available as volflag "nohash" + no-hash: ^/mnt/nas/linux-isos/knoppix/ + + # regex: disable indexing of matching absolute-filesystem-paths during e2ds folder scans + # 📂 also available as volflag "noidx" + no-idx: ^/mnt/nas/logs/ + + # do not show total recursive size of folders in listings, show inode size instead; slightly faster + # 📂 also available as volflag "nodirsz" + no-dirsz + + # if the directory-sizes in the UI are bonkers, use this along with -e2dsa to rebuild the index from scratch + re-dirsz + + # disable rescan acceleration; do full database integrity check -- makes the db ~5% smaller and bootup/rescans 3~10x slower + no-dhash + + # force a cache rebuild on startup; enable this once if it gets out of sync (should never be necessary) + re-dhash + + # never forget indexed files, even when deleted from disk -- makes it impossible to ever upload the same file twice -- only useful for offloading uploads to a cloud service or something + # 📂 also available as volflag "noforget" + no-forget + + # remove uploader-IP from database (and make unpost impossible) MIN minutes after upload, for GDPR reasons. Default [0] is never-forget. [1440]=day, [10080]=week, [43200]=month. + # 📂 also available as volflag "forget_ip" + forget-ip: 0 # default (disabled) + + # database durability profile; sets the tradeoff between robustness and speed, see --help-dbd + # 📂 also available as volflag "dbd" + dbd: wal # default + + # on upload: check all volumes for dupes, not just the target volume (probably buggy, not recommended) + # 📂 also available as volflag "xlink" + xlink + + # num cpu cores to use for file hashing; set 0 or 1 for single-core hashing + hash-mt: 4 # default is autodetect but max 5 + + # rescan filesystem for changes every SEC seconds; 0=off + # 📂 also available as volflag "scan" + re-maxage: 0 # default + + # defer any scheduled volume reindexing until SEC seconds after last db write (uploads, renames, ...) + db-act: 10 # default + + # search deadline -- terminate searches running for more than SEC seconds + srch-time: 45 # default + + # max search results to allow clients to fetch; 125 results will be shown initially + srch-hits: 7999 # default + + # regex: exclude files from search results if the file-URL matches PTN (case-sensitive) + # 📂 also available as volflag "srch_excl" + srch-excl: password|logs/[0-9] # hint (any URL containing 'password' or 'logs/DIGIT'), default is unset + + # show dotfiles in search results (volflags: dotsrch | nodotsrch) + dotsrch + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// metadata db options \\000000000000000000000000000000000000000000000000000000000000000000\ + + # enable metadata indexing; makes it possible to search for artist/title/codec/resolution/... + e2t + + # scan newly discovered files for metadata on startup; sets -e2t + e2ts + + # delete all metadata from DB and do a full rescan; sets -e2ts + e2tsr + + # use FFprobe for tags instead; will detect more tags + no-mutagen + + # never use FFprobe as tag reader; is probably safer + no-mtag-ff + + # timeout for FFprobe tag-scan + mtag-to: 60 # default + + # num cpu cores to use for tag scanning + mtag-mt: 4 # hint; default is autodetect + + # verbose tag scanning; print errors from mtp subprocesses and such + mtag-v + + # debug mtp settings and mutagen/FFprobe parsers + mtag-vv + + # REPEATABLE: add/replace metadata mapping + mtm: qux=foo,bar # hint (clone metadata-key foo to qux with bar as fallback); default is unset + + # tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar" + mte: .files,circle,album,.tn,artist,title,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash # default + + # tags to hide by default (comma-sep.); assign/add/remove same as -mte" + mth: .vq,.aq,vc,ac,fmt,res,.fps # default + + # REPEATABLE: read tag M using program BIN to parse the file + mtp: .bpm=~/bin/audio-bpm.py # hint; default is unset + mtp: key=f,t5,~/bin/audio-key.py + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// textfile options \\000000000000000000000000000000000000000000000000000000000000000000000\ + + # where to store old version of markdown files; [s]=subfolder, [v]=volume-histpath, [n]=nope/disabled + # 📂 also available as volflag "md_hist" + md-hist: s # default + + # the textfile editor will check for serverside changes every SEC seconds + mcr: 60 # default + + # enable markdown plugins -- neat but dangerous, big XSS risk + emp + + # enable textfile expansion -- replace {{self.ip}} and such; see --help-exp + # 📂 also available as volflag "exp" + exp + + # comma/space-separated list of placeholders to expand in markdown files; add/remove stuff on the default list with +hdr_foo or /vf.scan + # 📂 also available as volflag "exp_md" + exp-md: self.ip self.ua self.uname self.host cfg.name cfg.logout vf.scan vf.thsize hdr.cf_ipcountry srv.itime srv.htime # default + + # comma/space-separated list of placeholders to expand in prologue/epilogue files + # 📂 also available as volflag "exp_lg" + exp-lg: self.ip self.ua self.uname self.host cfg.name cfg.logout vf.scan vf.thsize hdr.cf_ipcountry srv.itime srv.htime # default + + # regex of user-agents to reject from viewing documents through ?doc=[...]; disable with [no] or blank + ua-nodoc: Barkrowler|bingbot|BLEXBot|Googlebot|GoogleOther|GPTBot|PetalBot|SeekportBot|SemrushBot|YandexBot # default + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// og / open graph / discord-embed options \\0000000000000000000000000000000000000000000000\ + + # disable hotlinking and return an html document instead; this is required by open-graph, but can also be useful on its own + # 📂 also available as volflag "og" + og + + # only disable hotlinking / engage OG behavior if the useragent matches regex RE + # 📂 also available as volflag "og_ua" + og-ua: (Discord|Twitter|Slack)bot # hint; default is unset + + # do not return the regular copyparty html, but instead load the jinja2 template at PATH (if path contains 'EXT' then EXT will be replaced with the requested file's extension) + # 📂 also available as volflag "og_tpl" + og-tpl: /var/copyparty/opengraph-EXT.j2 # hint; default is unset + + # do not automatically add OG entries into <head> (useful if you're doing this yourself in a template or such) + # 📂 also available as volflag "og_no_head" + og-no-head + + # thumbnail format; j=jpeg, jf=jpeg-uncropped, jf3=jpeg-uncropped-large, w=webm, ... + # 📂 also available as volflag "og_th" + og-th: jf3 # default + + # fallback title if there is nothing in the -e2t database + # 📂 also available as volflag "og_title" + og-title: HEY CHECK THIS OUT # hint; default is blank + + # audio title format; takes any metadata key + # 📂 also available as volflag "og_title_a" + og-title-a: 🎵 {{ artist }} - {{ title }} # default + + # video title format; takes any metadata key + # 📂 also available as volflag "og_title_v" + og-title-v: {{ title }} # default + + # image title format; takes any metadata key + # 📂 also available as volflag "og_title_i" + og-title-i: {{ title }} # default + + # force default title; do not read from tags + # 📂 also available as volflag "og_s_title" + og-s-title + + # description text; same for all files, disable with [-] + # 📂 also available as volflag "og_desc" + og-desc: bottom text # hint; default is blank + + # sitename; defaults to --name, disable with [-] + # 📂 also available as volflag "og_site" + og-site: dank memes # hint; default is blank which means it'll copy the `name` global-option + + # accent color (3 or 6 hex digits); may also affect safari and/or android-chrome + # 📂 also available as volflag "tcolor" + tcolor: 333 # default (copyparty gray) + + # query-string parceling; translate a request for /foo/.uqe/BASE64 into /foo?TEXT, or /foo/?TEXT if the first character in TEXT is a slash. Automatically enabled for --og + uqe + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// ui options \\000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # show grid/thumbnails by default + # 📂 also available as volflag "grid" + grid + + # select files in grid by ctrl-click + # 📂 also available as volflag "gsel" + gsel + + # default to local timezone instead of UTC + localtime + + # language; one of the following: eng nor chi + lang: eng # default + + # default theme to use (0..7) + theme: 0 # default + + # number of themes installed + themes: 8 # default + + # default audio/video volume percent + au-vol: 50 # default; anything 0-100 + + # default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: href -href ext sz ts tags/Album tags/.tn + # 📂 also available as volflag "sort" + sort: href # default + + # default-enable natural sort of filenames with leading numbers + # 📂 also available as volflag "nsort" + nsort + + # number of sorting rules to include in media URLs by default + # 📂 also available as volflag "hsortn" + hsortn: 2 # default + + # default-enable seeing dotfiles; only takes effect if user has the necessary permissions + see-dots + + # number of confirmations to show when deleting files (2/1/0) + qdel: 2 # default + + # don't show files/folders matching REGEX in file list. WARNING: Purely cosmetic! Does not affect API calls, just the browser. Example: [\.(js|css)$] + # 📂 also available as volflag "unlist" + unlist: REGEX # placeholder + + # favicon-text [ foreground [ background ] ], set blank to disable + favico: c 000 none # default + + # REPEATABLE: use thumbnail-image VP for file-extension E, example: [exe=/.res/exe.png] + # 📂 also available as volflag "ext_th" + ext-th: 7z=/.icons/archive.png # hint; default is unset + ext-th: exe=/.icons/glass-of-red-liquid.png + + # emoji or emoji,css Example: [🥖,padding:0] + spinner: 🌲 # default + + # URL to additional CSS to include in the filebrowser html + css-browser: /.res/rice.css # hint; default is unset + + # URL to additional JS to include in the filebrowser html + js-browser: /.res/mousetrail.js # hint; default is unset + + # URL to additional JS to include in all other pages + js-other: /.res/snowflakes.jpg # hint; default is unset + + # 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 + # 📂 also available as volflag "html_head" + html-head: <script>alert(1);</script> # hint; default is unset + + # 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) + ih + + # file extensions to present as plaintext + textfiles: txt,nfo,diz,cue,readme # default + + # max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS) + txt-max: 64 # default + + # title / service-name to show in html documents + doctitle: copyparty @ --name # default (--name will copy from global-option `name`) + + # server name (displayed in filebrowser document title) + bname: --name # default (copy global-option `name`) + + # powered-by link; disable with -nb + pb-url: https://github.com/9001/copyparty # default + + # show version on the control panel (incompatible with -nb) + ver + + # configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [0] = hidden and default-off, [1] = visible and default-off, [2] = visible and default-on + k304: 0 # default + + # configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [0] = hidden and default-off, [1] = visible and default-off, [2] = visible and default-on + no304: 0 # default + + # list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox + md-sbf: downloads forms popups scripts top-navigation-by-user-activation # default + + # list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs + # 📂 also available as volflag "lg_sbf" + lg-sbf: downloads forms popups scripts top-navigation-by-user-activation # default + + # the value of the iframe 'allow' attribute for README.md docs, for example [fullscreen] + # 📂 also available as volflag "md_sba" + md-sba: fullscreen # hint; default is blank + + # 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 + lg-sba: TXT # placeholder + + # don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md) + no-sb-md + + # don't sandbox prologue/epilogue docs (volflags: no_sb_lg | sb_lg); enables non-js support + no-sb-lg + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// debug options \\000000000000000000000000000000000000000000000000000000000000000000000000\ + + # verbose config file parser (explain config) + vc + + # generate config file from current config (best-effort; probably buggy) + cgen + + # list information about detected optional dependencies + deps + + # kernel-bug workaround: disable poll; use select instead (limits max num clients to ~700) + no-poll + + # kernel-bug workaround: disable sendfile; do a safe and slow read-send-loop instead + no-sendfile + + # kernel-bug workaround: disable scandir; do a listdir + stat on each file instead + no-scandir + + # wait for initial filesystem indexing before accepting client requests + no-fastboot + + # disable httpserver threadpool, create threads as-needed instead + no-htp + + # when listening on unix-sockets, do a basic delete+bind instead of the default atomic bind + rm-sck + + # explain search processing, and do some extra expensive sanity checks + srch-dbg + + # use mdns-domain instead of server-ip on /?hc + rclone-mdns + + # write stacktrace to Path every S second, for example --stackmon=./st/%Y-%m/%d/%H%M.xz,60 + stackmon: P,S # placeholder + + # list active threads every SEC + log-thrs: 0 # default + + # log filekey params for files where path matches REGEX; [.] (a single dot) = all files + log-fk: /mnt/a-problematic-fuse/this-folder-breaks-filekeys/ # hint; default is unset + + # [up2k] if a client uploads a bitflipped/corrupted chunk, store a copy according to --bf-nc and --bf-dir + bak-flips + + # bak-flips: stop if there's more than NUM files at --kf-dir already; default: 6.3 GiB max (200*32M) + bf-nc: 200 # default + + # bak-flips: store corrupted chunks at PATH; default: folder named 'bf' wherever copyparty was started + bf-dir: /srv/bitflips/ # hint; default = bf + + # bak-flips: log corruption info to a textfile at PATH + bf-log: /srv/bitflips/the-history.txt # hint; default is unset + + ############################################################################################### + ############################################################################################### + ############################################################################################### + ############################################################################################### + ############################################################################################### + ############################################################################################### + #####/ + ##### This is the end of the [global] config section + ####/ + +[accounts] + foo: bar # username foo, password bar + +[groups] + g1: u1, u2, u3 # group "g1" with users u1, u2, and u3 + +[/the/url/to/share/this/volume/on/] + /the/actual/filesystem/path/ + accs: + r: username_who_gets_Read_access + w: username_who_gets_Write_access + m: username_who_gets_Move_access + d: username_who_gets_Delete_access + .: username_who_can_see_Dotfiles + g: username_who_gets_Get_access + G: username_who_gets_upGet_access + h: username_who_gets_html_access + a: username_who_gets_admin_access + A: username_who_gets_ReadWriteMoveDeleteDotfileAdmin_access + rwm: @g1 # the group "g1" gets Read+Write+Move + flags: + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// uploads, general \\000000000000000000000000000000000000000000000000000000000000000000000\ + + # enable symlink-based file deduplication + dedup + + # enable hardlink-based file deduplication, with fallback on symlinks when that is impossible + hardlink + + # dedup with hardlink only, never symlink; make a full copy if hardlink is impossible + hardlinkonly + + # enable reflink-based file deduplication, with fallback on full copy when that is impossible + reflink + + # verify on-disk data before using it for dedup + safededup + + # take dupe data from clients, even if available on HDD + noclone + + # rejects existing files (instead of linking/cloning them) + nodupe + + # unix-permission for new dirs/folders + chmod_d: 755 + + # unix-permission for new files + chmod_f: 644 + + # change owner of new files/folders to unix-user 573 + uid: 573 + + # change owner of new files/folders to unix-group 999 + gid: 999 + + # force use of sparse files, mainly for s3-backed storage + sparse + + # deny use of sparse files, mainly for slow storage + nosparse + + # enable full WebDAV write support (dangerous); PUT-operations will now OVERWRITE existing files + daw + + # forces all uploads into the top folder of the vfs + nosub + + # enables filetype detection for nameless uploads + magic + + # fallback filename for nameless uploads + put_name + + # default checksum-hasher for PUT/WebDAV uploads + put_ck + + # default checksum-hasher for bup/basic uploads + bup_ck + + # allows server-side gzip compression of uploads with ?gz + gz + + # allows server-side lzma compression of uploads with ?xz + xz + + # forces server-side compression, optional arg: xz,9 + pk + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// upload rules \\0000000000000000000000000000000000000000000000000000000000000000000000000\ + + # max 250 uploads over 15min + maxn: 250,600 + + # max 1 GiB over 5min (suffixes: b, k, m, g, t) + maxb: 1g,300 + + # total volume size max 1 GiB (suffixes: b, k, m, g, t) + vmaxb: 1g + + # max 4096 files in volume (suffixes: b, k, m, g, t) + vmaxn: 4k + + # return medialinks for non-up2k uploads (not hotlinks) + medialinks + + # write-only users can upload logues without getting renamed + wo_up_readme + + # force randomized filenames, 9 chars long by default + rand + + # randomized filenames are N chars long + nrand: N + + # overwrite existing files? 0=no 1=if-older 2=always + u2ow: N + + # [f]orce [c]lient-last-modified or [u]pload-time + u2ts: fc + + # allow aborting unfinished uploads? 0=no 1=strict 2=ip-chk 3=acct-chk + u2abort: 1 + + # allow filesizes between 1 KiB and 3MiB + sz: 1k-3m + + # ensure 1 GiB free disk space + df: 1g + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// upload rotation -- (moves all uploads into the specified folder structure) \\00000000000\ + + # 3 levels of subfolders with 100 entries in each + rotn: 100,3 + + # date-formatted organizing + rotf: %Y-%m/%d-%H + + # uploads are deleted after 1 hour + lifetime: 3600 + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// database, general \\00000000000000000000000000000000000000000000000000000000000000000000\ + + # enable database; makes files searchable + enables upload-undo + e2d + + # scan writable folders for new files on startup; also sets -e2d + e2ds + + # scans all folders for new files on startup; also sets -e2d + e2dsa + + # enable multimedia indexing; makes it possible to search for tags + e2t + + # scan existing files for tags on startup; also sets -e2t + e2ts + + # delete all metadata from DB (full rescan); also sets -e2ts + e2tsr + + # disables metadata collection for existing files + d2ts + + # verify integrity on startup by hashing files and comparing to db + e2v + + # when e2v fails, update the db (assume on-disk files are good) + e2vu + + # when e2v fails, panic and quit copyparty + e2vp + + # disables onboot indexing, overrides -e2ds* + d2ds + + # disables metadata collection, overrides -e2t* + d2t + + # disables file verification, overrides -e2v* + d2v + + # disables all database stuff, overrides -e2* + d2d + + # puts thumbnails and indexes at that location + hist: /tmp/cdb + + # puts indexes at that location + dbpath: /tmp/cdb + + # disable db if file foo doesn't exist + landmark: foo + + # scan for new files every 60sec, same as --re-maxage + scan: 60 + + # skips hashing file contents if path matches *.iso + nohash: \.iso$ + + # fully ignores the contents at paths matching *.iso + noidx: \.iso$ + + # don't forget files when deleted from disk + noforget + + # forget uploader-IP after 30 days (GDPR) + forget_ip: 43200 + + # never store uploader-IP in the db; disables unpost + no_db_ip + + # avoid excessive reindexing on android sdcardfs + fat32 + + # database speed-durability tradeoff + dbd: [acid|swal|wal|yolo] + + # cross-volume dupe detection / linking (dangerous) + xlink + + # do not descend into other filesystems + xdev + + # do not follow symlinks leaving the volume root + xvol + + # show dotfiles in search results + dotsrch + + # hide dotfiles in search results (default) + nodotsrch + + # exclude search results with URL matching this regex + srch_excl + + # media-tags to index/display + mte: artist,title + + # media-tags to hide by default + mth: fmt,res,ac + + # uses the "audio-bpm.py" program to generate ".bpm" tags from uploads (f = overwrite tags) + mtp: .bpm=f,audio-bpm.py + + # collects two tags at once + mtp: ahash,vhash=media-hash.py + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// thumbnails \\000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # disables all thumbnails + dthumb + + # disables video thumbnails + dvthumb + + # disables audio thumbnails (spectrograms) + dathumb + + # disables image thumbnails + dithumb + + # compress audio waveforms 33% better + pngquant + + # thumbnail res; WxH + thsize + + # center-cropping (y/n/fy/fn) + crop + + # 3x resolution (y/n/fy/fn) + th3x + + # conversion timeout in seconds + convt + + # use /b.png as thumbnail for file-extension s + ext_th: s=/b.png + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// handlers -- (better explained in --help-handlers) \\000000000000000000000000000000000000\ + + # handle 404s by executing PY file + on404: ~/bin/hook.py + + # handle 403s by executing PY file + on403: ~/bin/hook.py + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// event hooks -- (better explained in --help-hooks) \\000000000000000000000000000000000000\ + + # execute CMD before a file upload starts + xbu: ~/bin/hook.py + + # execute CMD after a file upload finishes + xau: ~/bin/hook.py + + # execute CMD after all uploads finish and volume is idle + xiu: ~/bin/hook.py + + # execute CMD before a file copy + xbc: ~/bin/hook.py + + # execute CMD after a file copy + xac: ~/bin/hook.py + + # execute CMD before a file rename/move + xbr: ~/bin/hook.py + + # execute CMD after a file rename/move + xar: ~/bin/hook.py + + # execute CMD before a file delete + xbd: ~/bin/hook.py + + # execute CMD after a file delete + xad: ~/bin/hook.py + + # execute CMD on message + xm: ~/bin/hook.py + + # execute CMD if someone gets banned + xban: ~/bin/hook.py + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// client and ux \\000000000000000000000000000000000000000000000000000000000000000000000000\ + + # show grid/thumbnails by default + grid + + # select files in grid by ctrl-click + gsel + + # default sort order + sort + + # natural-sort of leading digits in filenames + nsort + + # number of sort-rules to add to media URLs + hsortn + + # dont list files matching REGEX + unlist + + # includes TXT in the <head>, or @PATH for file at PATH + html_head: <script>alert(1);</script> + + # theme color (a hint for webbrowsers, discord, etc.) + tcolor: #fc0 + + # don't show total folder size + nodirsz + + # allows indexing by search engines (default) + robots + + # kindly asks search engines to leave + norobots + + # don't list read-access in controlpanel + unlistcr + + # don't list write-access in controlpanel + unlistcw + + # disable js sandbox for markdown files + no_sb_md + + # disable js sandbox for prologue/epilogue + no_sb_lg + + # enable js sandbox for markdown files (default) + sb_md + + # enable js sandbox for prologue/epilogue (default) + sb_lg + + # list of markdown-sandbox safeguards to disable + md_sbf + + # list of *logue-sandbox safeguards to disable + lg_sbf + + # value of iframe allow-prop for markdown-sandbox + md_sba + + # value of iframe allow-prop for *logue-sandbox + lg_sba + + # return html and markdown as text/html + nohtml + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// opengraph (discord embeds) \\00000000000000000000000000000000000000000000000000000000000\ + + # enable OG (disables hotlinking) + og + + # sitename; defaults to --name, disable with '-' + og_site + + # description text for all files; disable with '-' + og_desc + + # thumbnail format; j / jf / jf3 / w / w3 / ... + og_th: jf + + # audio title format; default: {{ artist }} - {{ title }} + og_title_a + + # video title format; default: {{ title }} + og_title_v + + # image title format; default: {{ title }} + og_title_i + + # fallback title if there's nothing in the db + og_title: foo + + # force default title; do not read from tags + og_s_title + + # custom html; see --og-tpl in --help + og_tpl + + # you want to add tags manually with og_tpl + og_no_head + + # if defined: only send OG html if useragent matches this regex + og_ua + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// textfiles \\0000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # where to put markdown backups; s=subfolder, v=volHist, n=nope + md_hist + + # enable textfile expansion; see --help-exp + exp + + # placeholders to expand in markdown files; see --help + exp_md + + # placeholders to expand in prologue/epilogue; see --help + exp_lg + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// tailing \\000000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # disable ?tail (download a growing file continuously) + notail + + # check if file was replaced (new fd) every 1 sec + tail_fd: 1 + + # check for new data every 0.2 sec + tail_rate: 0.2 + + # kill connection after 30 sec + tail_tmax: 30 + + # restrict ?tail access (1=admins,2=authed,3=everyone) + tail_who: 2 + + ###000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + ###// others \\0000000000000000000000000000000000000000000000000000000000000000000000000000000\ + + # allow all users with read-access to enable the option to show dotfiles in listings + dots + + # generates per-file accesskeys, which are then required at the "g" permission; keys are invalidated if filesize or inode changes + fk: 8 + + # generates slightly weaker per-file accesskeys, which are then required at the "g" permission; not affected by filesize or inode numbers + fka: 8 + + # generates per-directory accesskeys, which are then required at the "g" permission; keys are invalidated if filesize or inode changes + dk: 8 + + # per-directory accesskeys allow browsing into subdirs + dks + + # allow seeing files (not folders) inside a specific folder with "g" perm, and does not require a valid dirkey to do so + dky + + # allow '?rss' URL suffix (experimental) + rss + + # expensive analysis for mimetype accuracy + rmagic + + # restrict viewing the list of recent uploads + ups_who: 2 + + # restrict access to download-as-zip/tar + zip_who: 2 + + # reject download-as-zip if more than 9000 files + zipmaxn: 9k + + # reject download-as-zip if size over 2 GiB + zipmaxs: 2g + + # reply with 'no' if download-as-zip exceeds max + zipmaxt: no + + # zip-size-limit does not apply to authenticated users + zipmaxu + + # disable race-the-beam (download unfinished uploads) + nopipe + + # ms-windows: timeout for renaming busy files + mv_retry + + # ms-windows: timeout for deleting busy files + rm_retry + + # ask webdav clients to login for all folders + davauth + + # show lastmod time of symlink destination, not the link itself (note: this option is always enabled for recursive listings) + davrt From 00cb1f74e22dea5041c74b2389ac3087a4444041 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 20:23:39 +0000 Subject: [PATCH 31/66] golf --- copyparty/web/browser.js | 4 ++-- copyparty/web/md2.js | 6 +++--- copyparty/web/mde.js | 6 +++--- copyparty/web/shares.js | 8 +++----- copyparty/web/up2k.js | 2 +- copyparty/web/util.js | 10 +++++----- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index d7982c78..df630251 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -11957,7 +11957,7 @@ function ev_load_m3u(e) { function () { load_m3u(url); }, function () { if (has(perms, 'write') && has(perms, 'delete')) - window.location = url + '?edit'; + location = url + '?edit'; else showfile.show(url); } @@ -12556,7 +12556,7 @@ var treectl = (function () { r.reqls = function (url, hpush, back, hydrate) { if (IE && !history.pushState) - return window.location = url; + return location = url; var xhr = new XHR(), m = /[?&](k=[^&#]+)/.exec(url), diff --git a/copyparty/web/md2.js b/copyparty/web/md2.js index f7d0b59c..26b1e14b 100644 --- a/copyparty/web/md2.js +++ b/copyparty/web/md2.js @@ -255,7 +255,7 @@ function Modpoll() { } console.log('modpoll...'); - var url = (document.location + '').split('?')[0] + '?_=' + Date.now(); + var url = (location + '').split('?')[0] + '?_=' + Date.now(); var xhr = new XHR(); xhr.open('GET', url, true); xhr.responseType = 'text'; @@ -346,7 +346,7 @@ function save(e) { fd.append("lastmod", (force ? -1 : last_modified)); fd.append("body", txt); - var url = (document.location + '').split('?')[0]; + var url = (location + '').split('?')[0]; var xhr = new XHR(); xhr.open('POST', url, true); xhr.responseType = 'text'; @@ -404,7 +404,7 @@ function save_cb() { function run_savechk(lastmod, txt, btn, ntry) { // download the saved doc from the server and compare - var url = (document.location + '').split('?')[0] + '?_=' + Date.now(); + var url = (location + '').split('?')[0] + '?_=' + Date.now(); var xhr = new XHR(); xhr.open('GET', url, true); xhr.responseType = 'text'; diff --git a/copyparty/web/mde.js b/copyparty/web/mde.js index 5c2872df..058825c9 100644 --- a/copyparty/web/mde.js +++ b/copyparty/web/mde.js @@ -6,7 +6,7 @@ var dom_doc = ebi('m'); var dom_md = ebi('mt'); (function () { - var n = document.location + ''; + var n = location + ''; n = (n.slice(n.indexOf('//') + 2).split('?')[0] + '?v').split('/'); n[0] = 'top'; var loc = []; @@ -113,7 +113,7 @@ function save(mde) { fd.append("lastmod", (force ? -1 : last_modified)); fd.append("body", txt); - var url = (document.location + '').split('?')[0]; + var url = (location + '').split('?')[0]; var xhr = new XHR(); xhr.open('POST', url, true); xhr.responseType = 'text'; @@ -166,7 +166,7 @@ function save_cb() { //alert('save OK -- wrote ' + r.size + ' bytes.\n\nsha512: ' + r.sha512); // download the saved doc from the server and compare - var url = (document.location + '').split('?')[0] + '?_=' + Date.now(); + var url = (location + '').split('?')[0] + '?_=' + Date.now(); var xhr = new XHR(); xhr.open('GET', url, true); xhr.responseType = 'text'; diff --git a/copyparty/web/shares.js b/copyparty/web/shares.js index d14dfeb7..281de673 100644 --- a/copyparty/web/shares.js +++ b/copyparty/web/shares.js @@ -1,11 +1,9 @@ -var SRS = SR.trimEnd('/') + '/'; - var t = QSA('a[k]'); for (var a = 0; a < t.length; a++) t[a].onclick = rm; function rm() { - var u = SRS + '?eshare=rm&skey=' + uricom_enc(this.getAttribute('k')), + var u = SR + '/?eshare=rm&skey=' + uricom_enc(this.getAttribute('k')), xhr = new XHR(); xhr.open('POST', u, true); @@ -15,7 +13,7 @@ function rm() { function bump() { var k = this.closest('tr').getElementsByTagName('a')[2].getAttribute('k'), - u = SRS + '?skey=' + uricom_enc(k) + '&eshare=' + this.value, + u = SR + '/?skey=' + uricom_enc(k) + '&eshare=' + this.value, xhr = new XHR(); xhr.open('POST', u, true); @@ -27,7 +25,7 @@ function cb() { if (this.status !== 200) return modal.alert('<h6>server error</h6>' + esc(unpre(this.responseText))); - document.location = '?shares'; + location = '?shares'; } function qr(e) { diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 31ed1d6a..1e49fc4e 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -1572,7 +1572,7 @@ function up2k_init(subtle) { function linklist() { var ret = [], - base = document.location.origin.replace(/\/$/, ''); + base = location.origin.replace(/\/$/, ''); for (var a = 0; a < st.files.length; a++) { var t = st.files[a], diff --git a/copyparty/web/util.js b/copyparty/web/util.js index 929316e5..e58e7cca 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -120,7 +120,7 @@ function esc(txt) { function basenames(txt) { return (txt + '').replace(/https?:\/\/[^ \/]+\//g, '/').replace(/js\?_=[a-zA-Z]{4}/g, 'js'); } -if ((document.location + '').indexOf(',rej,') + 1) +if ((location + '').indexOf(',rej,') + 1) window.onunhandledrejection = function (e) { var err = e.reason; try { @@ -741,7 +741,7 @@ function assert_vp(path) { if (path.indexOf('//') + 1) throw 'nonlocal1: ' + path; - var o = window.location.origin; + var o = location.origin; if (have_URL && (new URL(path, o)).origin != o) throw 'nonlocal2: ' + path; } @@ -893,7 +893,7 @@ function uricom_adec(arr, li) { function get_evpath() { - var ret = document.location.pathname; + var ret = location.pathname; if (ret.indexOf('/') !== 0) ret = '/' + ret; @@ -1249,10 +1249,10 @@ function hist_replace(url) { function sethash(hv) { if (window.history && history.replaceState) { - hist_replace(document.location.pathname + document.location.search + '#' + hv); + hist_replace(location.pathname + location.search + '#' + hv); } else { - document.location.hash = hv; + location.hash = hv; } } From 0f55a1ae86675490fad2297770aa7c0f063bc031 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 20:24:31 +0000 Subject: [PATCH 32/66] fix js-crash for url `//`; closes #487 --- copyparty/web/browser.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index df630251..de66887e 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -6742,6 +6742,10 @@ var ACtx = !IPHONE && (window.AudioContext || window.webkitAudioContext), dk, mp; +if (location.pathname.indexOf('//') === 0) + hist_replace(location.pathname.replace(/^\/+/, '/')); + + if (window.og_fn) { hash0 = 1; hist_replace(vsplit(get_evpath())[0]); From a57f7cc2f859a4d1ed09f5ce928728f11ec3a1b8 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 20:25:29 +0000 Subject: [PATCH 33/66] ie9: recent-uploads --- copyparty/httpcli.py | 4 ++++ copyparty/web/rups.html | 9 +-------- copyparty/web/rups.js | 8 +++++--- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index d562485b..274316d5 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -5447,6 +5447,8 @@ class HttpCli(object): elif nfi == 3: if not vp.endswith(vfi): continue + else: + continue n -= 1 if not n: @@ -5571,6 +5573,8 @@ class HttpCli(object): elif nfi == 3: if not vp.endswith(vfi): continue + else: + continue if not dots and "/." in vp: continue diff --git a/copyparty/web/rups.html b/copyparty/web/rups.html index af90eefe..2cc0443a 100644 --- a/copyparty/web/rups.html +++ b/copyparty/web/rups.html @@ -19,14 +19,7 @@ <a href="{{ r }}/?h">control-panel</a>   Filter: <input type="text" id="filter" size="20" placeholder="documents/passwords" />   <span id="hits"></span> - <table id="tab"><thead><tr> - <th>size</th> - <th>who</th> - <th>when</th> - <th>age</th> - <th>dir</th> - <th>file</th> - </tr></thead><tbody id="tb"></tbody></table> + <div id="tw"></div> </div> <a href="#" id="repl">π</a> <script> diff --git a/copyparty/web/rups.js b/copyparty/web/rups.js index 9559be8c..17a44556 100644 --- a/copyparty/web/rups.js +++ b/copyparty/web/rups.js @@ -1,5 +1,6 @@ function render() { - var ups = V.ups, now = V.now, html = []; + var html = ['<table id="tab"><thead><tr><th>size</th><th>who</th><th>when</th><th>age</th><th>dir</th><th>file</th></tr></thead><tbody>']; + var ups = V.ups, now = V.now; ebi('filter').value = V.filter; ebi('hits').innerHTML = 'showing ' + ups.length + ' files'; @@ -26,7 +27,8 @@ function render() { var t = V.filter ? ' matching the filter' : ''; html = ['<tr><td colspan="6">there are no uploads' + t + '</td></tr>']; } - ebi('tb').innerHTML = html.join(''); + html.push('</tbody></table>'); + ebi('tw').innerHTML = html.join('\n'); } render(); @@ -46,7 +48,7 @@ function ask(e) { V = JSON.parse(this.responseText) } catch (ex) { - ebi('tb').innerHTML = '<tr><td colspan="6">failed to decode server response as json: <pre>' + esc(this.responseText) + '</pre></td></tr>'; + ebi('tw').innerHTML = 'failed to decode server response as json: <pre>' + esc(this.responseText) + '</pre>'; return; } render(); From 7ae84dea1a105483d5131b167ce7d5da981e16c3 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 20:30:01 +0000 Subject: [PATCH 34/66] autorefresh controlpanel --- copyparty/__main__.py | 1 + copyparty/httpcli.py | 8 ++++++++ copyparty/web/splash.html | 2 +- copyparty/web/splash.js | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 3bb8c69e..3f07bfc1 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1583,6 +1583,7 @@ def add_ui(ap, retry): ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)") ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on") ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on") + ap2.add_argument("--ctl-re", metavar="SEC", type=int, default=1, help="the controlpanel Refresh-button will autorefresh every SEC; [\033[32m0\033[0m] = just once") ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox") ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs (volflag=lg_sbf)") ap2.add_argument("--md-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for README.md docs, for example [\033[32mfullscreen\033[0m] (volflag=md_sba)") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 274316d5..b335fe4a 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -5071,6 +5071,13 @@ class HttpCli(object): self.reply(zb, mime="text/plain; charset=utf-8") return True + re_btn = "" + nre = self.args.ctl_re + if "re" in self.uparam: + self.out_headers["Refresh"] = str(nre) + elif nre: + re_btn = "&re=%s" % (nre,) + html = self.j2s( "splash", this=self, @@ -5088,6 +5095,7 @@ class HttpCli(object): mtpq=vs["mtpq"], dbwt=vs["dbwt"], url_suf=suf, + re=re_btn, k304=self.k304(), no304=self.no304(), k304vis=self.args.k304 > 0, diff --git a/copyparty/web/splash.html b/copyparty/web/splash.html index 2fdc264f..8dd56bab 100644 --- a/copyparty/web/splash.html +++ b/copyparty/web/splash.html @@ -15,7 +15,7 @@ <body> <div id="wrap"> {%- if not in_shr %} - <a id="a" href="{{ r }}/?h" class="af">refresh</a> + <a id="a" href="{{ r }}/?h{{ re }}" class="af">refresh</a> <a id="v" href="{{ r }}/?hc" class="af">connect</a> {%- if this.uname == '*' %} diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index bad3615f..d3d395af 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -385,6 +385,9 @@ if (o && /[0-9]+$/.exec(o.innerHTML)) ebi('uhash').value = '' + location.hash; +if (/\&re=/.test('' + location)) + ebi('a').className = 'af g'; + (function() { if (!ebi('x')) return; From 50f46187f112bb62b33af94539a1c3e61b98fe52 Mon Sep 17 00:00:00 2001 From: chamdim <94919340+chamdim@users.noreply.github.com> Date: Thu, 7 Aug 2025 00:00:42 +0300 Subject: [PATCH 35/66] Greek translation (#468) * Greek translation * Update browser.js * greek: fixes before merge --------- Signed-off-by: chamdim <94919340+chamdim@users.noreply.github.com> Signed-off-by: ed <s@ocv.me> Co-authored-by: ed <s@ocv.me> --- copyparty/web/browser.js | 631 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 630 insertions(+), 1 deletion(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index de66887e..60b4a349 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3152,6 +3152,635 @@ var Ls = { "lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?", }, + "grc": { + "tt": "Ελληνικά", + + "cols": { + "c": "κουμπιά ενεργειών", + "dur": "διάρκεια", + "q": "ποιότητα / bitrate", + "Ac": "κωδικοποιητής ήχου", + "Vc": "κωδικοποιητής βίντεο", + "Fmt": "μορφή / container", + "Ahash": "checksum ήχου", + "Vhash": "checksum βίντεο", + "Res": "ανάλυση", + "T": "τύπος αρχείου", + "aq": "ποιότητα ήχου / bitrate", + "vq": "ποιότητα βίντεο / bitrate", + "pixfmt": "subsampling / δομή εικονοστοιχείων", + "resw": "οριζόντια ανάλυση", + "resh": "κάθετη ανάλυση", + "chs": "κανάλια ήχου", + "hz": "συχνότητα δειγματοληψίας" + }, + + "hks": [ + [ + "διάφορα", + ["ESC", "κλείσιμο διαφόρων λειτουργιών"], + + "διαχειριστής αρχείων", + ["G", "εναλλαγή λίστας / πλέγματος"], + ["T", "εναλλαγή μικρογραφιών / εικονιδίων"], + ["⇧ A/D", "μέγεθος μικρογραφιών"], + ["ctrl-K", "διαγραφή επιλεγμένων"], + ["ctrl-X", "αποκοπή επιλογής στο πρόχειρο"], + ["ctrl-C", "αντιγραφή επιλογής στο πρόχειρο"], + ["ctrl-V", "επικόλληση (μετακίνηση/αντιγραφή) εδώ"], + ["Y", "λήψη επιλεγμένων"], + ["F2", "μετονομασία επιλεγμένων"], + + "λίστα αρχείων", + ["space", "εναλλαγή επιλογής αρχείου"], + ["↑/↓", "μετακίνηση δείκτη επιλογής"], + ["ctrl ↑/↓", "μετακίνηση δείκτη και προβολής"], + ["⇧ ↑/↓", "επιλογή προηγούμενου/επόμενου αρχείου"], + ["ctrl-A", "επιλογή όλων των αρχείων / φακέλων"] + ], [ + "πλοήγηση", + ["B", "εναλλαγή σε καρτέλες διαδρομών / δέντρο διαδρομών"], + ["I/K", "προηγούμενος/επόμενος φάκελος"], + ["M", "γονικός φάκελος (ή σμίκρυνση τρέχοντος)"], + ["V", "εναλλαγή φακέλων / δέντρο αρχείων κειμένου"], + ["A/D", "μέγεθος πίνακα πλοήγησης"] + ], [ + "μουσική", + ["J/L", "προηγούμενο/επόμενο τραγούδι"], + ["U/O", "μετάβαση 10δευτ πίσω/μπροστά"], + ["0..9", "μετάβαση στο 0%..90%"], + ["P", "αναπαραγωγή/παύση (ξεκινάει κιόλας)"], + ["S", "επιλογή αναπαραγόμενου τραγουδιού"], + ["Y", "λήψη τραγουδιού"] + ], [ + "εικόνες", + ["J/L, ←/→", "προηγούμενη/επόμενη εικόνα"], + ["Home/End", "πρώτη/τελευταία εικόνα"], + ["F", "πλήρης οθόνη"], + ["R", "περιστροφή δεξιόστροφα"], + ["⇧ R", "περιστροφή αριστερόστροφα"], + ["S", "επιλογή εικόνας"], + ["Y", "λήψη εικόνας"] + ], [ + "βίντεο", + ["U/O", "μετάβαση 10δευτ πίσω/μπροστά"], + ["P/K/Space", "αναπαραγωγή/παύση"], + ["C", "συνέχεια στο επόμενο"], + ["V", "επανάληψη"], + ["M", "σίγαση"], + ["[ και ]", "ορισμός διαστήματος επανάληψης"] + ], [ + "αρχεία κειμένου", + ["I/K", "προηγούμενο/επόμενο αρχείο"], + ["M", "κλείσιμο αρχείου"], + ["E", "επεξεργασία αρχείου"], + ["S", "επιλογή αρχείου (για αποκοπή/αντιγραφή/μετονομασία)"] + ] + ], + + "m_ok": "Εντάξει", + "m_ng": "Άκυρο", + + "enable": "Ενεργοποίηση", + "danger": "ΚΙΝΔΥΝΟΣ", + "clipped": "αντιγράφηκε στο πρόχειρο", + + "ht_s1": "δευτερόλεπτο", + "ht_s2": "δευτερόλεπτα", + "ht_m1": "λεπτό", + "ht_m2": "λεπτά", + "ht_h1": "ώρα", + "ht_h2": "ώρες", + "ht_d1": "μέρα", + "ht_d2": "μέρες", + "ht_and": " και ", + + "goh": "πίνακας ελέγχου", + "gop": 'προηγούμενος φάκελος στο ίδιο επίπεδο">προηγούμενο', + "gou": 'γονικός φάκελος">πάνω', + "gon": 'επόμενος φάκελος">επόμενο', + "logout": "Αποσύνδεση ", + "access": " πρόσβαση", + "ot_close": "κλείσιμο υπομενού", + "ot_search": "αναζήτηση αρχείων με βάση χαρακτηριστικά, διαδρομή / όνομα, μουσικά tags ή οποιονδήποτε συνδυασμό$N$N<code>foo bar</code> = πρέπει να περιέχει και τα «foo» και «bar»,$N<code>foo -bar</code> = πρέπει να περιέχει το «foo» αλλά όχι το «bar»,$N<code>^yana .opus$</code> = να ξεκινά με «yana» και να είναι αρχείο «opus»$N<code>"try unite"</code> = να περιέχει ακριβώς «try unite»$N$Nη μορφή ημερομηνίας είναι iso-8601, όπως$N<code>2009-12-31</code> ή <code>2020-09-12 23:30:00</code>", + "ot_unpost": "unpost: διαγραφή πρόσφατων μεταφορτώσεων ή ακύρωση ανολοκλήρωτων", + "ot_bup": "bup: βασικός uploader, υποστηρίζει μέχρι και netscape 4.0", + "ot_mkdir": "mkdir: δημιουργία νέου φακέλου", + "ot_md": "new-md: δημιουργία νέου markdown εγγράφου", + "ot_msg": "msg: αποστολή μηνύματος στο server log", + "ot_mp": "επιλογές media player", + "ot_cfg": "επιλογές ρυθμίσεων", + "ot_u2i": 'up2k: ανέβασε αρχεία (αν έχεις δικαίωμα εγγραφής) ή ενεργοποίησε τη λειτουργία αναζήτησης για να δεις αν υπάρχουν ήδη στο server$N$Nοι μεταφορτώσεις συνεχίζονται αν διακοπούν, είναι πολυνηματικές και διατηρούν τις χρονοσφραγίδες, αλλά καταναλώνουν περισσότερο CPU από τον [🎈]  (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!', + "ot_u2w": 'up2k: ανέβασε αρχεία με υποστήριξη συνέχισης (κλείσε τον browser και ρίξε τα ίδια αρχεία ξανά μετά)$N$Nπολυνηματικό, διατηρεί τις χρονοσφραγίδες, αλλά καταναλώνει περισσότερο CPU από τον [🎈]  (βασικός uploader)<br /><br />κατά τη διάρκεια της μεταφόρτωσης, αυτό το εικονίδιο δείχνει την πρόοδό της!', + "ot_noie": 'Χρησιμοποίησε Chrome / Firefox / Edge', + + "ab_mkdir": "δημιουργία φακέλου", + "ab_mkdoc": "νέο markdown έγγραφο", + "ab_msg": "στείλε μήνυμα στο server log", + + "ay_path": "πήγαινε σε φακέλους", + "ay_files": "πήγαινε σε αρχεία", + + "wt_ren": "μετονομασία επιλεγμένων$NΣυντόμευση: F2", + "wt_del": "διαγραφή επιλεγμένων$NΣυντόμευση: ctrl-K", + "wt_cut": "αποκοπή επιλεγμένων <small>(και επικόλληση αλλού)</small>$NΣυντόμευση: ctrl-X", + "wt_cpy": "αντιγραφή επιλεγμένων στο πρόχειρο$N(για επικόλληση αλλού)$NΣυντόμευση: ctrl-C", + "wt_pst": "επικόλληση αποκομμένων / αντεγραμμένων$NΣυντόμευση: ctrl-V", + "wt_selall": "επιλογή όλων$NΣυντόμευση: ctrl-A (με το αρχείο επιλεγμένο)", + "wt_selinv": "αντιστροφή επιλογής", + "wt_zip1": "κατέβασμα φακέλου ως συμπιεσμένο αρχείο", + "wt_selzip": "κατέβασμα επιλογής ως συμπιεσμένο αρχείο", + "wt_seldl": "κατέβασμα επιλογής ως μεμονωμένα αρχεία$NΣυντόμευση: Y", + "wt_npirc": "αντιγραφή πληροφοριών τραγουδιού σε μορφή irc", + "wt_nptxt": "αντιγραφή πληροφοριών τραγουδιού ως κείμενο", + "wt_m3ua": "προσθήκη σε m3u λίστα αναπαραγωγής (μετά πάτησε <code>📻αντιγραφή</code>)", + "wt_m3uc": "αντιγραφή m3u λίστας αναπαραγωγής στο πρόχειρο", + "wt_grid": "εναλλαγή πλέγματος / λίστας$NΣυντόμευση: G", + "wt_prev": "προηγούμενο κομμάτι$NΣυντόμευση: J", + "wt_play": "αναπαραγωγή / παύση$NΣυντόμευση: P", + "wt_next": "επόμενο κομμάτι$NΣυντόμευση: L", + + "ul_par": "παράλληλες μεταφορτώσεις:", + "ut_rand": "τυχαιοποίηση ονομάτων αρχείων", + "ut_u2ts": "αντιγραφή της τελευταίας τροποποιημένης χρονοσφραγίδας αλλαγής$Nαπό το σύστημά σου στον server\">📅", + "ut_ow": "αντικατάσταση σε ήδη υπάρχοντα αρχεία του server?$N🛡️: ποτέ (θα δημιουργηθεί νέο όνομα)$N🕒: αν το αρχείο του server είναι παλαιότερο$N♻️: πάντα να αντικαθίστανται αν διαφέρουν", + "ut_mt": "συνέχιση υπολογισμού hash για άλλα αρχεία κατά τη μεταφόρτωση$N$Nαπενεργοποίησέ το αν η CPU ή ο δίσκος σου ζορίζονται", + "ut_ask": 'επιβεβαίωση πριν ξεκινήσει η μεταφόρτωση">💭', + "ut_pot": "βελτίωση ταχύτητας μεταφόρτωσης σε αργές συσκευές$Nμε απλοποίηση του UI", + "ut_srch": "μην ανεβάζεις, έλεγξε αν τα αρχεία$Nυπάρχουν ήδη στον server (ψάχνει σε όλους τους φακέλους που έχεις πρόσβαση)", + "ut_par": "κάνε παύση στις μεταφορτώσεις βάζοντάς το 0$N$Nαύξησε το αν έχεις αργή/μεγάλη καθυστέρηση σύνδεσης$N$Nκράτα το 1 σε LAN ή αν ο server έχει αργό δίσκο", + "ul_btn": "ρίξε αρχεία / φακέλους<br>εδώ (ή κάνε κλικ σε μένα)", + "ul_btnu": "Μ Ε Τ Α Φ Ο Ρ Τ Ω Σ Η", + "ul_btns": "Α Ν Α Ζ Η Τ Η Σ Η", + + "ul_hash": "υπολογισμός hash", + "ul_send": "αποστολή", + "ul_done": "ολοκληρώθηκε", + "ul_idle1": "καμία μεταφόρτωση στην ουρά για την ώρα", + "ut_etah": "μέση ταχύτητα <em>υπολογισμού hash</em> και εκτίμηση χρόνου μέχρι την ολοκλήρωση", + "ut_etau": "μέση ταχύτητα <em>μεταφόρτωσης</em> και εκτίμηση χρόνου μέχρι την ολοκλήρωση", + "ut_etat": "μέση <em>συνολική</em> ταχύτητα και εκτίμηση χρόνου μέχρι την ολοκλήρωση", + + "uct_ok": "ολοκληρώθηκε επιτυχώς", + "uct_ng": "no-good: απέτυχε / απορρίφθηκε / δεν βρέθηκε", + "uct_done": "ολοκληρωμένα και αποτυχημένα", + "uct_bz": "κάνει hash ή μεταφορτώνει", + "uct_q": "σε αναμονή, εκκρεμεί", + + "utl_name": "όνομα αρχείου", + "utl_ulist": "λίστα", + "utl_ucopy": "αντιγραφή", + "utl_links": "σύνδεσμοι", + "utl_stat": "κατάσταση", + "utl_prog": "πρόοδος", + + // keep short: + "utl_404": "404", + "utl_err": "ΣΦΑΛΜΑ", + "utl_oserr": "ΣΦ-ΛΕ", + "utl_found": "βρέθηκε", + "utl_defer": "αναβολή", + "utl_yolo": "YOLO", + "utl_done": "έγινε", + + "ul_flagblk": "τα αρχεία προστέθηκαν στην ουρά</b><br>αλλά υπάρχει άλλη ενεργή μεταφόρτωση σε άλλη καρτέλα,<br>οπότε περίμενε να τελειώσει αυτό πρώτα", + "ul_btnlk": "ο διακομιστής έχει κλειδώσει αυτήν την επιλογή σε αυτήν την κατάσταση", + + "udt_up": "Μεταφόρτωση", + "udt_srch": "Αναζήτηση", + "udt_drop": "ρίξ' το εδώ", + + "u_nav_m": '<h6>οκ, τι έχουμε εδώ;</h6><code>Enter</code> = Αρχεία (ένα ή περισσότερα)\n<code>ESC</code> = Ένας φάκελος (μαζί με υποφακέλους)', + "u_nav_b": '<a href="#" id="modal-ok">Αρχεία</a><a href="#" id="modal-ng">Ένας φάκελος</a>', + + "cl_opts": "διακόπτες", + "cl_themes": "θέμα", + "cl_langs": "γλώσσα", + "cl_ziptype": "λήψη φακέλου", + "cl_uopts": "διακόπτες μεταφόρτωσης", + "cl_favico": "favicon", + "cl_bigdir": "μεγάλοι φάκελοι", + "cl_hsort": "#ταξινόμηση", + "cl_keytype": "σημείωση πλήκτρων", + "cl_hiddenc": "κρυφές στήλες", + "cl_hidec": "κρύψε", + "cl_reset": "επανεκκίνηση", + "cl_hpick": "πάτησε στις κεφαλίδες στηλών για να τις κρύψεις στον πίνακα παρακάτω", + "cl_hcancel": "η απόκρυψη στηλών ακυρώθηκε", + + "ct_grid": '田 το πλέγμα', + "ct_ttips": '◔ ◡ ◔">ℹ️ συμβουλές εργαλείων', + "ct_thumb": 'σε προβολή πλέγματος, εναλλαγή εικονιδίων ή μικρογραφιών$NΠλήκτρο συντόμευσης: T">🖼️ μικρογραφίες', + "ct_csel": 'χρησιμοποίησε CTRL και SHIFT για επιλογή αρχείων σε προβολή πλέγματος">επιλογή', + "ct_ihop": 'όταν η προβολή εικόνων κλείνει, κάνε scroll στο τελευταίο προβολόμενο αρχείο">g⮯', + "ct_dots": 'εμφάνιση κρυφών αρχείων (αν το επιτρέπει ο server)">dotfiles', + "ct_qdel": 'όταν διαγράφεις αρχεία, ζήτα επιβεβαίωση μόνο μία φορά">γρήγορη διαγραφή', + "ct_dir1st": 'ταξινόμηση φακέλων πριν από τα αρχεία">📁 πρώτα', + "ct_nsort": 'φυσική ταξινόμηση (για ονόματα αρχείων με αριθμούς στην αρχή)">φυσική ταξινόμηση', + "ct_utc": 'εμφάνιση όλων των ημερομηνιών σε UTC">UTC', + "ct_readme": 'εμφάνιση README.md στις λίστες φακέλων">📜 πληροφορίες', + "ct_idxh": 'εμφάνιση index.html αντί για λίστα φακέλων">html', + "ct_sbars": 'εμφάνιση μπαρών κύλισης">⟊', + + "cut_umod": "αν το αρχείο υπάρχει ήδη στον server, ενημέρωσέ το με την τελευταία χρονοσφραγίδα τροποποίησης για να ταιριάζει με το τοπικό αρχείο (απαιτεί δικαιώματα εγγραφής+διαγραφής)\">re📅", + + "cut_turbo": "το κουμπί yolo, πιθανόν να ΜΗΝ ΘΕΛΕΙΣ να το ενεργοποιήσεις:$N$Nχρησιμοποίησέ το αν μεταφορτώνεις πολλά αρχεία και χρειάστηκε να ξαναρχίσεις, και θες να συνεχίσεις τη μεταφότρωση όσο το δυνατόν πιο γρήγορα$N$Nαντικαθιστά τον έλεγχο hash με απλό <em>"έχει το ίδιο μέγεθος αρχείου στον server?"</em> οπότε αν το περιεχόμενο είναι διαφορετικό, ΔΕΝ θα ανέβει$N$Nπρέπει να το κλείσεις όταν τελειώσει η μεταφόρτωση και μετά να "μεταφορτώσεις" πάλι τα ίδια αρχεία για να τα επιβεβαιώσει το τοπικό σου πρόγραμμα\">turbo", + + "cut_datechk": "δεν επηρεάζει τίποτα εκτός αν το turbo είναι ενεργοποιημένο$N$Nμειώνει λίγο τον παράγοντα yolo; ελέγχει αν οι χρονοσφραγίδες στο διακομιστή ταιριάζουν με τα δικά σου$N$Nπιάνει <em>θεωρητικά</em> τις περισσότερες μισοτελειωμένες/κατεστραμμένες μεταφορτώσεις, αλλά δεν αντικαθιστά τον έλεγχο με το turbo απενεργοποιημένο μετέπειτα\">έλεγχος ημερομηνίας", + + "cut_u2sz": "μέγεθος (σε MiB) κάθε κομματιού μεταφόρτωσης; μεγάλες τιμές λειτουργούν καλύτερα σε μεγαλύτερες αποστάσεις διακομιστή-πελάτη. Δοκίμασε μικρές τιμές σε πολύ άστατες συνδέσεις", + + "cut_flag": "εξασφαλίζει ότι μόνο μία καρτέλα μεταφορτώνει κάθε φορά $N -- οι άλλες καρτέλες πρέπει να το έχουν κι αυτές ενεργό $N -- επηρεάζει μόνο τις καρτέλες που βρίσκονται στο ίδιο διεύθυνση", + + "cut_az": "μεταφόρτωσε τα αρχεία αλφαβητικά, αντί για το μικρότερο αρχείο, πρώτα$N$Nη αλφαβητική σειρά βοηθά να καταλάβεις αν κάτι χάλασε στο διακομιστή αλλά κάνει το ανέβασμα λίγο πιο αργό σε fiber / LAN", + + "cut_nag": "ειδοποίηση λειτουργικού συστήματος όταν τελειώσει η μεταφόρτωση$N(μόνο αν ο browser ή η καρτέλα δεν είναι ενεργά)", + "cut_sfx": "ηχητική ειδοποίηση όταν τελειώσει η μεταφόρτωση$N(μόνο αν ο browser ή η καρτέλα δεν είναι ενεργά)", + + "cut_mt": "χρησιμοποίησε multithreading για να επιταχύνεις το hashing των αρχείων$N$Nχρησιμοποιεί web-workers και χρειάζεται$Nπερισσότερη RAM (μέχρι 512 MiB επιπλέον)$N$Nκάνει το https 30% πιο γρήγορο, το http 4.5x πιο γρήγορο\">mt", + + "cut_wasm": "χρησιμοποίησε wasm αντί για τον ενσωματωμένο hasher του browser; βελτιώνει την ταχύτητα σε chrome-based browsers αλλά αυξάνει το φορτίο της CPU, και παλιές εκδόσεις chrome έχουν bugs που κάνουν το browser να τρώει όλη τη RAM και να κρασάρει αν ενεργοποιηθεί\">wasm", + + "cft_text": "κείμενο favicon (κενό και ανανέωση για απενεργοποίηση)", + "cft_fg": "χρώμα προσκηνίου", + "cft_bg": "χρώμα παρασκηνίου", + + "cdt_lim": "μέγιστος αριθμός αρχείων προς εμφάνιση σε ένα φάκελο", + "cdt_ask": "όταν φτάνεις στο τέλος,$Nαντί να φορτώσει περισσότερα αρχεία,$Nρώτα τι να κάνει", + "cdt_hsort": "πόσους κανόνες ταξινόμησης (<code>,sorthref</code>) να συμπεριλάβει σε URLs πολυμέσων. Αν το βάλεις 0 αγνοεί και κανόνες ταξινόμησης στους συνδέσμους πολυμέσων", + + "tt_entree": "εμφάνιση navpane (δέντρο διαδρομών)$NΠλήκτρο συντόμευσης: B", + "tt_detree": "εμφάνιση breadcrumbs (καρτέλες διαδρομών)$NΠλήκτρο συντόμευσης: B", + "tt_visdir": "κύλιση στον επιλεγμένο φάκελο", + "tt_ftree": "εναλλαγή δέντρου διαδρομών / αρχείων κειμένου$NΠλήκτρο συντόμευσης: V", + "tt_pdock": "εμφάνιση γονικών φακέλων σε σταθερή μπάρα επάνω", + "tt_dynt": "αυτόματη επέκταση καθώς επεκτείνεται το δέντρο διαδρομών", + "tt_wrap": "αναδίπλωση λέξεων", + "tt_hover": "αποκάλυψη των γραμμών που ξεπερνούν το πλάτος με το ποντίκι πάνω τους$N( σπάει το scroll εκτός αν το ποντίκι $N  είναι στην αριστερή στήλη )", + + "ml_pmode": "στο τέλος του φακέλου...", + "ml_btns": "εντολές", + "ml_tcode": "μετακωδικοποίηση", + "ml_tcode2": "μετακωδικοποίηση σε", + "ml_tint": "φίλτρο χρώματος", + "ml_eq": "ισοσταθμιστής ήχου", + "ml_drc": "συμπιεστής δυναμικής εμβέλειας", + + "mt_loop": "επανάληψη ενός τραγουδιού\">🔁", + "mt_one": "σταμάτα μετά από ένα τραγούδι\">1️⃣", + "mt_shuf": "τυχαία σειρά τραγουδιών σε κάθε φάκελο\">🔀", + "mt_aplay": "αυτόματη αναπαραγωγή αν υπάρχει song-ID στη διεύθυνση που μπήκες στο διακομιστή$N$Nη απενεργοποίηση αυτού, σταματά το URL από το να ενημερώνεται με τα song-ID ενώ παίζει η μουσική για να αποτραπεί η αυτόματη αναπαραγωγή αν χαθούν αυτές οι ρυθμίσεις αλλά το URL παραμείνει το ίδιο\">a▶", + "mt_preload": "ξεκίνα τη φόρτωση του επόμενου τραγουδιού κοντά στο τέλος για συνεχόμενη ακρόαση\">προφόρτωση", + "mt_prescan": "πήγαινε στον επόμενο φάκελο πριν τελειώσει το τελευταίο τραγούδι$Nγια να μη σταματήσει το πρόγραμμα περιήγησης να παίζει μουσική\">nav", + "mt_fullpre": "προσπάθησε να προφορτώσεις ολόκληρο το τραγούδι;$N✅ ενεργό σε <b>αναξιόπιστες</b> συνδέσεις,$N❌ πιθανότατα απενεργοποιημένο σε αργές συνδέσεις\">πλήρες", + "mt_fau": "σε κινητά, πρόλαβε να μην σταματήσει η μουσική αν το επόμενο τραγούδι δεν προφορτώθηκε γρήγορα (μπορεί να προκαλέσει πρόβλημα στην εμφάνιση των ετικετών)\">☕️", + "mt_waves": "γραμμή αναζήτησης κυματομορφής:$Nεμφάνιση έντασης ήχου στην μπάρα αναζήτησης\">~s", + "mt_npclip": "εμφάνισε κουμπιά για αντιγραφή του τρέχοντος τραγουδιού\">/np", + "mt_m3u_c": "εμφάνισε κουμπιά για αντιγραφή των$Nεπιλεγμένων τραγουδιών ως καταχωρήσεις λίστας m3u8\">📻", + "mt_octl": "ενσωμάτωση στο λειτουργικό σύστημα (σηντομεύσεις πλήκτρων πολυμέσων / osd)\">έλεγχος-OS", + "mt_oseek": "επιτρέπει την αναζήτηση μέσω ενσωμάτωσης του λειτουργικού συστήματος$N$Nσημείωση: σε μερικές συσκευές (iPhones),$Nαντικαθιστά το κουμπί επόμενου τραγουδιού\">αναζήτηση", + "mt_oscv": "εμφάνιση εξωφύλλου άλμπουμ σε osd\">εξώφυλλο", + "mt_follow": "κρατά το τρέχον κομμάτι ορατό κατά την κύλιση\">🎯", + "mt_compact": "συμπαγή κουμπιά ελέγχου\">⟎", + "mt_uncache": "καθάρισε την προσωρινή μνήμη  (δοκίμασε αυτό αν ο browser έχει αποθηκεύσει$Nχαλασμένο αντίγραφο τραγουδιού και αρνείται να παίξει)\">εκκαθάριση", + "mt_mloop": "τυχαία αναπαραγωγή στον ανοικτό φάκελο\">🔁 τυχαία αναπαραγωγή", + "mt_mnext": "φόρτωση επόμενου φακέλου και συνέχιση\">📂 επόμενο", + "mt_mstop": "σταμάτησε την αναπαραγωγή\">⏸ σταμάτημα", + "mt_cflac": "μετατροπή flac / wav σε opus\">flac", + "mt_caac": "μετατροπή aac / m4a σε opus\">aac", + "mt_coth": "μετατροπή όλων των άλλων (εκτός των mp3) σε opus\">άλλο", + "mt_c2opus": "καλύτερη επιλογή για desktop, laptop, android\">opus", + "mt_c2owa": "opus-weba, για iOS 17.5 και νεότερα\">owa", + "mt_c2caf": "opus-caf, για iOS 11 έως 17\">caf", + "mt_c2mp3": "χρησιμοποίησε αυτό σε πολύ παλιές συσκευές\">mp3", + "mt_c2flac": "βέλτιστη ποιότητα ήχου αλλά τεράστιο αρχείο για μεταφόρτωση\">flac", + "mt_c2wav": "ασυμπίεστη αναπαραγωγή (ακόμα μεγαλύτερο αρχείο)\">wav", + "mt_c2ok": "μια χαρά, σοφή επιλογή", + "mt_c2nd": "δεν είναι η προτεινόμενη μορφή εξόδου για τη συσκευή σου, αλλά αυτό είναι ok", + "mt_c2ng": "η συσκευή σου φαίνεται να μην υποστηρίζει αυτήν τη μορφή εξόδου, αλλά ας το δοκιμάσουμε ούτως ή άλλως", + "mt_xowa": "υπάρχουν bugs σε iOS που εμποδίζουν την αναπαραγωγή στο παρασκήνιο με αυτήν τη μορφή· χρησιμοποίησε caf ή mp3 αντ’ αυτού", + "mt_tint": "επίπεδο φόντου (0-100) στην μπάρα αναζήτησης$Nγια να κάνεις το buffering λιγότερο ενοχλητικό", + "mt_eq": "ενεργοποιεί τον ισοσταθμιστή και τον έλεγχο ενίσχυσης;$N$Nενίσχυση <code>0</code> = στάνταρ 100% ένταση (απαράλλαχτη)$N$Nεύρος <code>1  </code> = στάνταρ στερεοφωνικό (απαράλλαχτο)$Nεύρος <code>0.5</code> = 50% αριστερά-δεξιά μίξη ήχου$Nεύρος <code>0  </code> = μονοφωνικό$N$Nενίσχυση <code>-0.8</code> & εύρος <code>10</code> = αφαίρεση φωνής :^)$N$Nη ενεργοποίηση του ισοσταθμιστή κάνει τα άλμπουμ χωρίς κενά, να παίζουν χωρίς καθόλου κενά, οπότε άφησέ το ενεργό με όλες τις τιμές στο μηδέν (εκτός από εύρος = 1) αν σε νοιάζει", + "mt_drc": "ενεργοποιεί τον συμπιεστή δυναμικής εμβέλειας (εξομάλυνση έντασης / ακραία συμπίεση έντασης); θα ενεργοποιήσει και τον ισοσταθμιστή για να ισορροπήσει τον ήχο, οπότε βάλε όλα τα πεδία ισοσταθμιστή εκτός από το 'εύρος' στο 0 αν δεν το θες$N$Nχαμηλώνει την ένταση του ήχου πάνω από το όριο (THRESHOLD) dB; για κάθε RATIO dB πέρα από το όριο υπάρχει 1 dB εξόδου, οπότε οι προεπιλεγμένες τιμές όριο -24 και 'λόγος' 12 σημαίνουν ότι δεν θα ξεπεράσει ποτέ τα -22 dB και είναι ασφαλές να αυξήσεις την ενίσχυση ισοσταθμιστή σε 0.8, ή και 1.8 με ATK 0 και μεγάλο RLS όπως 90 (δουλεύει μόνο σε firefox· το RLS είναι max 1 σε άλλους browsers)$N$N(δες wikipedia, το εξηγούν καλύτερα)", + + "mb_play": "παίξε", + "mm_hashplay": "να παίξω αυτό το αρχείο ήχου;", + "mm_m3u": "πάτα <code>Enter/OK</code> για Αναπαραγωγή\nπάτα <code>ESC/Άκυρο</code> για Επεξεργασία", + "mp_breq": "χρειάζεται firefox 82+ ή chrome 73+ ή iOS 15+", + "mm_bload": "φορτώνει...", + "mm_bconv": "μετατροπή σε {0}, περίμενε...", + "mm_opusen": "ο browser σου δεν παίζει αρχεία aac / m4a;\nη μετατροπή σε opus είναι τώρα ενεργή", + "mm_playerr": "η αναπαραγωγή, απέτυχε: ", + "mm_eabrt": "Η προσπάθεια αναπαραγωγής ακυρώθηκε", + "mm_enet": "Η σύνδεση του ίντερνέτ σου είναι χάλια", + "mm_edec": "Το αρχείο αυτό είναι μάλλον κατεστραμμένο;;", + "mm_esupp": "Ο browser σου δεν καταλαβαίνει αυτή τη μορφή ήχου", + "mm_eunk": "Άγνωστο σφάλμα", + "mm_e404": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 404: Το αρχείο δεν βρέθηκε.", + "mm_e403": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 403: Άρνηση πρόσβασης.\n\nΔοκίμασε F5 για επαναφόρτωση, ίσως να έχεις αποσυνδεθεί", + "mm_e500": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα 500: Έλεγξε τα logs του διακομιστή.", + "mm_e5xx": "Αδύνατη η αναπαραγωγή ήχου; σφάλμα διακομιστή", + "mm_nof": "δεν βρέθηκαν άλλα αρχεία ήχου τριγύρω", + "mm_prescan": "Αναζήτηση μουσικής για επόμενο τραγούδι...", + "mm_scank": "Βρέθηκε το επόμενο τραγούδι:", + "mm_uncache": "κρυφή μνήμη καθαρίστηκε· όλα τα τραγούδια θα ξανακατεβούν στην επόμενη αναπαραγωγή", + "mm_hnf": "το τραγούδι αυτό πλέον δεν υπάρχει", + + "im_hnf": "η εικόνα αυτή πλέον δεν υπάρχει", + + "f_empty": "αυτός ο φάκελος είναι άδειος", + "f_chide": "αυτό θα κρύψει τη στήλη «{0}»\n\nμπορείς να εμφανίσεις τις στήλες από τις ρυθμίσεις", + "f_bigtxt": "αυτό το αρχείο είναι {0} MiB σε μέγεθος — σίγουρα θέλεις να το δεις ως κείμενο;", + "f_bigtxt2": "να δεις μόνο το τέλος του αρχείου αντί για όλο; αυτό ενεργοποιεί και το following/tailing, που δείχνει νέες γραμμές που προστίθενται ζωντανά", + "fbd_more": '<div id="blazy">εμφανίζονται <code>{0}</code> από <code>{1}</code> αρχεία; <a href="#" id="bd_more">δείξε {2}</a> ή <a href="#" id="bd_all">δείξε τα όλα</a></div>', + "fbd_all": '<div id="blazy">εμφανίζονται <code>{0}</code> από <code>{1}</code> αρχεία; <a href="#" id="bd_all">δείξε όλα</a></div>', + "f_anota": "μόνο {0} από τα {1} αντικείμενα επιλέχθηκαν;\nγια να επιλέξεις ολόκληρο το φάκελο, κύλησε πρώτα μέχρι κάτω", + + "f_dls": 'οι σύνδεσμοι αρχείων στον τρέχοντα φάκελο έχουν\nμετατραπεί σε συνδέσμους λήψης', + + "f_partial": "Για να κατεβάσεις με ασφάλεια ένα αρχείο που ανεβαίνει, κλίκαρε το αρχείο με το ίδιο όνομα, αλλά χωρίς την κατάληξη <code>.PARTIAL</code>. Πάτα Άκυρο ή Escape για να σταματήσεις.\n\nΠάτα OK / Enter αν αγνοείς την προειδοποίηση και κατέβασε το <code>.PARTIAL</code> αρχείο, που σχεδόν σίγουρα θα είναι κατεστραμμένο.", + + "ft_paste": "επικόλλησε {0} αντικείμενα$NΠλήκτρο συντόμευσης: ctrl-V", + "fr_eperm": 'δεν μπορεί να μετονομαστεί:\nδεν έχεις δικαίωμα “μετακίνησης” σε αυτόν το φάκελο', + "fd_eperm": 'δεν μπορεί να διαγραφεί:\nδεν έχεις δικαίωμα “διαγραφής” σε αυτόν το φάκελο', + "fc_eperm": 'δεν μπορεί να κοπεί:\nδεν έχεις δικαίωμα “μετακίνησης” σε αυτόν το φάκελο', + "fp_eperm": 'δεν μπορεί να επικολληθεί:\nδεν έχεις δικαίωμα “εγγραφής” σε αυτόν το φάκελο', + "fr_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για μετονομασία", + "fd_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για διαγραφή", + "fc_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για αποκοπή", + "fcp_emore": "επίλεξε τουλάχιστον ένα αντικείμενο για αντιγραφή στο πρόχειρο", + + "fs_sc": "μοιράσου το φάκελο που βρίσκεσαι", + "fs_ss": "μοιράσου τα επιλεγμένα αρχεία", + "fs_just1d": "δεν μπορείς να επιλέξεις περισσότερους από έναν φακέλους,\nή να αναμείξεις αρχεία και φακέλους στην ίδια επιλογή", + "fs_abrt": "❌ ακύρωση", + "fs_rand": "🎲 τυχαίο όνομα", + "fs_go": "✅ δημιούργησε κοινή χρήση", + "fs_name": "όνομα", + "fs_src": "πηγή", + "fs_pwd": "κωδικός", + "fs_exp": "λήξη", + "fs_tmin": "λεπτά", + "fs_thrs": "ώρες", + "fs_tdays": "ημέρες", + "fs_never": "αιώνιο", + "fs_pname": "προαιρετικό όνομα συνδέσμου; αν είναι κενό, θα είναι τυχαίο", + "fs_tsrc": "το αρχείο ή ο φάκελος προς κοινή χρήση", + "fs_ppwd": "προαιρετικός κωδικός", + "fs_w8": "δημιουργία κοινής χρήσης...", + "fs_ok": "πάτα <code>Enter/OK</code> για Πρόχειρο\nπάτα <code>ESC/Άκυρο</code> για Κλείσιμο", + + "frt_dec": "μπορεί να διορθώσει μερικές περιπτώσεις κατεστραμμένων ονομάτων αρχείων\">αποκωδικοποίηση url", + "frt_rst": "επανέφερε τα ονόματα αρχείων στα αρχικά τους\">↺ επαναφορά", + "frt_abrt": "ακύρωσε και κλείσε αυτό το παράθυρο\">❌ ακύρωση", + "frb_apply": "ΕΦΑΡΜΟΓΗ ΜΕΤΟΝΟΜΑΣΙΑΣ", + "fr_adv": "μαζική / μεταδεδομένα / μετονομασία με πρότυπα\">προχωρημένη", + "fr_case": "regex με διάκριση πεζών/κεφαλαίων\">case", + "fr_win": "ασφαλή ονόματα για windows; αντικαθιστά <code><>:"\\|?*</code> με ιαπωνικούς χαρακτήρες πλήρους πλάτους\">win", + "fr_slash": "αντικαθίσταται <code>/</code> με χαρακτήρα που δεν δημιουργεί νέους φακέλους\">όχι /", + "fr_re": "μοτίβα αναζήτησης (regex) για αναζήτηση στα αρχικά ονόματα; τα καταγραφόμενα groups μπορούν να χρησιμοποιηθούν στο πεδίο μορφοποίησης παρακάτω όπως <code>(1)</code> και <code>(2)</code> και ούτω καθεξής", + "fr_fmt": "εμπνευσμένο από foobar2000:$N<code>(title)</code> αντικαθίσταται από τίτλο τραγουδιού,$N<code>[(artist) - ](title)</code> παραλείπει το [this] αν το artist είναι κενό$N<code>$lpad((tn),2,0)</code> γεμίζει τον αριθμό κομματιού σε 2 ψηφία", + "fr_pdel": "διαγραφή", + "fr_pnew": "αποθήκευση ως", + "fr_pname": "δώσε όνομα για τη νέα προεπιλογή", + "fr_aborted": "ακυρώθηκε", + "fr_lold": "παλιό όνομα", + "fr_lnew": "νέο όνομα", + "fr_tags": "ετικέτες για τα επιλεγμένα αρχεία (μόνο για ανάγνωση):", + "fr_busy": "μετονομασία {0} αντικειμένων...\n\n{1}", + "fr_efail": "αποτυχία μετονομασίας:\n", + "fr_nchg": "{0} από τα νέα ονόματα άλλαξαν λόγω <code>win</code> και/ή <code>όχι /</code>\n\nΕίναι ΟΚ να συνεχίσουμε με αυτά τα ονόματα;", + + "fd_ok": "διαγραφή OK", + "fd_err": "αποτυχία διαγραφής:\n", + "fd_none": "δεν διαγράφηκε τίποτα; ίσως μπλοκαρισμένο από τις ρυθμίσεις του διακομιστή (xbd);", + "fd_busy": "διαγραφή {0} αντικειμένων...\n\n{1}", + "fd_warn1": "ΔΙΑΓΡΑΦΗ αυτών των {0} αντικειμένων;", + "fd_warn2": "<b>Τελευταία ευκαιρία!</b> Δεν υπάρχει αναίρεση. Διαγραφή;", + + "fc_ok": "αποκοπή {0} αντικειμένων", + "fc_warn": 'αποκοπή {0} αντικειμένων\n\nαλλά: μόνο <b>αυτή</b> η καρτέλα browser μπορεί να τα επικολλήσει\n(λόγω πολύ μεγάλης επιλογής)', + + "fcc_ok": "αντιγράφηκαν {0} αντικείμενα στο πρόχειρο", + "fcc_warn": "αντιγράφηκαν {0} αντικείμενα στο πρόχειρο\n\nαλλά: μόνο <b>αυτή</b> η καρτέλα browser μπορεί να τα επικολλήσει\n(λόγω πολύ μεγάλης επιλογής)", + + "fp_apply": "χρησιμοποίησε αυτά τα ονόματα", + "fp_ecut": "πρώτα κάνε αποκοπή ή αντιγραφή κάποιων αρχείων / φακέλων για επικόλληση / μετακίνηση\n\nσημείωση: μπορείς να αποκόπτεις / επικολλάς ανάμεσα σε διαφορετικές καρτέλες browser", + "fp_ename": "τα {0} αντικείμενα δεν μπορούν να μετακινηθούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό για να τα αγνοήσεις:", + "fcp_ename": "τα {0} αντικείμενα δεν μπορούν να αντιγραφούν εδώ γιατί τα ονόματα υπάρχουν ήδη. Δώσε νέα ονόματα παρακάτω για να συνεχίσεις, ή άφησε κενό για να τα αγνοήσεις:", + "fp_emore": "υπάρχουν ακόμα συγκρούσεις ονομάτων που πρέπει να διορθωθούν", + "fp_ok": "μετακίνηση OK", + "fcp_ok": "αντιγραφή OK", + "fp_busy": "μετακίνηση {0} αντικειμένων...\n\n{1}", + "fcp_busy": "αντιγραφή {0} αντικειμένων...\n\n{1}", + "fp_err": "αποτυχία μετακίνησης:\n", + "fcp_err": "αποτυχία αντιγραφής:\n", + "fp_confirm": "να μετακινηθούν αυτά τα {0} αντικείμενα εδώ;", + "fcp_confirm": "να αντιγραφούν αυτά τα {0} αντικείμενα εδώ;", + "fp_etab": "αποτυχία ανάγνωσης πρόχειρου από άλλη καρτέλα browser", + "fp_name": "μεταφόρτωση αρχείου από τη συσκευή σου. Δώσε του όνομα:", + "fp_both_m": '<h6>διάλεξε τι θα επικολλήσεις</h6><code>Enter</code> = Μετακίνηση {0} αρχείων από «{1}»\n<code>ESC</code> = Μεταφόρτωση {2} αρχείων από τη συσκευή σου', + "fcp_both_m": '<h6>διάλεξε τι θα επικολλήσεις</h6><code>Enter</code> = Αντιγραφή {0} αρχείων από «{1}»\n<code>ESC</code> = Μεταφόρτωση {2} αρχείων από τη συσκευή σου', + "fp_both_b": '<a href="#" id="modal-ok">Μετακίνηση</a><a href="#" id="modal-ng">Μεταφόρτωση</a>', + "fcp_both_b": '<a href="#" id="modal-ok">Αντιγραφή</a><a href="#" id="modal-ng">Μεταφόρτωση</a>', + + "mk_noname": "γράψε ένα όνομα στο πεδίο κειμένου αριστερά πριν το κάνεις :p", + + "tv_load": "Φόρτωση αρχείου κειμένου:\n\n{0}\n\n{1}% ({2} από {3} MiB φορτωμένα)", + "tv_xe1": "αδυναμία φόρτωσης αρχείου κειμένου:\n\nσφάλμα ", + "tv_xe2": "404, αρχείο δεν βρέθηκε", + "tv_lst": "λίστα αρχείων κειμένου σε", + "tvt_close": "επιστροφή στην προβολή φακέλου$NΣυντόμευση: M (ή Esc)\">❌ κλείσιμο", + "tvt_dl": "κατέβασε αυτό το αρχείο$NΣυντόμευση: Y\">💾 λήψη", + "tvt_prev": "προβολή προηγούμενου εγγράφου$NΣυντόμευση: i\">⬆ προηγούμενο", + "tvt_next": "προβολή επόμενου εγγράφου$NΣυντόμευση: K\">⬇ επόμενο", + "tvt_sel": "επέλεξε αρχείο   (για αποκοπή / αντιγραφή / διαγραφή / ...)$NΣυντόμευση: S\">επιλογή", + "tvt_edit": "άνοιγμα αρχείου στον επεξεργαστή κειμένου$NΣυντόμευση: E\">✏️ επεξεργασία", + "tvt_tail": "παρακολούθηση αρχείου για αλλαγές; εμφάνιση νέων γραμμών σε πραγματικό χρόνο\">📡 παρακολούθηση", + "tvt_wrap": "αναδίπλωση λέξεων\">↵", + "tvt_atail": "κλείδωμα κύλισης στο κάτω μέρος\">⚓", + "tvt_ctail": "αποκωδικοποίηση χρωμάτων τερματικού (ansi escape codes)\">🌈", + "tvt_ntail": "όριο κύλισης (πόσα bytes κειμένου να κρατούνται φορτωμένα)", + + "m3u_add1": "το τραγούδι προστέθηκε στη λίστα m3u", + "m3u_addn": "προστέθηκαν {0} τραγούδια στη λίστα m3u", + "m3u_clip": "η λίστα m3u αντιγράφηκε στο πρόχειρο\n\nπρέπει να φτιάξεις ένα νέο αρχείο κειμένου με όνομα η_λίστα_μου.m3u και να επικολλήσεις τη λίστα μέσα· αυτό θα το καταστήσει αναπαράξιμο", + + "gt_vau": "μην δείχνεις το βίντεο, παίξε μόνο τον ήχο\">🎧", + "gt_msel": "ενεργοποίηση επιλογής αρχείων; ctrl-κλικ σε αρχείο για παράκαμψη$N$N<em>όταν είναι ενεργό: διπλό κλικ σε αρχείο / φάκελο το ανοίγει</em>$N$NΣυντόμευση: S\">πολλαπλή επιλογή", + "gt_crop": "κεντραρισμένη περικοπή μικρογραφιών\">περικοπή", + "gt_3x": "μικρογραφίες υψηλής ανάλυσης\">3x", + "gt_zoom": "ζουμ", + "gt_chop": "κόψε", + "gt_sort": "ταξινόμηση κατά", + "gt_name": "όνομα", + "gt_sz": "μέγεθος", + "gt_ts": "ημερομηνία", + "gt_ext": "τύπος", + "gt_c1": "μεγαλύτερη περικοπή ονομάτων αρχείων (δείξε λιγότερα)", + "gt_c2": "μικρότερη περικοπή ονομάτων αρχείων (δείξε περισσότερα)", + + "sm_w8": "αναζήτηση...", + "sm_prev": "τα παρακάτω αποτελέσματα αναζήτησης προέρχονται από προηγούμενη αναζήτηση:\n ", + "sl_close": "κλείσιμο αποτελεσμάτων αναζήτησης", + "sl_hits": "εμφανίζονται {0} αποτελέσματα", + "sl_moar": "φόρτωσε περισσότερα", + + "s_sz": "μέγεθος", + "s_dt": "ημερομηνία", + "s_rd": "μονοπάτι", + "s_fn": "όνομα", + "s_ta": "ετικέτες", + "s_ua": "ανέβηκε@", + "s_ad": "προχωρ.", + "s_s1": "ελάχιστο σε MiB", + "s_s2": "μέγιστο σε MiB", + "s_d1": "ελάχιστο iso8601", + "s_d2": "μέγιστο iso8601", + "s_u1": "μεταφορτώθηκε αργότερα", + "s_u2": "και/ή πριν", + "s_r1": "το μονοπάτι περιέχει   (χωρισμένα με κενό)", + "s_f1": "το όνομα περιέχει   (άρνηση με -nope)", + "s_t1": "οι ετικέτες περιέχουν   (^=αρχή, τέλος=$)", + "s_a1": "συγκεκριμένες ιδιότητες μεταδεδομένων", + + "md_eshow": "δεν μπορεί να εμφανιστεί ", + "md_off": "[📜<em>readme</em>] απενεργοποιημένο στο [⚙️] -- κρυμμένο έγγραφο", + + "badreply": "Αποτυχία ανάλυσης απάντησης από το διακομιστή", + + "xhr403": "403: Πρόσβαση αρνήθηκε\n\nδοκίμασε το F5, ίσως αποσυνδέθηκες", + "xhr0": "άγνωστο (πιθανόν αποσύνδεση από το διακομιστή ή ο διακομιστής είναι εκτός σύνδεσης)", + "cf_ok": "συγγνώμη γι' αυτό -- η προστασία DD" + wah + "oS ενεργοποιήθηκε\n\nοι διαδικασίες θα συνεχιστούν σε περίπου 30 δευτερόλεπτα\n\nαν δεν γίνει τίποτα, πάτα F5 για επαναφόρτωση", + "tl_xe1": "αδύνατη η λίστα υποφακέλων:\n\nσφάλμα ", + "tl_xe2": "404: Ο φάκελος δεν βρέθηκε", + "fl_xe1": "αδύνατη η λίστα αρχείων σε φάκελο:\n\nσφάλμα ", + "fl_xe2": "404: Ο φάκελος δεν βρέθηκε", + "fd_xe1": "αδύνατη η δημιουργία υποφακέλου:\n\nσφάλμα ", + "fd_xe2": "404: Ο γονικός φάκελος δεν βρέθηκε", + "fsm_xe1": "αδύνατη η αποστολή μηνύματος:\n\nσφάλμα ", + "fsm_xe2": "404: Ο γονικός φάκελος δεν βρέθηκε", + "fu_xe1": "αποτυχία φόρτωσης λίστας unpost από το διακομιστή:\n\nσφάλμα ", + "fu_xe2": "404: Το αρχείο δεν βρέθηκε??", + + "fz_tar": "μη συμπιεσμένο αρχείο gnu-tar (linux / mac)", + "fz_pax": "μη συμπιεσμένο pax-format tar (πιο αργό)", + "fz_targz": "gnu-tar με συμπίεση gzip επίπεδο 3$N$Nσυνήθως πολύ αργό, οπότε$Nχρησιμοποίησε καλύτερα μη συμπιεσμένο tar", + "fz_tarxz": "gnu-tar με συμπίεση xz επίπεδο 1$N$Nσυνήθως πολύ αργό, οπότε$Nχρησιμοποίησε καλύτερα μη συμπιεσμένο tar", + "fz_zip8": "zip με ονόματα αρχείων utf8 (ίσως να κολλάει σε windows 7 και παλιότερα)", + "fz_zipd": "zip με παραδοσιακά ονόματα cp437, για πολύ παλιό λογισμικό", + "fz_zipc": "cp437 με crc32 υπολογισμένο νωρίτερα,$Nγια MS-DOS PKZIP v2.04g (οκτώβριος 1993)$N(παίρνει παραπάνω χρόνο πριν ξεκινήσει η μεταφόρτωση)", + + "un_m1": "μπορείς να διαγράψεις τα πρόσφατα αρχεία που μεταφόρτωσες (ή να ακυρώσεις τα μισοτελειωμένα) παρακάτω", + "un_upd": "ανανέωση", + "un_m4": "ή μοιράσου τα αρχεία που βλέπεις παρακάτω:", + "un_ulist": "εμφάνιση", + "un_ucopy": "αντιγραφή", + "un_flt": "προαιρετικό φίλτρο:  η διεύθυνση πρέπει να περιέχει", + "un_fclr": "καθαρισμός φίλτρου", + "un_derr": "αποτυχία διαγραφής unpost:\n", + "un_f5": "κάτι χάλασε, δοκίμασε την ανανέωση ή πάτα F5", + "un_uf5": "συγγνώμη αλλά πρέπει να ανανεώσεις τη σελίδα (πχ με F5 ή CTRL-R) πριν ακυρώσεις αυτήν την αποστολή", + "un_nou": "<b>προσοχή:</b> ο διακομιστής είναι πολύ φορτωμένος για να δείξει μισοτελειωμένες αποστολές· πάτα την ανανέωση, σε λίγο", + "un_noc": "<b>προσοχή:</b> το unpost των ολοκληρωμένων αρχείων δεν επιτρέπεται από τη ρύθμιση του διακομιστή", + "un_max": "εμφανίζονται τα πρώτα 2000 αρχεία (χρησιμοποίησε φίλτρο)", + "un_avail": "μπορείς να διαγράψεις {0} πρόσφατα αρχεία<br />μπορείς να ακυρώσεις {1} μισοτελειωμένες αποστολές", + "un_m2": "ταξινομημένα κατά χρόνο μεταφόρτωσης; τα πιο πρόσφατα πρώτα:", + "un_no1": "άκυρο! καμία μεταφόρτωση δεν είναι αρκετά πρόσφατη", + "un_no2": "άκυρο! καμία μεταφόρτωση με αυτό το φίλτρο δεν είναι αρκετά πρόσφατη", + "un_next": "διάγραψε τα επόμενα {0} αρχεία παρακάτω", + "un_abrt": "άκυρο", + "un_del": "διαγραφή", + "un_m3": "φορτώνω τις πρόσφατες μεταφορτώσεις σου...", + "un_busy": "διαγράφω {0} αρχεία...", + "un_clip": "αντιγράφηκαν {0} σύνδεσμοι στο πρόχειρο", + + "u_https1": "πρέπει", + "u_https2": "μετάβαση σε https", + "u_https3": "για καλύτερη απόδοση", + "u_ancient": 'ο browser σου είναι εντυπωσιακά απαρχαιωμένος — ίσως να <a href="#" onclick="goto(\'bup\')">χρησιμοποιήσεις το bup αντί γι\' αυτό</a>', + "u_nowork": "χρειάζεται firefox 53+ ή chrome 57+ ή iOS 11+", + "tail_2old": "χρειάζεται firefox 105+ ή chrome 71+ ή iOS 14.5+", + "u_nodrop": "ο browser σου είναι πολύ παλιός για drag&drop μεταφορτώσεις", + "u_notdir": "αυτός δεν είναι φάκελος!\n\nο browser σου είναι πολύ παλιός,\nδοκίμασε drag&drop αντ' αυτού", + "u_uri": "για να κάνεις drag&drop εικόνων από άλλα παράθυρα browser,\nρίξ' τες πάνω στο μεγάλο κουμπί μεταφόρτωσης", + "u_enpot": 'άλλαξε στο <a href="#">potato UI</a> (ίσως ανεβάζει πιο γρήγορα)', + "u_depot": 'άλλαξε στο <a href="#">fancy UI</a> (ίσως ανεβάζει πιο αργά)', + "u_gotpot": "αλλάζω στο potato UI για πιο γρήγορη μεταφόρτωση,\n\nμπορείς να το αλλάξεις πάλι αν θες!", + "u_pott": "<p>αρχεία:   <b>{0}</b> ολοκληρωμένα,   <b>{1}</b> αποτυχημένα,   <b>{2}</b> σε εξέλιξη,   <b>{3}</b> σε ουρά</p>", + "u_ever": "αυτός είναι ο βασικός uploader; το up2k θέλει τουλάχιστον<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1", + "u_su2k": 'αυτός είναι ο βασικός uploader; το <a href="#" id="u2yea">up2k</a> είναι καλύτερο', + "u_uput": "βελτιστοποίηση για ταχύτητα (παράλειψη ελέγχου ακεραιότητας)", + "u_ewrite": "δεν έχεις δικαίωμα εγγραφής σε αυτόν τον φάκελο", + "u_eread": "δεν έχεις δικαίωμα ανάγνωσης σε αυτόν τον φάκελο", + "u_enoi": "η αναζήτηση αρχείων δεν είναι ενεργοποιημένη στο αρχείο ρυθμίσεων του διακομιστή", + "u_enoow": "δεν μπορείς να κάνεις αντικατάσταση εδώ· χρειάζεται δικαίωμα Διαγραφής", + "u_badf": "Αυτά τα {0} αρχεία (από {1} συνολικά) παραλείφθηκαν, πιθανώς λόγω δικαιωμάτων συστήματος αρχείων:\n\n", + "u_blankf": "Αυτά τα {0} αρχεία (από {1} συνολικά) είναι άδεια / κενά· να τα μεταφορτώσω έτσι κι αλλιώς;\n\n", + "u_applef": "Αυτά τα {0} αρχεία (από {1} συνολικά) πιθανώς δεν είναι επιθυμητά;\nΠάτα <code>OK/Enter</code> για ΝΑ ΑΓΝΟΗΘΟΥΝ τα παρακάτω αρχεία,\nΠάτα <code>Cancel/ESC</code> για ΝΑ ΜΗΝ ΑΠΟΚΛΕΙΣΤΟΥΝ και να ΜΕΤΑΦΟΡΤΩΘΟΎΝ κι αυτά:\n\n", + "u_just1": "\nΊσως δουλέψει καλύτερα αν επιλέξεις μόνο ένα αρχείο", + "u_ff_many": "αν χρησιμοποιείς <b>Linux / MacOS / Android,</b> τότε τόσα αρχεία <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1790500\" target=\"_blank\"><em>μπορεί</em> να κατάρρευση του Firefox!</a>\nαν γίνει αυτό, δοκίμασε ξανά (ή χρησιμοποίησε τον Chrome).", + "u_up_life": "Αυτή η μεταφόρτωση θα διαγραφεί από το διακομιστή\n{0} μετά την ολοκλήρωσή της", + "u_asku": "μεταφόρτωση αυτών των {0} αρχείων στο <code>{1}</code>", + "u_unpt": "μπορείς να αναιρέσεις / διαγράψεις αυτήν τη μεταφόρτωση χρησιμοποιώντας το 🧯, πάνω αριστερά", + "u_bigtab": "θα εμφανιστούν {0} αρχεία\n\nαυτό μπορεί να κάνει τον browser σου να κολλήσει, είσαι σίγουρος;", + "u_scan": "Σάρωση αρχείων...", + "u_dirstuck": "ο επεξεργαστής φακέλων κόλλησε προσπαθώντας να προσπελάσει τα εξής {0} αντικείμενα· θα τα παραλείψει:", + "u_etadone": "Ολοκληρώθηκε ({0}, {1} αρχεία)", + "u_etaprep": "(προετοιμασία για μεταφόρτωση)", + "u_hashdone": "το hashing ολοκληρώθηκε", + "u_hashing": "υπολογισμός hash", + "u_hs": "handshaking...", + "u_started": "τα αρχεία ανεβαίνουν τώρα· δες τα στο [🚀]", + "u_dupdefer": "διπλότυπο; θα επεξεργαστεί μετά από όλα τα άλλα αρχεία", + "u_actx": "πάτα αυτό το κείμενο για να μην χάσεις<br />απόδοση όταν αλλάζεις παράθυρα/καρτέλες", + "u_fixed": "ΟΚ!  Το διόρθωσα 👍", + "u_cuerr": "αποτυχία μεταφόρτωσης τμήματοςς {0} από {1};\nπιθανώς ακίνδυνο, συνεχίζω\n\nαρχείο: {2}", + "u_cuerr2": "ο διακομιστής απέρριψε τη μεταφόρτωση (τμήμα {0} από {1});\nθα ξαναδοκιμάσει αργότερα\n\nαρχείο: {2}\n\nσφάλμα ", + "u_ehstmp": "θα ξαναδοκιμάσει; δες κάτω δεξιά", + "u_ehsfin": "ο διακομιστής απέρριψε το αίτημα ολοκλήρωσης της μεταφόρτωσης; ξαναδοκιμάζει...", + "u_ehssrch": "ο διακομιστής απέρριψε το αίτημα αναζήτησης; ξαναδοκιμάζει...", + "u_ehsinit": "ο διακομιστής απέρριψε το αίτημα για εκκίνηση μεταφόρτωσης; ξαναδοκιμάζει...", + "u_eneths": "σφάλμα δικτύου κατά το handshake μεταφόρτωσης; ξαναδοκιμάζει...", + "u_enethd": "σφάλμα δικτύου κατά τον έλεγχο ύπαρξης στόχου; ξαναδοκιμάζει...", + "u_cbusy": "ο διακομιστής περιμένει να μας εμπιστευτεί ξανά μετά από πρόβλημα δικτύου...", + "u_ehsdf": "ο διακομιστής έμεινε από χώρο στο δίσκο!\n\nθα συνεχίσει να ξαναδοκιμάζει,\nσε περίπτωση που κάποιος\nελευθερώσει αρκετό χώρο για συνέχεια", + "u_emtleak1": "φαίνεται πως ο browser σου έχει διαρροή μνήμης;\nπαρακαλώ", + "u_emtleak2": ' <a href="{0}">αλλαγή σε https (συνιστάται)</a> ή ', + "u_emtleak3": ' ', + "u_emtleakc": 'δοκίμασε τα εξής:\n<ul><li>πάτα <code>F5</code> για ανανέωση σελίδας</li><li>μετά απενεργοποίησε το  <code>mt</code>  κουμπί στις  <code>⚙️ ρυθμίσεις</code></li><li>και δοκίμασε ξανά τη μεταφόρτωση</li></ul>Οι μεταφορτώσιες θα είναι λίγο πιο αργές, αλλά ok.\nΣυγγνώμη για την ταλαιπωρία!\n\nPS: το chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">έχει διόρθωση γι\' αυτό</a>', + "u_emtleakf": 'δοκίμασε τα εξής:\n<ul><li>πάτα <code>F5</code> για ανανέωση σελίδας</li><li>μετά άνοιξε το <code>🥔</code> (potato) στο UI μεταφόρτωσης<li>και δοκίμασε ξανά τη μεταφόρτωση</li></ul>\nPS: ο firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">ελπίζει να φτιάξει αυτό το bug</a> κάποια στιγμή', + "u_s404": "δεν βρέθηκε στο διακομιστή", + "u_expl": "επεξήγηση", + "u_maxconn": "οι περισσότεροι browser το περιορίζουν στα 6, αλλά ο firefox σου επιτρέπει να το αυξήσεις με <code>connections-per-server</code> στο <code>about:config</code>", + "u_tu": '<p class="warn">ΠΡΟΕΙΔΟΠΟΙΗΣΗ: το turbo είναι ενεργοποιημένο, <span> το πρόγραμμα πελάτη ίσως να μην ανιχνεύσει και να μην ξαναεκκινήσει μισοτελειωμένες μεταφορτώσεις; δες τα tooltip του κουμπιού turbo</span></p>', + "u_ts": '<p class="warn">ΠΡΟΕΙΔΟΠΟΙΗΣΗ: το turbo είναι ενεργοποιημένο, <span> τα αποτελέσματα αναζήτησης μπορεί να είναι λάθος; δες τα tooltip του κουμπιού turbo</span></p>', + "u_turbo_c": "το turbo είναι απενεργοποιημένο στο αρχείο ρυθμίσεων του διακομιστή", + "u_turbo_g": "απενεργοποιώ το turbo επειδή δεν έχεις δικαίωμα\nγια τη λίστα φακέλων σε αυτόν τον τόμο", + "u_life_cfg": 'αυτόματη διαγραφή μετά από <input id="lifem" p="60" /> λεπτά (ή <input id="lifeh" p="3600" /> ώρες)', + "u_life_est": 'η μεταφόρτωση θα διαγραφεί <span id="lifew" tt="τοπική ώρα">---</span>', + "u_life_max": 'αυτός ο φάκελος επιβάλλει\nμέγιστη διάρκεια ζωής {0}', + "u_unp_ok": "επιτρέπεται το unpost για {0}", + "u_unp_ng": "δεν επιτρέπεται το unpost", + "ue_ro": "έχεις μόνο δικαίωμα ανάγνωσης σε αυτόν το φάκελο\n\n", + "ue_nl": "δεν είσαι συνδεδεμένος τώρα", + "ue_la": 'είσαι συνδεδεμένος ως "{0}"', + "ue_sr": "είσαι σε λειτουργία αναζήτησης αρχείων\n\nπήγαινε σε λειτουργία μεταφόρτωσης πατώντας το 🔎 (δίπλα στο μεγάλο κουμπί ΑΝΑΖΗΤΗΣΗΣ) και δοκίμασε πάλι\n\nσυγγνώμη", + "ue_ta": "δοκίμασε να μεταφορτώσεις εκ νέου, θα πρέπει να δουλέψει τώρα", + "ue_ab": "αυτό το αρχείο ανεβαίνει σε άλλο φάκελο και η μεταφόρτωση πρέπει να ολοκληρωθεί πριν ανέβει αλλού.\n\nΜπορείς να ακυρώσεις και να ξεχάσεις την αρχική μεταφόρτωση με το κουμπί 🧯 πάνω αριστερά", + "ur_1uo": "ΟΚ: Το αρχείο ανέβηκε επιτυχώς", + "ur_auo": "ΟΚ: Και τα {0} αρχεία ανέβηκαν επιτυχώς", + "ur_1so": "ΟΚ: Το αρχείο βρέθηκε στο διακομιστή", + "ur_aso": "ΟΚ: Και τα {0} αρχεία βρέθηκαν στο διακομιστή", + "ur_1un": "Η μεταφόρτωση απέτυχε, συγγνώμη", + "ur_aun": "Και οι {0} μεταφορτώσεις απέτυχαν, συγγνώμη", + "ur_1sn": "Το αρχείο ΔΕΝ βρέθηκε στο διακομιστή", + "ur_asn": "Τα {0} αρχεία ΔΕΝ βρέθηκαν στο διακομιστή", + "ur_um": "Ολοκληρώθηκε;\n{0} μεταφορτώσεις είναι OK,\n{1} μεταφορτώσεις απέτυχαν, συγγνώμη", + "ur_sm": "Ολοκληρώθηκε;\n{0} αρχεία βρέθηκαν στο διακομιστή,\n{1} αρχεία ΔΕΝ βρέθηκαν στο διακομιστή", + + "lang_set": "ανανέωση σελίδας για εφαρμογή της αλλαγής;" + }, "ita": { "tt": "Italiano", @@ -6298,7 +6927,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "deu", "fin", "ita", "nld", "rus", "spa", "ukr"]; +var LANGS = ["eng", "nor", "chi", "deu", "fin", "ita", "nld", "rus", "spa", "ukr", "grc"]; if (window.langmod) langmod(); From 392abd0675bfb13f6b74cb7918a39842bfe95475 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 21:02:25 +0000 Subject: [PATCH 36/66] add greek splash tl; closes #493 --- copyparty/web/splash.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index d3d395af..14865781 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -177,6 +177,47 @@ var Ls = { "af1": "näytä viimeaikaiset lataukset", "ag1": "näytä tunnetut IdP-käyttäjät", }, + "grc": { + "a1": "ανανέωση", + "b1": "γεια σου ξένε!   <small>(δεν είσαι συνδεδεμένος)</small>", + "c1": "αποσύνδεση", + "d1": "σωρός απορριμμάτων", + "d2": "εμφανίζει την κατάσταση όλων των ενεργών διεργασιών", + "e1": "επαναφόρτωση του cfg", + "e2": "φορτώνει ξανά τα αρχεία ρυθμίσεων (λογαριασμοί/τόμοι/volflags),$Nκαι κάνει επανεξέταση όλων των τόμων e2ds$N$Nσημείωση: οποιαδήποτε αλλαγή στις καθολικές ρυθμίσεις$Nαπαιτεί πλήρη επανεκκίνηση για να εφαρμοστεί", + "f1": "μπορείς να περιηγηθείς:", + "g1": "μπορείς να εκτελέσεις μεταφόρτωση σε:", + "cc1": "άλλα πράγματα:", + "h1": "απενεργοποίση k304", + "i1": "ενεργοποίηση k304", + "j1": "η ενεργοποίηση του k304 θα αποσυνδέσει το πρόγραμμα πελάτη σου σε κάθε HTTP 304, κάτι που μπορεί να αποτρέψει κάποια προβληματικά proxies από το να κολλάνε (να μην φορτώνουν ξαφνικά σελίδες), <em>αλλά</em> θα κάνει τα πράγματα, γενικά πιο αργά", + "k1": "επαναφορά ρυθμίσεων στο πρόγραμμα πελάτη", + "l1": "συνδέσου για περισσότερα:", + "m1": "καλώς ήρθες,", + "n1": "404 δεν βρέθηκε  ┐( ´ -`)┌", + "o1": '´η μήπως δεν έχεις πρόσβαση -- δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>', + "p1": "403 απαγορευμένο  ~┻━┻", + "q1": 'δοκίμασε έναν κωδικό <a href="' + SR + '/?h">πήγαινε στην αρχική</a>', + "r1": "πίσω στην αρχική", + ".s1": "επανάληψη σάρωσης", + "t1": "ενέργεια", + "u2": "χρόνος από την τελευταία εγγραφή του διακομιστή$N( μεταφόρτωση / μετονομασία / ... )$N$N17d = 17 days$N1ω23 = 1 ώρα 23 λεπτά$N4λ56 = 4 λεπτά 56 δευτερόλεπτα", + "v1": "σύνδεση", + "v2": "χρησιμοποίησε αυτόν το διακομιστή σαν τοπικό δίσκο", + "w1": "εναλλαγή σε https", + "x1": "αλλαγή κωδικού", + "y1": "επεξεργασία κοινόχρηστων φακέλων", + "z1": "ξεκλείδωμα αυτού του κοινόχρηστου φακέλου:", + "ta1": "συμπλήρωσε πρώτα το νέο σου κωδικό", + "ta2": "επανέλαβε για να επιβεβαιώσεις το νέο κωδικό:", + "ta3": "βρέθηκε τυπογραφικό λάθος· δοκίμασε ξανά", + "aa1": "εισερχόμενα αρχεία:", + "ab1": "απενεργοποίηση no304", + "ac1": "ενεργοποίηση no304", + "ad1": "η ενεργοποίηση του no304 θα απενεργοποιήσει όλη την προσωρινή αποθήκευση· δοκίμασέ το αν το k304 δεν ήταν αρκετό. Προσοχή, θα σπαταλήσει τεράστιο όγκο δικτυακής κίνησης!", + "ae1": "ενεργές μεταφορτώσεις:", + "af1": "προβολή πρόσφατων μεταφορτώσεων", + }, "ita": { "a1": "aggiorna", "b1": "ciao   <small>(non sei connesso)</small>", From 3b26884c691dc23f473e09107ad7f41a4a248fbe Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 21:08:11 +0000 Subject: [PATCH 37/66] tl cleanup --- copyparty/web/browser.js | 2 +- copyparty/web/splash.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 60b4a349..9c20c5d8 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -6927,7 +6927,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "deu", "fin", "ita", "nld", "rus", "spa", "ukr", "grc"]; +var LANGS = ["eng", "nor", "chi", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"]; if (window.langmod) langmod(); diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 14865781..1a24beb2 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -174,7 +174,7 @@ var Ls = { "ac1": "ota no304 käyttöön", "ad1": "no304:n lopettaa välimuistin käytön kokonaan; kokeile tätä jos k304 ei riittänyt. Tuhlaa valtavan määrän verkkoliikennettä!", "ae1": "lähtevät:", - "af1": "näytä viimeaikaiset lataukset", + "af1": "näytä viimeaikaiset lataukset", "ag1": "näytä tunnetut IdP-käyttäjät", }, "grc": { @@ -259,7 +259,7 @@ var Ls = { "ae1": "in uscita:", "af1": "mostra i file caricati di recente", "ag1": "mostra utenti IdP conosciuti" -}, + }, "nld": { "a1": "Update", "b1": "Hallo, hoe gaat het met jou?   <small>(Je bent niet ingelogd)</small>", From 29a4e54799564b5124d1a84e62a11dc71739954f Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 21:10:15 +0000 Subject: [PATCH 38/66] tl cleanup --- copyparty/web/browser.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 9c20c5d8..ea4c3f1f 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -2439,7 +2439,7 @@ var Ls = { "u_https1": "für bessere Performance solltest du", "u_https2": "auf HTTPS wechseln", - "u_https3": "", + "u_https3": " ", "u_ancient": 'Dein Browser ist verdammt antik -- vielleicht solltest du <a href="#" onclick="goto(\'bup\')">stattdessen bup benutzen</a>', "u_nowork": "Benötigt Firefox 53+ oder Chrome 57+ oder iOS 11+", "tail_2old": "Benötigt Firefox 105+ oder Chrome 71+ oder iOS 14.5+", @@ -2489,7 +2489,7 @@ var Ls = { "u_ehsdf": "Server hat kein Speicherplatz mehr!\n\nwerde es erneut versuchen, falls jemand\ngenug Platz schafft um fortzufahren", "u_emtleak1": "scheint, als ob dein Browser ein Memory Leak hätte;\nbitte", "u_emtleak2": ' <a href="{0}">wechsle auf HTTPS (empfohlen)</a> oder ', - "u_emtleak3": '', + "u_emtleak3": ' ', "u_emtleakc": 'versuche folgendes:\n<ul><li>drücke <code>F5</code> um die Seite neu zu laden</li><li>deaktivere dann den  <code>mt</code>  Button in den  <code>⚙️ Einstellungen</code></li><li>und versuche den Upload nochmal.</li></ul>Uploads werden etwas langsamer sein, aber man kann ja nicht alles haben.\nSorry für die Umstände !\n\nPS: Chrome v107 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">hat ein Bugfix</a> dafür', "u_emtleakf": 'versuche folgendes:\n<ul><li>drücke <code>F5</code> um die Seite neu zu laden</li><li>aktivere dann <code>🥔</code> (potato) im Upload UI<li>und versuche den Upload nochmal</li></ul>\nPS: Firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">hat hoffentlich irgendwann ein Bugfix</a>', "u_s404": "nicht auf dem Server gefunden", @@ -2857,7 +2857,7 @@ var Ls = { "mm_uncache": "välimuisti tyhjennetty; kaikki kappaleet ladataan uudelleen seuraavalla toistolla", "mm_hnf": "tuota kappaletta ei enää ole olemassa", -" im_hnf": "tuota kuvaa ei enää ole olemassa", + "im_hnf": "tuota kuvaa ei enää ole olemassa", "f_empty": 'tämä hakemisto on tyhjä', "f_chide": 'tämä piilottaa sarakkeen «{0}»\n\nvoit palauttaa sarakkeet asetuksista', From a9ee4f24d50286079788fc4f203b486ff5871f19 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Wed, 6 Aug 2025 21:53:20 +0000 Subject: [PATCH 39/66] dropdowns for languages, themes, key-notation --- copyparty/web/browser.css | 5 +++ copyparty/web/browser.js | 73 +++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css index 1f5a7da6..b5506f39 100644 --- a/copyparty/web/browser.css +++ b/copyparty/web/browser.css @@ -1374,6 +1374,7 @@ html.y #ops svg circle { #op_cfg input[type=text] { top: -.3em; } +.opview select, .opview input[type=text] { color: var(--fg); background: var(--txt-bg); @@ -1384,6 +1385,10 @@ html.y #ops svg circle { border-radius: .2em; padding: .2em .3em; } +.opview select { + padding: .3em; + margin: .2em .4em; +} .opview input.err { color: var(--err-fg); background: var(--err-bg); diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index ea4c3f1f..b84c39ee 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -7151,13 +7151,12 @@ ebi('op_cfg').innerHTML = ( '</div>\n' + '<div>\n' + ' <h3>' + L.cl_themes + '</h3>\n' + - ' <div id="themes">\n' + + ' <div><select id="themes"></select></div>\n' + ' </div>\n' + '</div>\n' + '<div>\n' + ' <h3>' + L.cl_langs + '</h3>\n' + - ' <div id="langs">\n' + - ' </div>\n' + + ' <div><select id="langs"></select></div>\n' + '</div>\n' + (have_zip ? ( '<div><h3>' + L.cl_ziptype + '</h3><div id="arc_fmt"></div></div>\n' @@ -7204,7 +7203,7 @@ ebi('op_cfg').innerHTML = ( ' </td>\n' + ' </div>\n' + '</div>\n' + - '<div><h3>' + L.cl_keytype + '</h3><div id="key_notation"></div></div>\n' + + '<div><h3>' + L.cl_keytype + '</h3><div><select id="key_notation"></select></div></div>\n' + '<div><h3>' + L.cl_hiddenc + '  ' + (MOBILE ? '<a href="#" id="hcolsh">' + L.cl_hidec + '</a> / ' : '') + '<a href="#" id="hcolsr">' + L.cl_reset + '</a></h3><div id="hcols"></div></div>' ); @@ -14109,25 +14108,21 @@ var mukey = (function () { defnot = 'rekobo_alnum'; var map = {}, - html = []; + html = [], + cb = ebi('key_notation'); for (var k in maps) { if (!maps.hasOwnProperty(k)) continue; - html.push( - '<span><input type="radio" name="keytype" value="' + k + '" id="key_' + k + '">' + - '<label for="key_' + k + '">' + k + '</label></span>'); - + html.push('<option value="{0}">{0}</option>'.format(k)); for (var a = 0; a < 24; a++) maps[k][a] = maps[k][a].trim(); } - ebi('key_notation').innerHTML = html.join('\n'); + cb.innerHTML = html.join(''); - function set_key_notation(e) { - ev(e); - var notation = this.getAttribute('value'); - load_notation(notation); + function set_key_notation() { + load_notation(cb.value); try_render(); } @@ -14184,14 +14179,10 @@ var mukey = (function () { if (!maps[notation]) notation = defnot; - ebi('key_' + notation).checked = true; + cb.value = notation; + cb.onchange = set_key_notation; load_notation(notation); - var o = QSA('#key_notation input'); - for (var a = 0; a < o.length; a++) { - o[a].onchange = set_key_notation; - } - return { "render": try_render }; @@ -14230,17 +14221,17 @@ var settheme = (function () { showfile.setstyle(); bchrome(); - var html = [], itheme = ax.indexOf(theme[0]) * 2 + (light ? 1 : 0), + var html = [], + cb = ebi('themes'), + itheme = ax.indexOf(theme[0]) * 2 + (light ? 1 : 0), names = ['classic dark', 'classic light', 'pm-monokai', 'flat light', 'vice', 'hotdog stand', 'hacker', 'hi-con']; for (var a = 0; a < themes; a++) - html.push('<a href="#" class="btn tgl' + (a == itheme ? ' on' : '') + - '" tt="' + (names[a] || 'custom') + '">' + a + '</a>'); + html.push('<option value="{0}">{0} ┃ {1}</option>'.format(a, names[a] || 'custom')); ebi('themes').innerHTML = html.join(''); - var btns = QSA('#themes a'); - for (var a = 0; a < themes; a++) - btns[a].onclick = r.go; + cb.value = itheme; + cb.onchange = r.onsel; if (chldr) { var x = r.ldr[itheme] || [tre]; @@ -14249,12 +14240,13 @@ var settheme = (function () { } bcfg_set('light', light); - tt.att(ebi('themes')); } - r.go = function (e) { - var i = e; - try { ev(e); i = e.target.textContent; } catch (ex) { } + r.onsel = function () { + r.go(parseInt(ebi('themes').value)); + }; + + r.go = function (i) { light = i % 2 == 1; var c = ax[Math.floor(i / 2)], l = light ? 'y' : 'z'; @@ -14262,7 +14254,7 @@ var settheme = (function () { themen = c + l; swrite('cpp_thm', theme); freshen(); - } + }; freshen(); return r; @@ -14272,26 +14264,25 @@ var settheme = (function () { (function () { function freshen() { lang = sread("cpp_lang", LANGS) || lang; - var k, html = []; + var k, cb = ebi('langs'), html = []; for (var a = 0; a < LANGS.length; a++) { k = LANGS[a]; - html.push('<a href="#" class="btn tgl' + (k == lang ? ' on' : '') + - '" tt="' + Ls[k].tt + '">' + k + '</a>'); + html.push('<option value="{0}">{0} ┃ {1}</option>'.format(k, Ls[k].tt)); } - ebi('langs').innerHTML = html.join(''); - var btns = QSA('#langs a'); - for (var a = 0, aa = btns.length; a < aa; a++) - btns[a].onclick = setlang; + cb.innerHTML = html.join(''); + cb.onchange = setlang; + cb.value = lang; } function setlang(e) { ev(e); var t = L.lang_set; - L = Ls[this.textContent]; - swrite("cpp_lang", this.textContent); + lang = ebi('langs').value; + L = Ls[lang]; + swrite("cpp_lang", lang); freshen(); modal.confirm(L.lang_set + "\n\n" + t, location.reload.bind(location), null); - }; + } freshen(); })(); From 9b9d2a92ca128289b9e6943ad24e3d6f5f3df5ce Mon Sep 17 00:00:00 2001 From: mati1210 <49544174+mati1210@users.noreply.github.com> Date: Thu, 7 Aug 2025 12:00:53 -0300 Subject: [PATCH 40/66] support systemd socket activation (fd passing) (#515) * add support for socket passing * slight tweaks before merge --------- Signed-off-by: mat <matheuz1210@gmail.com> Signed-off-by: ed <s@ocv.me> Co-authored-by: ed <s@ocv.me> --- copyparty/__main__.py | 6 ++++-- copyparty/ftpd.py | 2 +- copyparty/svchub.py | 4 ++-- copyparty/tcpsrv.py | 21 ++++++++++++++++----- copyparty/tftpd.py | 2 +- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 3f07bfc1..86b6b031 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -536,7 +536,7 @@ def get_sects(): dedent( """ \033[33m-i\033[0m takes a comma-separated list of interfaces to listen on; - IP-addresses and/or unix-sockets (Unix Domain Sockets) + IP-addresses, unix-sockets and/or open file descriptors the default (\033[32m-i ::\033[0m) means all IPv4 and IPv6 addresses @@ -562,7 +562,9 @@ def get_sects(): \033[32m-i unix:\033[33m/dev/shm/party.sock\033[0m keeps umask-defined permission (usually \033[33m0600\033[0m) and the same user/group as copyparty - \033[33m-p\033[0m (tcp ports) is ignored for unix sockets + \033[32m-i fd:\033[33m3\033[0m uses the socket passed to copyparty on file descriptor 3 + + \033[33m-p\033[0m (tcp ports) is ignored for non ip-addresses """ ), ], diff --git a/copyparty/ftpd.py b/copyparty/ftpd.py index 2f45c3f4..bace7d28 100644 --- a/copyparty/ftpd.py +++ b/copyparty/ftpd.py @@ -607,7 +607,7 @@ class Ftpd(object): if "::" in ips: ips.append("0.0.0.0") - ips = [x for x in ips if "unix:" not in x] + ips = [x for x in ips if not x.startswith(("unix:", "fd:"))] if self.args.ftp4: ips = [x for x in ips if ":" not in x] diff --git a/copyparty/svchub.py b/copyparty/svchub.py index bd7562e4..9a00f890 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -868,7 +868,7 @@ class SvcHub(object): have_tcp = False for zs in al.i: - if not zs.startswith("unix:"): + if not zs.startswith(("unix:", "fd:")): have_tcp = True if not have_tcp: zb = False @@ -878,7 +878,7 @@ class SvcHub(object): setattr(al, zs, False) zb = True if zb: - t = "only listening on unix-sockets; cannot enable zeroconf/mdns/ssdp as requested" + t = "no ip addresses provided; cannot enable zeroconf/mdns/ssdp as requested" self.log("root", t, 3) if not self.args.no_dav: diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py index 53388c5e..6c61fe61 100644 --- a/copyparty/tcpsrv.py +++ b/copyparty/tcpsrv.py @@ -25,8 +25,8 @@ from .util import ( termsize, ) -if True: - from typing import Generator, Union +if True: # pylint: disable=using-constant-test + from typing import Generator, Optional, Union if TYPE_CHECKING: from .svchub import SvcHub @@ -245,8 +245,10 @@ class TcpSrv(object): def _listen(self, ip: str, port: int) -> None: uds_perm = uds_gid = -1 + bound: Optional[socket.socket] = None + tcp = False + if "unix:" in ip: - tcp = False ipv = socket.AF_UNIX uds = ip.split(":") ip = uds[-1] @@ -259,7 +261,12 @@ class TcpSrv(object): import grp uds_gid = grp.getgrnam(uds[2]).gr_gid + elif "fd:" in ip: + fd = ip[3:] + bound = socket.socket(fileno=int(fd)) + tcp = bound.proto == socket.IPPROTO_TCP + ipv = bound.family elif ":" in ip: tcp = True ipv = socket.AF_INET6 @@ -267,7 +274,7 @@ class TcpSrv(object): tcp = True ipv = socket.AF_INET - srv = socket.socket(ipv, socket.SOCK_STREAM) + srv = bound or socket.socket(ipv, socket.SOCK_STREAM) if not ANYWIN or self.args.reuseaddr: srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -285,6 +292,10 @@ class TcpSrv(object): if getattr(self.args, "freebind", False): srv.setsockopt(socket.SOL_IP, socket.IP_FREEBIND, 1) + if bound: + self.srv.append(srv) + return + try: if tcp: srv.bind((ip, port)) @@ -437,7 +448,7 @@ class TcpSrv(object): def detect_interfaces(self, listen_ips: list[str]) -> dict[str, Netdev]: from .stolen.ifaddr import get_adapters - listen_ips = [x for x in listen_ips if "unix:" not in x] + listen_ips = [x for x in listen_ips if not x.startswith(("unix:", "fd:"))] nics = get_adapters(True) eps: dict[str, Netdev] = {} diff --git a/copyparty/tftpd.py b/copyparty/tftpd.py index 6f5726b3..4ef01103 100644 --- a/copyparty/tftpd.py +++ b/copyparty/tftpd.py @@ -179,7 +179,7 @@ class Tftpd(object): if "::" in ips: ips.append("0.0.0.0") - ips = [x for x in ips if "unix:" not in x] + ips = [x for x in ips if not x.startswith(("unix:", "fd:"))] if self.args.tftp4: ips = [x for x in ips if ":" not in x] From 54caf63f6aab9198d0e2038da38b2d7b0622bffc Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 15:18:59 +0000 Subject: [PATCH 41/66] optimize --- copyparty/__main__.py | 4 ++-- copyparty/httpcli.py | 13 +++++-------- copyparty/multicast.py | 6 +----- copyparty/svchub.py | 2 +- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 86b6b031..eb44ef4f 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -536,7 +536,7 @@ def get_sects(): dedent( """ \033[33m-i\033[0m takes a comma-separated list of interfaces to listen on; - IP-addresses, unix-sockets and/or open file descriptors + IP-addresses, unix-sockets, and/or open file descriptors the default (\033[32m-i ::\033[0m) means all IPv4 and IPv6 addresses @@ -564,7 +564,7 @@ def get_sects(): \033[32m-i fd:\033[33m3\033[0m uses the socket passed to copyparty on file descriptor 3 - \033[33m-p\033[0m (tcp ports) is ignored for non ip-addresses + \033[33m-p\033[0m (tcp ports) is ignored for unix-sockets and FDs """ ), ], diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index b335fe4a..c982a812 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -262,7 +262,8 @@ class HttpCli(object): def _assert_safe_rem(self, rem: str) -> None: # sanity check to prevent any disasters - if rem.startswith("/") or rem.startswith("../") or "/../" in rem: + # (this function hopefully serves no purpose; validation has already happened at this point, this only exists as a last-ditch effort just in case) + if rem.startswith(("/", "../")) or "/../" in rem: raise Exception("that was close") def _gen_fk(self, alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str: @@ -5031,7 +5032,7 @@ class HttpCli(object): wvol = [x for x in wvol if "unlistcw" not in allvols[x[1:-1]].flags] fmt = self.uparam.get("ls", "") - if not fmt and (self.ua.startswith("curl/") or self.ua.startswith("fetch")): + if not fmt and self.ua.startswith(("curl/", "fetch")): fmt = "v" if fmt in ["v", "t", "txt"]: @@ -5141,7 +5142,7 @@ class HttpCli(object): t = '<h1 id="n">404 not found  ┐( ´ -`)┌</h1><p><a id="r" href="{}/?h">go home</a></p>' pt = "404 not found ┐( ´ -`)┌" - if self.ua.startswith("curl/") or self.ua.startswith("fetch"): + if self.ua.startswith(("curl/", "fetch")): pt = "# acct: %s\n%s\n" % (self.uname, pt) self.reply(pt.encode("utf-8"), status=rc) return True @@ -6267,11 +6268,7 @@ class HttpCli(object): is_ls = "ls" in self.uparam is_js = self.args.force_js or self.cookies.get("js") == "y" - if ( - not is_ls - and not add_og - and (self.ua.startswith("curl/") or self.ua.startswith("fetch")) - ): + if not is_ls and not add_og and self.ua.startswith(("curl/", "fetch")): self.uparam["ls"] = "v" is_ls = True diff --git a/copyparty/multicast.py b/copyparty/multicast.py index 6d6507f8..766dc15d 100644 --- a/copyparty/multicast.py +++ b/copyparty/multicast.py @@ -183,11 +183,7 @@ class MCast(object): srv.ips[oth_ip.split("/")[0]] = ipaddress.ip_network(oth_ip, False) # gvfs breaks if a linklocal ip appears in a dns reply - ll = { - k: v - for k, v in srv.ips.items() - if k.startswith("169.254") or k.startswith("fe80") - } + ll = {k: v for k, v in srv.ips.items() if k.startswith(("169.254", "fe80"))} rt = {k: v for k, v in srv.ips.items() if k not in ll} if self.args.ll or not rt: diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 9a00f890..07d85d83 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -878,7 +878,7 @@ class SvcHub(object): setattr(al, zs, False) zb = True if zb: - t = "no ip addresses provided; cannot enable zeroconf/mdns/ssdp as requested" + t = "not listening on any ip-addresses (only unix-sockets and/or FDs); cannot enable zeroconf/mdns/ssdp as requested" self.log("root", t, 3) if not self.args.no_dav: From 8a0746c6af6d72cac2c8f10dfa383c76b93562f8 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 15:24:15 +0000 Subject: [PATCH 42/66] fix viewing .MD files --- copyparty/httpcli.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index c982a812..79003bcc 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -3584,7 +3584,7 @@ class HttpCli(object): rem = "{}/{}".format(rp, fn).strip("/") dbv, vrem = vfs.get_dbv(rem) - if not rem.endswith(".md") and not self.can_delete: + if not rem.lower().endswith(".md") and not self.can_delete: raise Pebkac(400, "only markdown pls") if nullwrite: @@ -6196,7 +6196,8 @@ class HttpCli(object): if not use_filekey: return self.tx_404(True) - if add_og and not abspath.lower().endswith(".md"): + is_md = abspath.lower().endswith(".md") + if add_og and not is_md: if og_ua or self.host not in self.headers.get("referer", ""): self.vpath, og_fn = vsplit(self.vpath) vpath = self.vpath @@ -6208,10 +6209,10 @@ class HttpCli(object): vpnodes.pop() if ( - (abspath.endswith(".md") or self.can_delete) + (is_md or self.can_delete) and "nohtml" not in vn.flags and ( - ("v" in self.uparam and abspath.endswith(".md")) + (is_md and "v" in self.uparam) or "edit" in self.uparam or "edit2" in self.uparam ) From 4a0435681449ada06c87c9cb7cff37b92d4d3bb4 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 15:57:51 +0000 Subject: [PATCH 43/66] fix non-e2d dupe finalizing; when the up2k database is not enabled, only the 38400 most recent uploads are kept in memory serverside the webui did not anticipate this, expecting the server to finalize all dupes with just a single pass of brief handshakes fix this by doing as many passes as necessary, only stopping if a pass does not make any progress (filesystem-issues or some such) --- copyparty/web/up2k.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 1e49fc4e..2743ea36 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -964,6 +964,7 @@ function up2k_init(subtle) { "t": 0 }, "car": 0, + "nre": 0, "slow_io": null, "oserr": false, "modn": 0, @@ -1783,8 +1784,7 @@ function up2k_init(subtle) { } var tasker = (function () { - var running = false, - was_busy = false; + var running = false; var defer = function () { running = false; @@ -1801,7 +1801,17 @@ function up2k_init(subtle) { while (true) { var now = Date.now(), blocktime = now - r.tact, - is_busy = st.car < st.files.length; + was_busy = st.is_busy, + is_busy = !!( // gzip take the wheel + st.car < st.files.length || + st.busy.hash.length || + st.todo.hash.length || + st.busy.handshake.length || + st.todo.handshake.length || + st.busy.upload.length || + st.todo.upload.length || + st.busy.head.length || + st.todo.head.length); if (blocktime > 2500) console.log('main thread blocked for ' + blocktime); @@ -1809,7 +1819,16 @@ function up2k_init(subtle) { r.tact = now; if (was_busy && !is_busy) { - for (var a = 0; a < st.files.length; a++) { + var nre = 0, nf = 0; + for (var a = 0; a < st.files.length; a++) + if (st.files[a].want_recheck) + nre++; + console.log('nre', nre, 'st', st.nre); + if (st.nre != nre) { + st.nre = nre; + nf = st.files.length; + } + for (var a = 0; a < nf; a++) { var t = st.files[a]; if (t.want_recheck) { t.rechecks++; @@ -1817,7 +1836,7 @@ function up2k_init(subtle) { push_t(st.todo.handshake, t); } } - is_busy = st.todo.handshake.length; + is_busy = !!st.todo.handshake.length; try { if (!is_busy && !uc.fsearch && !msel.getsel().length && (!mp.au || mp.au.paused)) treectl.goto(); @@ -1826,7 +1845,7 @@ function up2k_init(subtle) { } if (was_busy != is_busy) { - st.is_busy = was_busy = is_busy; + st.is_busy = is_busy; window[(is_busy ? "add" : "remove") + "EventListener"]("beforeunload", warn_uploader_busy); @@ -1947,7 +1966,7 @@ function up2k_init(subtle) { for (var a = 0; a < st.files.length; a++) { var t = st.files[a]; - if (t.want_recheck && !t.rechecks) + if (t.want_recheck && t.rechecks < 999) return; } @@ -2693,8 +2712,9 @@ function up2k_init(subtle) { if (ofs !== -1) { err = err.slice(0, ofs + 1) + linksplit(err.slice(ofs + 2).trimEnd()).join(' / '); } - if (!t.rechecks && (err_pend || err_srcb)) { + if (!t.rechecks) t.rechecks = 0; + if (t.rechecks < 999 && (err_pend || err_srcb)) { t.want_recheck = true; if (st.busy.upload.length || st.busy.handshake.length || st.bytes.uploaded) { err = L.u_dupdefer; From 3f8cb7e877e9ef8dffd1cdf910c36ef1ac5aad34 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 17:00:42 +0000 Subject: [PATCH 44/66] xff: require explicit configuration of --rproxy; try to avoid dangerous misconfiguration of how to determine the client's IP by more aggressively asking for the correct config; if the --xff-hdr (default: x-forwarded-for) appears in a request then it will now be ignored unless --rproxy says which IP to use --- README.md | 8 ++++++-- copyparty/__main__.py | 2 +- copyparty/httpcli.py | 17 ++++++++++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9746581b..2afc4a81 100644 --- a/README.md +++ b/README.md @@ -2058,7 +2058,11 @@ you can either: * or do location-based proxying, using `--rp-loc=/stuff` to tell copyparty where it is mounted -- has a slight performance cost and higher chance of bugs * if copyparty says `incorrect --rp-loc or webserver config; expected vpath starting with [...]` it's likely because the webserver is stripping away the proxy location from the request URLs -- see the `ProxyPass` in the apache example below -when running behind a reverse-proxy (this includes services like cloudflare), it is important to configure real-ip correctly, as many features rely on knowing the client's IP. Look out for red and yellow log messages which explain how to do this. But basically, set `--xff-hdr` to the name of the http header to read the IP from (usually `x-forwarded-for`, but cloudflare uses `cf-connecting-ip`), and then `--xff-src` to the IP of the reverse-proxy so copyparty will trust the xff-hdr. Note that `--rp-loc` in particular will not work at all unless you do this +when running behind a reverse-proxy (this includes services like cloudflare), it is important to configure real-ip correctly, as many features rely on knowing the client's IP. The best/safest approach is to configure your reverse-proxy so it gives copyparty a header which only contains the client's true/real IP-address, and then setting `--xff-hdr theHeaderName --rproxy 1` but alternatively, if you want/need to let copyparty handle this, look out for red and yellow log messages which explain how to do that. Basically, the log will say this: + +> set `--xff-hdr` to the name of the http-header to read the IP from (usually `x-forwarded-for`, but cloudflare uses `cf-connecting-ip`), and then `--xff-src` to the IP of the reverse-proxy so copyparty will trust the xff-hdr. You will also need to configure `--rproxy` to `1` if the header only contains one IP (the correct one) or to a *negative value* if it contains multiple; `-1` being the rightmost and most trusted IP (the nearest proxy, so usually not the correct one), `-2` being the second-closest hop, and so on + +Note that `--rp-loc` in particular will not work at all unless you configure the above correctly some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which *could* be a nice speed boost, depending on a lot of factors * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now @@ -2615,7 +2619,7 @@ there is a [discord server](https://discord.gg/25J8CdTT6G) with an `@everyone` some notes on hardening -* set `--rproxy 0` if your copyparty is directly facing the internet (not through a reverse-proxy) +* set `--rproxy 0` *if and only if* your copyparty is directly facing the internet (not through a reverse-proxy) * cors doesn't work right otherwise * if you allow anonymous uploads or otherwise don't trust the contents of a volume, you can prevent XSS with volflag `nohtml` * this returns html documents as plaintext, and also disables markdown rendering diff --git a/copyparty/__main__.py b/copyparty/__main__.py index eb44ef4f..81476e7f 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1091,7 +1091,7 @@ def add_network(ap): ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (comma-separated list; see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6") ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to listen on (comma/range); ignored for unix-sockets") ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)") - ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=1, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m2\033[0m]=outermost-proxy, [\033[32m3\033[0m]=second-proxy, [\033[32m-1\033[0m]=closest-proxy") + ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=9999999, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m-1\033[0m]=closest-proxy, [\033[32m-2\033[0m]=second-hop, [\033[32m-3\033[0m]=third-hop") ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from") ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="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]") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 79003bcc..2986275f 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -384,9 +384,20 @@ class HttpCli(object): try: cli_ip = zsl[n].strip() except: - cli_ip = zsl[0].strip() - t = "rproxy={} oob x-fwd {}" - self.log(t.format(self.args.rproxy, zso), c=3) + cli_ip = self.ip + self.bad_xff = True + if self.args.rproxy != 9999999: + t = "global-option --rproxy %d could not be used (out-of-bounds) for the received header [%s]" + self.log(t % (self.args.rproxy, zso), c=3) + else: + zsl = [ + " rproxy: %d if this client's IP-address is [%s]" + % (-1 - zd, zs.strip()) + for zd, zs in enumerate(zsl) + ] + t = 'could not determine the client\'s IP-address because the global-option --rproxy has not been configured, so the request-header [%s] specified by global-option --xff-hdr cannot be used safely! Please see the "reverse-proxy" section in the readme. The best approach is to configure your reverse-proxy to give copyparty the exact IP-address to assume (perhaps in another header), but you may also try the following:' + t = t % (self.args.xff_hdr,) + self.log("%s\n\n%s\n" % (t, "\n".join(zsl)), 3) pip = self.conn.addr[0] xffs = self.conn.xff_nm From 9e980bb55203c2a73a0a9efc7792c7e0fd379ab2 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 17:57:10 +0000 Subject: [PATCH 45/66] try to detect proxies with misbehaving caches (#488) --- copyparty/__main__.py | 1 + copyparty/httpcli.py | 6 ++++++ copyparty/web/browser.js | 4 ++++ tests/util.py | 4 ++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 81476e7f..0715af28 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1300,6 +1300,7 @@ def add_yolo(ap): ap2 = ap.add_argument_group("yolo options") ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests") ap2.add_argument("--cookie-lax", action="store_true", help="allow cookies from other domains (if you follow a link from another website into your server, you will arrive logged-in); this reduces protection against CSRF") + ap2.add_argument("--no-fnugg", action="store_true", help="disable the smoketest for caching-related issues in the web-UI") ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET") ap2.add_argument("--wo-up-readme", action="store_true", help="allow users with write-only access to upload logues and readmes without adding the _wo_ filename prefix (volflag=wo_up_readme)") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 2986275f..3da299c7 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -6025,6 +6025,12 @@ class HttpCli(object): else: [x.pop(k) for k in ["name", "dt"] for y in [dirs, files] for x in y] + # nonce (tlnote: norwegian for flake as in snowflake) + if self.args.no_fnugg: + ls["fnugg"] = "nei" + elif "fnugg" in self.headers: + ls["fnugg"] = self.headers["fnugg"] + ret = json.dumps(ls) mime = "application/json" diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index b84c39ee..0563d8ee 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -13204,6 +13204,7 @@ var treectl = (function () { xhr.hydrate = hydrate; xhr.ts = Date.now(); xhr.open('GET', xhr.top + '?ls' + uq, true); + xhr.setRequestHeader('Fnugg', '' + xhr.ts); xhr.onload = xhr.onerror = recvls; xhr.send(); @@ -13269,6 +13270,9 @@ var treectl = (function () { if (r.chk_index_html(this.top, res)) return; + if (this.ts != res.fnugg && res.fnugg != 'nei' && sread('no_fnugg') !== '1') + toast.warn(60, "WARNING: A proxy/CDN between your webbrowser and the server is misbehaving, and caching responses it shouldn't. As a result, you are now seeing stale directory listings. There will be many issues.\n\nIf you need to ignore this and stop these messages, you can set the global-option 'no-fnugg' on the server, or click <code>π</code> and run this: <code>STG.no_fnugg=1</code>"); + for (var a = 0; a < res.files.length; a++) if (res.files[a].tags === undefined) res.files[a].tags = {}; diff --git a/tests/util.py b/tests/util.py index ea9bfeb9..7b4ad2aa 100644 --- a/tests/util.py +++ b/tests/util.py @@ -143,7 +143,7 @@ class Cfg(Namespace): def __init__(self, a=None, v=None, c=None, **ka0): ka = {} - ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" + ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_fnugg no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" ka.update(**{k: False for k in ex.split()}) ex = "dav_inf dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash see_dots plain_ip" @@ -161,7 +161,7 @@ class Cfg(Namespace): ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who" ka.update(**{k: 9 for k in ex.split()}) - ex = "db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" + ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" ka.update(**{k: 0 for k in ex.split()}) ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR" From 34d98e9980c40450d9375ff48e9bdc31110d05c1 Mon Sep 17 00:00:00 2001 From: exci <76759714+icxes@users.noreply.github.com> Date: Thu, 7 Aug 2025 21:10:26 +0300 Subject: [PATCH 46/66] add systemd user services and templated services (#502) * move service files from contrib/package/arch/ to /contrib/systemd/ * add simpler default copyparty.conf that puts users in jail * remove warning about .conf files in ~/.config/copyparty/ * update PKGBUILD with changes * add links to configuration examples in index.md * fix link to the example config * update README.md arch instructions --------- Co-authored-by: icxes <icxes@dev.null@need.moe> Co-authored-by: ed <s@ocv.me> --- README.md | 6 +- contrib/package/arch/PKGBUILD | 58 ++++++++----------- contrib/package/arch/copyparty.conf | 7 --- contrib/package/arch/copyparty.service | 32 ---------- contrib/package/arch/index.md | 3 - contrib/systemd/copyparty-user.service | 26 +++++++++ contrib/systemd/copyparty.conf | 45 +++----------- contrib/systemd/copyparty.example.conf | 42 ++++++++++++++ contrib/systemd/copyparty@.service | 30 ++++++++++ contrib/systemd/index.md | 10 ++++ contrib/systemd/prisonparty-user.service | 33 +++++++++++ .../prisonparty@.service} | 25 ++++---- copyparty/svchub.py | 9 --- 13 files changed, 191 insertions(+), 135 deletions(-) delete mode 100644 contrib/package/arch/copyparty.conf delete mode 100644 contrib/package/arch/copyparty.service delete mode 100644 contrib/package/arch/index.md create mode 100644 contrib/systemd/copyparty-user.service create mode 100644 contrib/systemd/copyparty.example.conf create mode 100644 contrib/systemd/copyparty@.service create mode 100644 contrib/systemd/index.md create mode 100644 contrib/systemd/prisonparty-user.service rename contrib/{package/arch/prisonparty.service => systemd/prisonparty@.service} (51%) diff --git a/README.md b/README.md index 2afc4a81..39bd932f 100644 --- a/README.md +++ b/README.md @@ -2281,11 +2281,9 @@ if your distro/OS is not mentioned below, there might be some hints in the [«on `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/)) -it comes with a [systemd service](./contrib/package/arch/copyparty.service) and expects to find one or more [config files](./docs/example.conf) in `/etc/copyparty.d/` +it comes with a [systemd service](./contrib/systemd/copyparty@.service) as well as a [user service](./contrib/systemd/copyparty-user.service), and expects to find a [config file](./contrib/systemd/copyparty.example.conf) in `/etc/copyparty/copyparty.conf` or `~/.config/copyparty/copyparty.conf` -after installing it, you may want to `cp /usr/lib/systemd/system/copyparty.service /etc/systemd/system/` and then `vim /etc/systemd/system/copyparty.service` to change what user/group it is running as (you only need to do this once) - -NOTE: there used to be an aur package; this evaporated when copyparty was adopted by the official archlinux repos. If you're still using the aur package, please move +after installing, start either the system service or the user service and navigate to http://127.0.0.1:3923 for further instructions (unless you already edited the config files, in which case you are good to go, probably) ## fedora package diff --git a/contrib/package/arch/PKGBUILD b/contrib/package/arch/PKGBUILD index 9efb5c41..c6dc4687 100644 --- a/contrib/package/arch/PKGBUILD +++ b/contrib/package/arch/PKGBUILD @@ -1,4 +1,7 @@ # Maintainer: icxes <dev.null@need.moe> +# Contributor: Morgan Adamiec <morganamilo@archlinux.org> +# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead. + pkgname=copyparty pkgver="1.18.10" pkgrel=1 @@ -6,52 +9,41 @@ pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFT arch=("any") url="https://github.com/9001/${pkgname}" license=('MIT') -depends=("python" "lsof" "python-jinja") +depends=("bash" "python" "lsof" "python-jinja") makedepends=("python-wheel" "python-setuptools" "python-build" "python-installer" "make" "pigz") optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tags" - "cfssl: generate TLS certificates on startup (pointless when reverse-proxied)" - "python-mutagen: music tags (alternative)" - "python-pillow: thumbnails for images" - "python-pyvips: thumbnails for images (higher quality, faster, uses more ram)" - "libkeyfinder-git: detection of musical keys" - "qm-vamp-plugins: BPM detection" - "python-pyopenssl: ftps functionality" - "python-pyzmq: send zeromq messages from event-hooks" - "python-argon2-cffi: hashed passwords in config" - "python-impacket-git: smb support (bad idea)" + "cfssl: generate TLS certificates on startup" + "python-mutagen: music tags (alternative)" + "python-pillow: thumbnails for images" + "python-pyvips: thumbnails for images (higher quality, faster, uses more ram)" + "libkeyfinder: detection of musical keys" + "python-pyopenssl: ftps functionality" + "python-pyzmq: send zeromq messages from event-hooks" + "python-argon2-cffi: hashed passwords in config" ) source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") -backup=("etc/${pkgname}.d/init" ) +backup=("etc/${pkgname}/copyparty.conf" ) sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99") build() { + cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web" + make + cd "${srcdir}/${pkgname}-${pkgver}" - - pushd copyparty/web - make -j$(nproc) - rm Makefile - popd - - python3 -m build -wn + python -m build --wheel --no-isolation } package() { cd "${srcdir}/${pkgname}-${pkgver}" - python3 -m installer -d "$pkgdir" dist/*.whl + python -m installer --destdir="$pkgdir" dist/*.whl - install -dm755 "${pkgdir}/etc/${pkgname}.d" + install -dm755 "${pkgdir}/etc/${pkgname}" install -Dm755 "bin/prisonparty.sh" "${pkgdir}/usr/bin/prisonparty" - install -Dm644 "contrib/package/arch/${pkgname}.conf" "${pkgdir}/etc/${pkgname}.d/init" - install -Dm644 "contrib/package/arch/${pkgname}.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}.service" - install -Dm644 "contrib/package/arch/prisonparty.service" "${pkgdir}/usr/lib/systemd/system/prisonparty.service" - install -Dm644 "contrib/package/arch/index.md" "${pkgdir}/var/lib/${pkgname}-jail/README.md" + install -Dm644 "contrib/systemd/${pkgname}.conf" "${pkgdir}/etc/${pkgname}/copyparty.conf" + install -Dm644 "contrib/systemd/${pkgname}@.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}@.service" + install -Dm644 "contrib/systemd/${pkgname}-user.service" "${pkgdir}/usr/lib/systemd/user/${pkgname}.service" + install -Dm644 "contrib/systemd/prisonparty@.service" "${pkgdir}/usr/lib/systemd/system/prisonparty@.service" + install -Dm644 "contrib/systemd/prisonparty-user.service" "${pkgdir}/usr/lib/systemd/user/prisonparty.service" + install -Dm644 "contrib/systemd/index.md" "${pkgdir}/var/lib/${pkgname}-jail/README.md" install -Dm644 "LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" - - find /etc/${pkgname}.d -iname '*.conf' 2>/dev/null | grep -qE . && return - echo "┏━━━━━━━━━━━━━━━──-" - echo "┃ Configure ${pkgname} by adding .conf files into /etc/${pkgname}.d/" - echo "┃ and maybe copy+edit one of the following to /etc/systemd/system/:" - echo "┣━♦ /usr/lib/systemd/system/${pkgname}.service (standard)" - echo "┣━♦ /usr/lib/systemd/system/prisonparty.service (chroot)" - echo "┗━━━━━━━━━━━━━━━──-" } diff --git a/contrib/package/arch/copyparty.conf b/contrib/package/arch/copyparty.conf deleted file mode 100644 index 1d90d772..00000000 --- a/contrib/package/arch/copyparty.conf +++ /dev/null @@ -1,7 +0,0 @@ -## import all *.conf files from the current folder (/etc/copyparty.d) -% ./ - -# add additional .conf files to this folder; -# see example config files for reference: -# https://github.com/9001/copyparty/blob/hovudstraum/docs/example.conf -# https://github.com/9001/copyparty/tree/hovudstraum/docs/copyparty.d diff --git a/contrib/package/arch/copyparty.service b/contrib/package/arch/copyparty.service deleted file mode 100644 index 22dac3d6..00000000 --- a/contrib/package/arch/copyparty.service +++ /dev/null @@ -1,32 +0,0 @@ -# this will start `/usr/bin/copyparty-sfx.py` -# and read config from `/etc/copyparty.d/*.conf` -# -# you probably want to: -# change "User=cpp" and "/home/cpp/" to another user -# -# unless you add -q to disable logging, you may want to remove the -# following line to allow buffering (slightly better performance): -# Environment=PYTHONUNBUFFERED=x - -[Unit] -Description=copyparty file server - -[Service] -Type=notify -SyslogIdentifier=copyparty -Environment=PYTHONUNBUFFERED=x -WorkingDirectory=/var/lib/copyparty-jail -ExecReload=/bin/kill -s USR1 $MAINPID - -# user to run as + where the TLS certificate is (if any) -User=cpp -Environment=XDG_CONFIG_HOME=/home/cpp/.config - -# stop systemd-tmpfiles-clean.timer from deleting copyparty while it's running -ExecStartPre=+/bin/bash -c 'mkdir -p /run/tmpfiles.d/ && echo "x /tmp/pe-copyparty*" > /run/tmpfiles.d/copyparty.conf' - -# run copyparty -ExecStart=/usr/bin/python3 /usr/bin/copyparty -c /etc/copyparty.d/init - -[Install] -WantedBy=multi-user.target diff --git a/contrib/package/arch/index.md b/contrib/package/arch/index.md deleted file mode 100644 index 016c0b0a..00000000 --- a/contrib/package/arch/index.md +++ /dev/null @@ -1,3 +0,0 @@ -this is `/var/lib/copyparty-jail`, the fallback webroot when copyparty has not yet been configured - -please add some `*.conf` files to `/etc/copyparty.d/` diff --git a/contrib/systemd/copyparty-user.service b/contrib/systemd/copyparty-user.service new file mode 100644 index 00000000..c6f61000 --- /dev/null +++ b/contrib/systemd/copyparty-user.service @@ -0,0 +1,26 @@ +# this will start `/usr/bin/copyparty` +# and read config from `$HOME/.config/copyparty.conf` +# +# unless you add -q to disable logging, you may want to remove the +# following line to allow buffering (slightly better performance): +# Environment=PYTHONUNBUFFERED=x + +[Unit] +Description=copyparty file server + +[Service] +Type=notify +SyslogIdentifier=copyparty +WorkingDirectory=/var/lib/copyparty-jail +Environment=PYTHONUNBUFFERED=x +Environment=PRTY_CONFIG=%h/.config/copyparty/copyparty.conf +ExecReload=/bin/kill -s USR1 $MAINPID + +# ensure there is a config +ExecStartPre=/bin/bash -c 'if [[ ! -f %h/.config/copyparty/copyparty.conf ]]; then mkdir -p %h/.config/copyparty; cp /etc/copyparty/copyparty.conf %h/.config/copyparty/copyparty.conf; fi' + +# run copyparty +ExecStart=/usr/bin/python3 /usr/bin/copyparty + +[Install] +WantedBy=default.target diff --git a/contrib/systemd/copyparty.conf b/contrib/systemd/copyparty.conf index 79560d0d..5d9bdbe3 100644 --- a/contrib/systemd/copyparty.conf +++ b/contrib/systemd/copyparty.conf @@ -1,42 +1,13 @@ -# not actually YAML but lets pretend: -# -*- mode: yaml -*- -# vim: ft=yaml: - - -# put this file in /etc/ - - [global] - e2dsa # enable file indexing and filesystem scanning - e2ts # and enable multimedia indexing - ansi # and colors in log messages - - # disable logging to stdout/journalctl and log to a file instead; - # $LOGS_DIRECTORY is usually /var/log/copyparty (comes from systemd) - # and copyparty replaces %Y-%m%d with Year-MonthDay, so the - # full path will be something like /var/log/copyparty/2023-1130.txt - # (note: enable compression by adding .xz at the end) - q, lo: $LOGS_DIRECTORY/%Y-%m%d.log - - # p: 80,443,3923 # listen on 80/443 as well (requires CAP_NET_BIND_SERVICE) - # i: 127.0.0.1 # only allow connections from localhost (reverse-proxies) - # ftp: 3921 # enable ftp server on port 3921 - # p: 3939 # listen on another port - # df: 16 # stop accepting uploads if less than 16 GB free disk space - # ver # show copyparty version in the controlpanel - # grid # show thumbnails/grid-view by default - # theme: 2 # monokai - # name: datasaver # change the server-name that's displayed in the browser - # stats, nos-dup # enable the prometheus endpoint, but disable the dupes counter (too slow) - # no-robots, force-js # make it harder for search engines to read your server - + i: 127.0.0.1 [accounts] - ed: wark # username: password + user: password - -[/] # create a volume at "/" (the webroot), which will - /mnt # share the contents of the "/mnt" folder +[/] + /var/lib/copyparty-jail accs: - rw: * # everyone gets read-write access, but - rwmda: ed # the user "ed" gets read-write-move-delete-admin + r: * + rwdma: user + flags: + grid \ No newline at end of file diff --git a/contrib/systemd/copyparty.example.conf b/contrib/systemd/copyparty.example.conf new file mode 100644 index 00000000..79560d0d --- /dev/null +++ b/contrib/systemd/copyparty.example.conf @@ -0,0 +1,42 @@ +# not actually YAML but lets pretend: +# -*- mode: yaml -*- +# vim: ft=yaml: + + +# put this file in /etc/ + + +[global] + e2dsa # enable file indexing and filesystem scanning + e2ts # and enable multimedia indexing + ansi # and colors in log messages + + # disable logging to stdout/journalctl and log to a file instead; + # $LOGS_DIRECTORY is usually /var/log/copyparty (comes from systemd) + # and copyparty replaces %Y-%m%d with Year-MonthDay, so the + # full path will be something like /var/log/copyparty/2023-1130.txt + # (note: enable compression by adding .xz at the end) + q, lo: $LOGS_DIRECTORY/%Y-%m%d.log + + # p: 80,443,3923 # listen on 80/443 as well (requires CAP_NET_BIND_SERVICE) + # i: 127.0.0.1 # only allow connections from localhost (reverse-proxies) + # ftp: 3921 # enable ftp server on port 3921 + # p: 3939 # listen on another port + # df: 16 # stop accepting uploads if less than 16 GB free disk space + # ver # show copyparty version in the controlpanel + # grid # show thumbnails/grid-view by default + # theme: 2 # monokai + # name: datasaver # change the server-name that's displayed in the browser + # stats, nos-dup # enable the prometheus endpoint, but disable the dupes counter (too slow) + # no-robots, force-js # make it harder for search engines to read your server + + +[accounts] + ed: wark # username: password + + +[/] # create a volume at "/" (the webroot), which will + /mnt # share the contents of the "/mnt" folder + accs: + rw: * # everyone gets read-write access, but + rwmda: ed # the user "ed" gets read-write-move-delete-admin diff --git a/contrib/systemd/copyparty@.service b/contrib/systemd/copyparty@.service new file mode 100644 index 00000000..cd891eab --- /dev/null +++ b/contrib/systemd/copyparty@.service @@ -0,0 +1,30 @@ +# this will start `/usr/bin/copyparty` +# and read config from `/etc/copyparty/copyparty.conf` +# +# the %i refers to whatever you put after the copyparty@ +# so with copyparty@foo.service, %i == foo +# +# unless you add -q to disable logging, you may want to remove the +# following line to allow buffering (slightly better performance): +# Environment=PYTHONUNBUFFERED=x + +[Unit] +Description=copyparty file server + +[Service] +Type=notify +SyslogIdentifier=copyparty +WorkingDirectory=/var/lib/copyparty-jail +Environment=PYTHONUNBUFFERED=x +Environment=PRTY_CONFIG=/etc/copyparty/copyparty.conf +ExecReload=/bin/kill -s USR1 $MAINPID + +# user to run as + where the TLS certificate is (if any) +User=%i +Environment=XDG_CONFIG_HOME=/home/%i/.config + +# run copyparty +ExecStart=/usr/bin/python3 /usr/bin/copyparty + +[Install] +WantedBy=multi-user.target diff --git a/contrib/systemd/index.md b/contrib/systemd/index.md new file mode 100644 index 00000000..cfd1b715 --- /dev/null +++ b/contrib/systemd/index.md @@ -0,0 +1,10 @@ +this is `/var/lib/copyparty-jail`, the fallback webroot when copyparty has not yet been configured + +please edit `/etc/copyparty/copyparty.conf` (if running as a system service) +or `$HOME/.config/copyparty/copyparty.conf` if running as a user service + +a basic configuration example is available at https://github.com/9001/copyparty/blob/hovudstraum/contrib/systemd/copyparty.example.conf +a configuration example that explains most flags is available at https://github.com/9001/copyparty/blob/hovudstraum/docs/chungus.conf + +the full list of configuration options can be seen at https://ocv.me/copyparty/helptext.html +or by running `copyparty --help` diff --git a/contrib/systemd/prisonparty-user.service b/contrib/systemd/prisonparty-user.service new file mode 100644 index 00000000..e0aaeaf8 --- /dev/null +++ b/contrib/systemd/prisonparty-user.service @@ -0,0 +1,33 @@ +# this will start `/usr/bin/copyparty` +# in a chroot, preventing accidental access elsewhere, +# and read copyparty config from `$HOME/.config/copyparty.conf` +# +# expose additional filesystem locations to copyparty +# by listing them between the last `%u` and `--` +# +# unless you add -q to disable logging, you may want to remove the +# following line to allow buffering (slightly better performance): +# Environment=PYTHONUNBUFFERED=x + +[Unit] +Description=copyparty file server + +[Service] +Type=notify +SyslogIdentifier=prisonparty +WorkingDirectory=/var/lib/copyparty-jail +Environment=PYTHONUNBUFFERED=x +Environment=PRTY_CONFIG=%h/.config/copyparty/copyparty.conf +ExecReload=/bin/kill -s USR1 $MAINPID + +# ensure there is a config +ExecStartPre=/bin/bash -c 'if [[ ! -f %h/.config/copyparty/copyparty.conf ]]; then mkdir -p %h/.config/copyparty; cp /etc/copyparty/copyparty.conf %h/.config/copyparty/copyparty.conf; fi' + +# run copyparty +ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail %u %u \ + %h/.config/copyparty \ + -- \ + /usr/bin/python3 /usr/bin/copyparty + +[Install] +WantedBy=default.target diff --git a/contrib/package/arch/prisonparty.service b/contrib/systemd/prisonparty@.service similarity index 51% rename from contrib/package/arch/prisonparty.service rename to contrib/systemd/prisonparty@.service index cd35ba99..d30010ae 100644 --- a/contrib/package/arch/prisonparty.service +++ b/contrib/systemd/prisonparty@.service @@ -1,11 +1,13 @@ -# this will start `/usr/bin/copyparty-sfx.py` +# this will start `/usr/bin/copyparty` # in a chroot, preventing accidental access elsewhere, -# and read copyparty config from `/etc/copyparty.d/*.conf` +# and read copyparty config from `/etc/copyparty/copyparty.conf` # # expose additional filesystem locations to copyparty -# by listing them between the last `cpp` and `--` +# by listing them between the last `%i` and `--` # -# `cpp cpp` = user/group to run copyparty as; can be IDs (1000 1000) +# `%i %i` = user/group to run copyparty as; can be IDs (1000 1000) +# the %i refers to whatever you put after the prisonparty@ +# so with prisonparty@foo.service, %i == foo # # unless you add -q to disable logging, you may want to remove the # following line to allow buffering (slightly better performance): @@ -15,19 +17,22 @@ Description=copyparty file server [Service] +Type=notify SyslogIdentifier=prisonparty -Environment=PYTHONUNBUFFERED=x WorkingDirectory=/var/lib/copyparty-jail +Environment=PYTHONUNBUFFERED=x +Environment=PRTY_CONFIG=/etc/copyparty/copyparty.conf ExecReload=/bin/kill -s USR1 $MAINPID -# stop systemd-tmpfiles-clean.timer from deleting copyparty while it's running -ExecStartPre=+/bin/bash -c 'mkdir -p /run/tmpfiles.d/ && echo "x /tmp/pe-copyparty*" > /run/tmpfiles.d/copyparty.conf' +# user to run as + where the TLS certificate is (if any) +User=%i +Environment=XDG_CONFIG_HOME=/home/%i/.config # run copyparty -ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail cpp cpp \ - /etc/copyparty.d \ +ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail %i %i \ + /etc/copyparty \ -- \ - /usr/bin/python3 /usr/bin/copyparty -c /etc/copyparty.d/init + /usr/bin/python3 /usr/bin/copyparty [Install] WantedBy=multi-user.target diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 07d85d83..1af13276 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -850,15 +850,6 @@ class SvcHub(object): def _check_env(self) -> None: al = self.args - try: - files = os.listdir(E.cfg) - except: - files = [] - - hits = [x for x in files if x.lower().endswith(".conf")] - if hits: - t = "WARNING: found config files in [%s]: %s\n config files are not expected here, and will NOT be loaded (unless your setup is intentionally hella funky)" - self.log("root", t % (E.cfg, ", ".join(hits)), 3) if self.args.no_bauth: t = "WARNING: --no-bauth disables support for the Android app; you may want to use --bauth-last instead" From 2943c7f2d51c4eb51706e246e67d72624e6d7f45 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 18:30:40 +0000 Subject: [PATCH 47/66] move the docker config smoketest over here --- copyparty/authsrv.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 44629e62..9c52f046 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -1700,6 +1700,7 @@ class AuthSrv(object): if not mount and not self.args.idp_h_usr: # -h says our defaults are CWD at root and read/write for everyone axs = AXS(["*"], ["*"], None, None) + ehint = "" if self.is_lxc: t = "Read-access has been disabled due to failsafe: Docker detected, but %s. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw" if len(cfg_files_loaded) == 1: @@ -1709,10 +1710,21 @@ class AuthSrv(object): else: self.log(t % ("the config does not define any volumes",), 1) axs = AXS() + ehint = "; please try moving them up one level, into the parent folder:" elif self.args.c: t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw" self.log(t, 1) axs = AXS() + ehint = ":" + if ehint: + try: + files = os.listdir(E.cfg) + except: + files = [] + hits = [x for x in files if x.lower().endswith(".conf")] + if hits: + t = "Hint: Found some config files in [%s], but these were not automatically loaded because they are in the wrong place%s %s\n" + self.log(t % (E.cfg, ehint, ", ".join(hits)), 3) zvf = {"tcolor": self.args.tcolor} vfs = VFS(self.log_func, absreal("."), "", "", axs, zvf) if not axs.uread: From bcc3b1568e2ceb46a40bff6661fd72970ebf3544 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 18:39:22 +0000 Subject: [PATCH 48/66] add qrcode to connectpage; closes #523 --- copyparty/web/svcs.html | 1 + copyparty/web/svcs.js | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/copyparty/web/svcs.html b/copyparty/web/svcs.html index a4b57746..26fd5267 100644 --- a/copyparty/web/svcs.html +++ b/copyparty/web/svcs.html @@ -37,6 +37,7 @@ {% if accs %}<code><b id="pw0">{{ pw }}</b></code>=password, {% endif %}<code><b>mp</b></code>=mountpoint </span> {% if accs %}<a href="#" id="setpw">use real password</a>{% endif %} + <a href="#" id="qr">show qr</a> </p> diff --git a/copyparty/web/svcs.js b/copyparty/web/svcs.js index 0de94523..dad7faab 100644 --- a/copyparty/web/svcs.js +++ b/copyparty/web/svcs.js @@ -49,12 +49,14 @@ function setos(os) { setos(WINDOWS ? 'win' : LINUX ? 'lin' : MACOS ? 'mac' : 'idk'); +var pw = ''; function setpw(e) { ev(e); modal.prompt('password:', '', function (v) { if (!v) return; + pw = v; var pw0 = ebi('pw0').innerHTML, oa = QSA('b'); @@ -67,3 +69,12 @@ function setpw(e) { } if (ebi('setpw')) ebi('setpw').onclick = setpw; + + +ebi('qr').onclick = function () { + var url = ('' + location).split('?')[0]; + if (pw) + url += '?pw=' + pw; + var txt = esc(url) + '<img class="b64" width="100" height="100" src="' + addq(url, 'qr') + '" />'; + modal.alert(txt); +}; From 8b31ed8816506776950cdc44ef7fc4a5ff681fa9 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 19:11:28 +0000 Subject: [PATCH 49/66] text-editor: optional EOL conversion; closes #513 --- copyparty/__main__.py | 1 + copyparty/cfg.py | 2 ++ copyparty/httpcli.py | 4 ++++ copyparty/util.py | 12 ++++++++++++ tests/util.py | 2 +- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 0715af28..d0fc325e 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1528,6 +1528,7 @@ def add_db_metadata(ap): def add_txt(ap): ap2 = ap.add_argument_group("textfile options") ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)") + ap2.add_argument("--txt-eol", metavar="TYPE", type=u, default="", help="enable EOL conversion when writing documents; supported: CRLF, LF (volflag=txt_eol)") ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="the textfile editor will check for serverside changes every \033[33mSEC\033[0m seconds") ap2.add_argument("-emp", action="store_true", help="enable markdown plugins -- neat but dangerous, big XSS risk") ap2.add_argument("--exp", action="store_true", help="enable textfile expansion -- replace {{self.ip}} and such; see \033[33m--help-exp\033[0m (volflag=exp)") diff --git a/copyparty/cfg.py b/copyparty/cfg.py index 2f75ab28..8a07f956 100644 --- a/copyparty/cfg.py +++ b/copyparty/cfg.py @@ -111,6 +111,7 @@ def vf_vmap() -> dict[str, str]: "tail_tmax", "tail_who", "tcolor", + "txt_eol", "unlist", "u2abort", "u2ts", @@ -322,6 +323,7 @@ flagcats = { "exp": "enable textfile expansion; see --help-exp", "exp_md": "placeholders to expand in markdown files; see --help", "exp_lg": "placeholders to expand in prologue/epilogue; see --help", + "txt_eol=lf": "enable EOL conversion when writing docs (LF or CRLF)", }, "tailing": { "notail": "disable ?tail (download a growing file continuously)", diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 3da299c7..e1c91c51 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -62,6 +62,7 @@ from .util import ( alltrace, atomic_move, b64dec, + eol_conv, exclude_dotfiles, formatdate, fsenc, @@ -3679,6 +3680,9 @@ class HttpCli(object): if p_field != "body": raise Pebkac(400, "expected body, got {}".format(p_field)) + if "txt_eol" in vfs.flags: + p_data = eol_conv(p_data, vfs.flags["txt_eol"]) + xbu = vfs.flags.get("xbu") if xbu: if not runhook( diff --git a/copyparty/util.py b/copyparty/util.py index 15b1924b..588028ab 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -2982,6 +2982,18 @@ def justcopy( return tlen, "checksum-disabled", "checksum-disabled" +def eol_conv( + fin: Generator[bytes, None, None], + conv: str +) -> Generator[bytes, None, None]: + crlf = conv.lower() == "crlf" + for buf in fin: + buf = buf.replace(b"\r", b"") + if crlf: + buf = buf.replace(b"\n", b"\r\n") + yield buf + + def hashcopy( fin: Generator[bytes, None, None], fout: Union[typing.BinaryIO, typing.IO[Any]], diff --git a/tests/util.py b/tests/util.py index 7b4ad2aa..5968215a 100644 --- a/tests/util.py +++ b/tests/util.py @@ -164,7 +164,7 @@ class Cfg(Namespace): ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" ka.update(**{k: 0 for k in ex.split()}) - ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles unlist vname xff_src zipmaxt R RS SR" + ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR" ka.update(**{k: "" for k in ex.split()}) ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner" From 13499d2846eb48b40fe6de93d4c7a7a90545db03 Mon Sep 17 00:00:00 2001 From: icxes <dev.null@need.moe> Date: Thu, 7 Aug 2025 22:42:33 +0300 Subject: [PATCH 50/66] remove prisonparty-user.service there is no real point to a prisonparty user service, as chroot requires root --- contrib/systemd/prisonparty-user.service | 33 ------------------------ 1 file changed, 33 deletions(-) delete mode 100644 contrib/systemd/prisonparty-user.service diff --git a/contrib/systemd/prisonparty-user.service b/contrib/systemd/prisonparty-user.service deleted file mode 100644 index e0aaeaf8..00000000 --- a/contrib/systemd/prisonparty-user.service +++ /dev/null @@ -1,33 +0,0 @@ -# this will start `/usr/bin/copyparty` -# in a chroot, preventing accidental access elsewhere, -# and read copyparty config from `$HOME/.config/copyparty.conf` -# -# expose additional filesystem locations to copyparty -# by listing them between the last `%u` and `--` -# -# unless you add -q to disable logging, you may want to remove the -# following line to allow buffering (slightly better performance): -# Environment=PYTHONUNBUFFERED=x - -[Unit] -Description=copyparty file server - -[Service] -Type=notify -SyslogIdentifier=prisonparty -WorkingDirectory=/var/lib/copyparty-jail -Environment=PYTHONUNBUFFERED=x -Environment=PRTY_CONFIG=%h/.config/copyparty/copyparty.conf -ExecReload=/bin/kill -s USR1 $MAINPID - -# ensure there is a config -ExecStartPre=/bin/bash -c 'if [[ ! -f %h/.config/copyparty/copyparty.conf ]]; then mkdir -p %h/.config/copyparty; cp /etc/copyparty/copyparty.conf %h/.config/copyparty/copyparty.conf; fi' - -# run copyparty -ExecStart=/bin/bash /usr/bin/prisonparty /var/lib/copyparty-jail %u %u \ - %h/.config/copyparty \ - -- \ - /usr/bin/python3 /usr/bin/copyparty - -[Install] -WantedBy=default.target From 3c42a34f7b43bdb17ba40432c3a493aedbaf5a88 Mon Sep 17 00:00:00 2001 From: icxes <dev.null@need.moe> Date: Thu, 7 Aug 2025 22:47:46 +0300 Subject: [PATCH 51/66] update PKGBUILD; remove prisonparty user service --- contrib/package/arch/PKGBUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/package/arch/PKGBUILD b/contrib/package/arch/PKGBUILD index c6dc4687..2673ec2a 100644 --- a/contrib/package/arch/PKGBUILD +++ b/contrib/package/arch/PKGBUILD @@ -43,7 +43,6 @@ package() { install -Dm644 "contrib/systemd/${pkgname}@.service" "${pkgdir}/usr/lib/systemd/system/${pkgname}@.service" install -Dm644 "contrib/systemd/${pkgname}-user.service" "${pkgdir}/usr/lib/systemd/user/${pkgname}.service" install -Dm644 "contrib/systemd/prisonparty@.service" "${pkgdir}/usr/lib/systemd/system/prisonparty@.service" - install -Dm644 "contrib/systemd/prisonparty-user.service" "${pkgdir}/usr/lib/systemd/user/prisonparty.service" install -Dm644 "contrib/systemd/index.md" "${pkgdir}/var/lib/${pkgname}-jail/README.md" install -Dm644 "LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } From 346515ccf17086392ef0440cad686a4065b6a54c Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 20:29:44 +0000 Subject: [PATCH 52/66] add optional username login; closes #511 --- README.md | 10 ++++++++++ copyparty/__main__.py | 6 +++++- copyparty/authsrv.py | 11 +++++++++++ copyparty/ftpd.py | 7 ++++++- copyparty/httpcli.py | 14 ++++++++++++++ copyparty/pwhash.py | 4 ++++ copyparty/util.py | 3 +-- copyparty/web/splash.html | 5 +++++ copyparty/web/splash.js | 2 +- tests/util.py | 2 +- 10 files changed, 58 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 39bd932f..e063e4af 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,7 @@ upgrade notes * can I link someone to a password-protected volume/file by including the password in the URL? * yes, by adding `?pw=hunter2` to the end; replace `?` with `&` if there are parameters in the URL already, meaning it contains a `?` near the end + * if you have enabled `--accounts` then do `?pw=username:password` instead * how do I stop `.hist` folders from appearing everywhere on my HDD? * by default, a `.hist` folder is created inside each volume for the filesystem index, thumbnails, audio transcodes, and markdown document history. Use the `--hist` global-option or the `hist` volflag to move it somewhere else; see [database location](#database-location) @@ -1016,6 +1017,7 @@ a feed example: https://cd.ocv.me/a/d2/d22/?rss&fext=mp3 url parameters: * `pw=hunter2` for password auth + * if you enabled `--usernames` then do `pw=username:password` instead * `recursive` to also include subfolders * `title=foo` changes the feed title (default: folder name) * `fext=mp3,opus` only include mp3 and opus files (default: all) @@ -1301,6 +1303,7 @@ an FTP server can be started using `--ftp 3921`, and/or `--ftps` for explicit T * if you enable both `ftp` and `ftps`, the port-range will be divided in half * some older software (filezilla on debian-stable) cannot passive-mode with TLS * login with any username + your password, or put your password in the username field + * unless you enabled `--usernames` some recommended FTP / FTPS clients; `wark` = example password: * https://winscp.net/eng/download.php @@ -1318,6 +1321,7 @@ click the [connect](http://127.0.0.1:3923/?hc) button in the control-panel to se general usage: * login with any username + your password, or put your password in the username field (password field can be empty/whatever) + * unless you enabled `--usernames` on macos, connect from finder: * [Go] -> [Connect to Server...] -> http://192.168.123.1:3923/ @@ -1333,6 +1337,7 @@ using the GUI (winXP or later): * rightclick [my computer] -> [map network drive] -> Folder: `http://192.168.123.1:3923/` * on winXP only, click the `Sign up for online storage` hyperlink instead and put the URL there * providing your password as the username is recommended; the password field can be anything or empty + * unless you enabled `--usernames` the webdav client that's built into windows has the following list of bugs; you can avoid all of these by connecting with rclone instead: * win7+ doesn't actually send the password to the server when reauthenticating after a reboot unless you first try to login with an incorrect password and then switch to the correct password @@ -1390,6 +1395,7 @@ some **BIG WARNINGS** specific to SMB/CIFS, in decreasing importance: * the smb backend is not fully integrated with vfs, meaning there could be security issues (path traversal). Please use `--smb-port` (see below) and [prisonparty](./bin/prisonparty.sh) or [bubbleparty](./bin/bubbleparty.sh) * account passwords work per-volume as expected, and so does account permissions (read/write/move/delete), but `--smbw` must be given to allow write-access from smb * [shadowing](#shadowing) probably works as expected but no guarantees +* not compatible with pw-hashing or `--usernames` and some minor issues, * clients only see the first ~400 files in big folders; @@ -2506,6 +2512,8 @@ you can provide passwords using header `PW: hunter2`, cookie `cppwd=hunter2`, ur > for basic-authentication, all of the following are accepted: `password` / `whatever:password` / `password:whatever` (the username is ignored) +* unless you've enabled `--usernames`, then it's `PW: usr:pwd`, cookie `cppwd=usr:pwd`, url-param `?pw=usr:pwd` + NOTE: curl will not send the original filename if you use `-T` combined with url-params! Also, make sure to always leave a trailing slash in URLs unless you want to override the filename @@ -2721,6 +2729,8 @@ when generating hashes using `--ah-cli` for docker or systemd services, make sur * inspecting the generated salt using `--show-ah-salt` in copyparty service configuration * setting the same `--ah-salt` in both environments +> ⚠️ if you have enabled `--usernames` then provide the password as `username:password` when hashing it, for example `ed:hunter2` + ## https diff --git a/copyparty/__main__.py b/copyparty/__main__.py index d0fc325e..2b55b058 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -918,6 +918,9 @@ def get_sects(): copyparty will also hash and print any passwords that are non-hashed (password which do not start with '+') and then terminate afterwards + if you have enabled --accounts then the password + must be provided as username:password for hashing + \033[36m--ah-alg\033[0m specifies the hashing algorithm and a list of optional comma-separated arguments: @@ -1002,6 +1005,7 @@ def add_general(ap, nc, srvname): ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]") ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts") ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]") + ap2.add_argument("--usernames", action="store_true", help="require username and password for login; default is just password") ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)") ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m") ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]") @@ -1393,7 +1397,7 @@ def add_logging(ap): ap2.add_argument("--no-voldump", action="store_true", help="do not list volumes and permissions on startup") ap2.add_argument("--log-utc", action="store_true", help="do not use local timezone; assume the TZ env-var is UTC (tiny bit faster)") ap2.add_argument("--log-tdec", metavar="N", type=int, default=3, help="timestamp resolution / number of timestamp decimals") - ap2.add_argument("--log-badpwd", metavar="N", type=int, default=1, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed") + ap2.add_argument("--log-badpwd", metavar="N", type=int, default=2, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed") ap2.add_argument("--log-conn", action="store_true", help="debug: print tcp-server msgs") ap2.add_argument("--log-htp", action="store_true", help="debug: print http-server threadpool scaling") ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 9c52f046..0f1c94f9 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -2642,6 +2642,8 @@ class AuthSrv(object): self.re_pwd = None pwds = [re.escape(x) for x in self.iacct.keys()] pwds.extend(list(self.sesa)) + if self.args.usernames: + pwds.extend([x.split(":", 1)[1] for x in pwds if ":" in x]) if pwds: if self.ah.on: zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)" @@ -2942,6 +2944,9 @@ class AuthSrv(object): t = "minimum password length: %d characters" return False, t % (self.args.chpw_len,) + if self.args.usernames: + pw = "%s:%s" % (uname, pw) + hpw = self.ah.hash(pw) if self.ah.on else pw if hpw == self.acct[uname]: @@ -3033,6 +3038,12 @@ class AuthSrv(object): self.log("chpw: " + msg, 6) def setup_pwhash(self, acct: dict[str, str]) -> None: + if self.args.usernames: + for uname, pw in list(acct.items())[:]: + if pw.startswith("+") and len(pw) == 33: + continue + acct[uname] = "%s:%s" % (uname, pw) + self.ah = PWHash(self.args) if not self.ah.on: if self.args.ah_cli or self.args.ah_gen: diff --git a/copyparty/ftpd.py b/copyparty/ftpd.py index bace7d28..004fb492 100644 --- a/copyparty/ftpd.py +++ b/copyparty/ftpd.py @@ -83,7 +83,12 @@ class FtpAuth(DummyAuthorizer): uname = "*" if username != "anonymous": uname = "" - for zs in (password, username): + if args.usernames: + alts = ["%s:%s" % (username, password)] + else: + alts = password, username + + for zs in alts: zs = asrv.iacct.get(asrv.ah.hash(zs), "") if zs: uname = zs diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index e1c91c51..cb061ac2 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -2937,12 +2937,16 @@ class HttpCli(object): def handle_chpw(self) -> bool: assert self.parser # !rm + if self.args.usernames: + self.parser.require("uname", 64) pwd = self.parser.require("pw", 64) self.parser.drop() ok, msg = self.asrv.chpw(self.conn.hsrv.broker, self.uname, pwd) if ok: self.cbonk(self.conn.hsrv.gpwc, pwd, "pw", "too many password changes") + if self.args.usernames: + pwd = "%s:%s" % (self.uname, pwd) ok, msg = self.get_pwd_cookie(pwd) if ok: msg = "new password OK" @@ -2955,6 +2959,13 @@ class HttpCli(object): def handle_login(self) -> bool: assert self.parser # !rm + if self.args.usernames: + try: + un = self.parser.require("uname", 256) + except: + un = "" + else: + un = "" pwd = self.parser.require("cppwd", 64) try: uhash = self.parser.require("uhash", 256) @@ -2965,6 +2976,9 @@ class HttpCli(object): if not pwd: raise Pebkac(422, "password cannot be blank") + if un: + pwd = "%s:%s" % (un, pwd) + dst = self.args.SRS if self.vpath: dst += quotep(self.vpaths) diff --git a/copyparty/pwhash.py b/copyparty/pwhash.py index ebbd78f3..d4455ca8 100644 --- a/copyparty/pwhash.py +++ b/copyparty/pwhash.py @@ -147,6 +147,10 @@ class PWHash(object): def cli(self) -> None: import getpass + if self.args.usernames: + t = "since you have enabled --usernames, please provide username:password" + print(t) + while True: try: p1 = getpass.getpass("password> ") diff --git a/copyparty/util.py b/copyparty/util.py index 588028ab..b5a2c45e 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -2983,8 +2983,7 @@ def justcopy( def eol_conv( - fin: Generator[bytes, None, None], - conv: str + fin: Generator[bytes, None, None], conv: str ) -> Generator[bytes, None, None]: crlf = conv.lower() == "crlf" for buf in fin: diff --git a/copyparty/web/splash.html b/copyparty/web/splash.html index 8dd56bab..4363efd2 100644 --- a/copyparty/web/splash.html +++ b/copyparty/web/splash.html @@ -120,7 +120,12 @@ <div> <form id="lf" method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}"> <input type="hidden" id="la" name="act" value="login" /> + {% if this.args.usernames %} + <input type="text" id="lu" name="uname" placeholder=" username" size="12" /> + <input type="password" id="lp" name="cppwd" placeholder=" password" size="12" /> + {% else %} <input type="password" id="lp" name="cppwd" placeholder=" password" /> + {% endif %} <input type="hidden" name="uhash" id="uhash" value="x" /> <input type="submit" id="ls" value="login" /> {% if chpw %} diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 1a24beb2..52e666f3 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -416,7 +416,7 @@ try { catch (ex) { } tt.init(); -var o = QS('input[name="cppwd"]'); +var o = QS('input[name="uname"]') || QS('input[name="cppwd"]'); if (!ebi('c') && o.offsetTop + o.offsetHeight < window.innerHeight) o.focus(); diff --git a/tests/util.py b/tests/util.py index 5968215a..d3884ca9 100644 --- a/tests/util.py +++ b/tests/util.py @@ -143,7 +143,7 @@ class Cfg(Namespace): def __init__(self, a=None, v=None, c=None, **ka0): ka = {} - ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_fnugg no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" + ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_fnugg no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe usernames vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs" ka.update(**{k: False for k in ex.split()}) ex = "dav_inf dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash see_dots plain_ip" From 1b71294aab0bfa4be10a71abacc84a397a6d78dc Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 20:30:09 +0000 Subject: [PATCH 53/66] close #387 --- copyparty/up2k.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 785d0a4f..b233cecb 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -375,11 +375,12 @@ class Up2k(object): if ineed == ihash or not ineed: continue + poke = job["poke"] zt = ( ineed / ihash, job["size"], - int(job["t0c"]), - int(job["poke"]), + int(job.get("t0c", poke)), + int(poke), djoin(vtop, job["prel"], job["name"]), ) ret.append(zt) From d9e3f998d1f5b508f7b57782d44ce43f9dd75e55 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 20:53:25 +0000 Subject: [PATCH 54/66] fix zipmaxu (it did nothing) --- copyparty/httpcli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index cb061ac2..73af0df7 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -4667,7 +4667,9 @@ class HttpCli(object): else: fn = self.host.split(":")[0] - if vn.flags.get("zipmax") and (not self.uname or not "zipmaxu" in vn.flags): + if vn.flags.get("zipmax") and not ( + vn.flags.get("zipmaxu") and self.uname != "*" + ): maxs = vn.flags.get("zipmaxs_v") or 0 maxn = vn.flags.get("zipmaxn_v") or 0 nf = 0 From 1bf23fabc6838c79bd7a95b6c97661e16504e57d Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 20:59:41 +0000 Subject: [PATCH 55/66] unames: fix shares --- copyparty/httpcli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 73af0df7..402d623f 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -2959,9 +2959,11 @@ class HttpCli(object): def handle_login(self) -> bool: assert self.parser # !rm - if self.args.usernames: + if self.args.usernames and not ( + self.args.shr and self.vpath.startswith(self.args.shr1) + ): try: - un = self.parser.require("uname", 256) + un = self.parser.require("uname", 64) except: un = "" else: From 36ab323d084d78491814ead1c71af5996ae249d4 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 21:26:59 +0000 Subject: [PATCH 56/66] sfx: simplify (remove bruteforce packing) --- scripts/make-sfx.sh | 21 ++++++--------------- scripts/rls.sh | 29 +---------------------------- 2 files changed, 7 insertions(+), 43 deletions(-) diff --git a/scripts/make-sfx.sh b/scripts/make-sfx.sh index deb7bee0..a1ee1a06 100755 --- a/scripts/make-sfx.sh +++ b/scripts/make-sfx.sh @@ -74,7 +74,6 @@ gtar=$(command -v gtar || command -v gnutar) || true sed() { gsed "$@"; } find() { gfind "$@"; } sort() { gsort "$@"; } - shuf() { gshuf "$@"; } nproc() { gnproc; } sha1sum() { shasum "$@"; } unexpand() { gunexpand "$@"; } @@ -157,9 +156,9 @@ stamp=$( done | sort | tail -n 1 | sha1sum | cut -c-16 ) -rm -rf sfx$CSN/* -mkdir -p sfx$CSN build -cd sfx$CSN +rm -rf sfx/* +mkdir -p sfx build +cd sfx tmpdir="$( printf '%s\n' "$TMPDIR" /tmp | @@ -395,7 +394,7 @@ ts=$(date -u +%s) hts=$(date -u +%Y-%m%d-%H%M%S) # --date=@$ts (thx osx) mkdir -p ../dist -sfx_out=../dist/copyparty-sfx$CSN +sfx_out=../dist/copyparty-sfx echo cleanup find -name '*.pyc' -delete @@ -554,7 +553,7 @@ gzres() { } -zdir="$tmpdir/cpp-mksfx$CSN" +zdir="$tmpdir/cpp-mksfx" [ -e "$zdir/$stamp" ] || rm -rf "$zdir" mkdir -p "$zdir" echo a > "$zdir/$stamp" @@ -583,15 +582,7 @@ echo gen tarlist for d in copyparty partftpy magic j2 py2 py37 ftp; do find $d -type f || true; done | # strip_hints sed -r 's/(.*)\.(.*)/\2 \1/' | LC_ALL=C sort | sed -r 's/([^ ]*) (.*)/\2.\1/' | grep -vE '/list1?$' > list1 - -for n in {1..50}; do - (grep -vE '\.gz$' list1; grep -E '\.gz$' list1 | (shuf||gshuf) ) >list || true - s=$( (sha1sum||shasum) < list | cut -c-16) - grep -q $s "$zdir/h" 2>/dev/null && continue - echo $s >> "$zdir/h" - break -done -[ $n -eq 50 ] && exit +(grep -vE '\.gz$' list1; grep -E '\.gz$' list1) >list echo creating tar tar -cf tar "${targs[@]}" --numeric-owner -T list diff --git a/scripts/rls.sh b/scripts/rls.sh index 613b53e0..e72eef0d 100755 --- a/scripts/rls.sh +++ b/scripts/rls.sh @@ -32,11 +32,7 @@ v=$1 rm -f ../dist/copyparty-sfx* shift ./make-sfx.sh "$@" -f=../dist/copyparty-sfx -[ -e $f.py ] && s= || s=-gz -# TODO: the -gz suffix is gone, can drop all the $s stuff probably - -$f$s.py --version >/dev/null +../dist/copyparty-sfx.py --version >/dev/null while [ "$1" ]; do case "$1" in @@ -46,27 +42,4 @@ while [ "$1" ]; do shift done -[ $parallel -gt 1 ] && { - printf '\033[%s' s 2r H "0;1;37;44mbruteforcing sfx size -- press enter to terminate" K u "7m $* " K $'27m\n' - trap "rm -f .sfx-run; printf '\033[%s' s r u" INT TERM EXIT - touch .sfx-run - min=99999999 - for ((a=0; a<$parallel; a++)); do - while [ -e .sfx-run ]; do - CSN=$a ./make-sfx.sh re "$@" - sz=$(wc -c <$f$a$s.py | awk '{print$1}') - [ $sz -ge $min ] && continue - mv $f$a$s.py $f$s.py.$sz - min=$sz - done & - done - read - exit -} - -while true; do - mv $f$s.py $f$s.$(wc -c <$f$s.py | awk '{print$1}').py - ./make-sfx.sh re "$@" -done - # git tag -d v$v; git push --delete origin v$v From 33497e6b11b41c82c1fc5694a46d80f0c0b9b417 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 21:28:56 +0000 Subject: [PATCH 57/66] sfx: add english-only --- README.md | 2 ++ scripts/rls.sh | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/README.md b/README.md index e063e4af..476d8ddc 100644 --- a/README.md +++ b/README.md @@ -2848,6 +2848,8 @@ these are standalone programs and will never be imported / evaluated by copypart the self-contained "binary" (recommended!) [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course +if you only need english, [copyparty-en.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-en.py) is the same thing but smaller + you can reduce the sfx size by repacking it; see [./docs/devnotes.md#sfx-repack](./docs/devnotes.md#sfx-repack) diff --git a/scripts/rls.sh b/scripts/rls.sh index e72eef0d..767ca2de 100755 --- a/scripts/rls.sh +++ b/scripts/rls.sh @@ -33,6 +33,7 @@ rm -f ../dist/copyparty-sfx* shift ./make-sfx.sh "$@" ../dist/copyparty-sfx.py --version >/dev/null +mv ../dist/copyparty-{sfx,int}.py while [ "$1" ]; do case "$1" in @@ -42,4 +43,8 @@ while [ "$1" ]; do shift done +./make-sfx.sh re lang eng "$@" +mv ../dist/copyparty-{sfx,en}.py +mv ../dist/copyparty-{int,sfx}.py + # git tag -d v$v; git push --delete origin v$v From a98360f2134362b1c377f10545216bcc023d5917 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 21:30:55 +0000 Subject: [PATCH 58/66] copyparty.exe: update to python 3.13.6 --- scripts/pyinstaller/deps.sha512 | 2 +- scripts/pyinstaller/notes.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pyinstaller/deps.sha512 b/scripts/pyinstaller/deps.sha512 index b698b95a..1d324c0e 100644 --- a/scripts/pyinstaller/deps.sha512 +++ b/scripts/pyinstaller/deps.sha512 @@ -30,5 +30,5 @@ a726fb46cce24f781fc8b55a3e6dea0a884ebc3b2b400ea74aa02333699f4955a5dc1e2ec5927ac7 3e39ea6e16b502d99a2e6544579095d0f7c6097761cd85135d5e929b9dec1b32e80669a846f94ee8c2cca9be2f5fe728625d09453988864c04e16bb8445c3f91 pillow-11.3.0-cp313-cp313-win_amd64.whl 59fbbcae044f4ee73d203ac74b553b27bfad3e6b2f3fb290fd3f8774753c6b545176b6b3399c240b092d131d152290ce732750accd962dc1e48e930be85f5e53 pyinstaller-6.14.1-py3-none-win_amd64.whl fc6f3e144c5f5b662412de07cb8bf0c2eb3b3be21d19ec448aef3c4244d779b9ab8027fd67a4871e6e13823b248ea0f5a7a9241a53aef30f3b51a6d3cb5bdb3f pyinstaller_hooks_contrib-2025.5-py3-none-any.whl -2c7a52e223b8186c21009d3fa5ed6a856d8eb4ef3b98f5d24c378c6a1afbfa1378bd7a51d6addc500e263d7989efb544c862bf920055e740f137c702dfd9d18b python-3.13.5-amd64.exe +3c37ea72ab062f65116a5faaaccbaa960a971797c78dbe6a504f41e562b018e7f28924647b5577fdb4fedfa61ffe0f1153842a8585f93b0332ed4d97905f6609 python-3.13.6-amd64.exe 2a0420f7faaa33d2132b82895a8282688030e939db0225ad8abb95a47bdb87b45318f10985fc3cee271a9121441c1526caa363d7f2e4a4b18b1a674068766e87 setuptools-80.9.0-py3-none-any.whl diff --git a/scripts/pyinstaller/notes.txt b/scripts/pyinstaller/notes.txt index 61f76fa4..44cebd10 100644 --- a/scripts/pyinstaller/notes.txt +++ b/scripts/pyinstaller/notes.txt @@ -40,7 +40,7 @@ fns=( pillow-11.3.0-cp313-cp313-win_amd64.whl pyinstaller-6.14.1-py3-none-win_amd64.whl pyinstaller_hooks_contrib-2025.5-py3-none-any.whl - python-3.13.5-amd64.exe + python-3.13.6-amd64.exe setuptools-80.9.0-py3-none-any.whl ) [ $w7 ] && fns+=( From c955658332d12b29525b4e392b9467a66832132c Mon Sep 17 00:00:00 2001 From: Jakub Pelc <jakub.pelc@seznam.cz> Date: Thu, 7 Aug 2025 23:48:32 +0200 Subject: [PATCH 59/66] Czech translation (#471) * added czech translation * add czech translations to splash --------- Signed-off-by: Jakub Pelc <jakub.pelc@seznam.cz> Signed-off-by: ed <s@ocv.me> Co-authored-by: ed <s@ocv.me> --- copyparty/web/browser.js | 635 ++++++++++++++++++++++++++++++++++++++- copyparty/web/splash.js | 41 +++ 2 files changed, 675 insertions(+), 1 deletion(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 0563d8ee..1b95ced2 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -1894,6 +1894,639 @@ var Ls = { "lang_set": "刷新以使更改生效?", }, + "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í)"], + ] + ], + + "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 ", + "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<code>foo bar</code> = musí obsahovat jak «foo» tak «bar»,$N<code>foo -bar</code> = musí obsahovat «foo» ale ne «bar»,$N<code>^yana .opus$</code> = začíná na «yana» a je to «opus» soubor$N<code>"try unite"</code> = obsahuje přesně «try unite»$N$Nformát data je iso-8601, jako$N<code>2009-12-31</code> nebo <code>2020-09-12 23:30:00</code>", + "ot_unpost": "unpost: smazat vaše nedávné nahrání nebo zrušit nedokončené", + "ot_bup": "bup: základní nahrávač, podporuje i netscape 4.0", + "ot_mkdir": "mkdir: vytvořit nový adresář", + "ot_md": "new-md: vytvořit nový markdown dokument", + "ot_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ž [🎈]  (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ž [🎈]  (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ý markdown dokument", + "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 <small>(pak je vložit někam jinam)</small>$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ší", + "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 <em>hashování</em> a odhadovaný čas do dokončení", + "ut_etau": "průměrná rychlost <em>nahrávání</em> a odhadovaný čas do dokončení", + "ut_etat": "průměrná <em>celková</em> 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_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", + + "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_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>"má to stejnou velikost souboru na serveru?"</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 "nahrát" 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í (<code>,sorthref</code>) zahrnout do media-URL. Nastavení na 0 bude také ignorovat pravidla řazení zahrnutá v media odkazech při kliknutí na ně", + + "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  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  (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 opus\">flac", + "mt_caac": "převést aac / m4a na opus\">aac", + "mt_coth": "převést všechny ostatní (ne mp3) na opus\">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 <code>0</code> = standardní 100% hlasitost (nezměněno)$N$Nwidth <code>1  </code> = standardní stereo (nezměněno)$Nwidth <code>0.5</code> = 50% levý-pravý crossfeed$Nwidth <code>0  </code> = mono$N$Nboost <code>-0.8</code> & width <code>10</code> = 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/Cancel</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 CANCEL 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><>:"\\|?*</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 <code>(1)</code> a <code>(2)</code> atd.", + "fr_fmt": "inspirováno foobar2000:$N<code>(title)</code> je nahrazeno názvem skladby,$N<code>[(artist) - ](title)</code> přeskočí [tuto] část pokud je umělec prázdný$N<code>$lpad((tn),2,0)</code> 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_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ý pro přeskočení:", + "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ý pro přeskočení:", + "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_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", + + "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   ( pro vyjmutí / kopírování / mazání / ... )$NKlávesová zkratka: S\">výběr", + "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<em>když aktivní: dvojklik na soubor / složku pro otevření</em>$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   (oddělené mezerami)", + "s_f1": "název obsahuje   (negace s -ne)", + "s_t1": "tagy obsahují   (^=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:  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:   <b>{0}</b> dokončeno,   <b>{1}</b> selhalo,   <b>{2}</b> nahrává se,   <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>Cancel/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!  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  <code>mt</code>  v  <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> 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> 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", + + "lang_set": "obnovit stránku, aby se změna projevila?", + }, "deu": { "tt": "Deutsch", @@ -6927,7 +7560,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"]; +var LANGS = ["eng", "nor", "chi", "cze", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"]; if (window.langmod) langmod(); diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 52e666f3..54eafc71 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -94,6 +94,47 @@ var Ls = { "af1": "显示最近上传的文件", //m "ag1": "查看已知 IdP 用户", //m }, + "cze": { + "a1": "obnovit", + "b1": "ahoj cizinče   <small>(nejsi přihlášen)</small>", + "c1": "odhlásit se", + "d1": "vypsat zásobníku", // TLNote: "d2" is the tooltip for this button + "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", // TLNote: "j1" explains what k304 is + "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:", + "m1": "vítej zpět,", // TLNote: "welcome back, USERNAME" + "n1": "404 nenalezeno  ┐( ´ -`)┌", + "o1": 'nebo možná nemáš přístup -- zkus heslo nebo <a href="' + SR + '/?h">jdi domů</a>', + "p1": "403 zakázáno  ~┻━┻", + "q1": 'použij heslo nebo <a href="' + SR + '/?h">jdi domů</a>', + "r1": "jdi domů", + ".s1": "znovu prohledat", + "t1": "akce", // TLNote: this is the header above the "rescan" buttons + "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í", // TLNote: shows the list of folders that the user has decided to share + "z1": "odblokovat toto sdílení:", // TLNote: the password prompt to see a hidden share + "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?   <small>(Du bist nicht angemeldet)</small>", From f0b1c82b44b1ef522840060dc391f73280ecfb0c Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 22:09:11 +0000 Subject: [PATCH 60/66] i18n: support czech declensions --- copyparty/web/browser.js | 10 +++++----- copyparty/web/util.js | 10 +++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 1b95ced2..986feb78 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -2247,10 +2247,10 @@ var Ls = { "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 CANCEL 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_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í", @@ -7580,7 +7580,7 @@ for (var a = 0; a < LANGS.length; a++) { t2 = Ls[LANGS[i2]]; for (var k in t1) - if (!t2[k]) { + if (!t2[k] && !/^ht_.5$/.test(k)) { console.log("E missing TL", LANGS[i2], k); t2[k] = t1[k]; } diff --git a/copyparty/web/util.js b/copyparty/web/util.js index e58e7cca..489cd416 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -1020,9 +1020,13 @@ function lhumantime(v) { if (!L || tp.length < 2 || tp[1].indexOf('$') + 1) return t; - var ret = ''; - for (var a = 0; a < tp.length; a += 2) - ret += tp[a] + ' ' + L['ht_' + tp[a + 1] + (tp[a]==1?1:2)] + L.ht_and; + var u, n, ret = ''; + for (var a = 0; a < tp.length; a += 2) { + n = tp[a]; + u = L.ht_h5 ? (n==1 ? 1 : (n>1&&n<5) ? 2 : 5) : + (n==1 ? 1 : 2); + ret += tp[a] + ' ' + L['ht_' + tp[a + 1] + u] + L.ht_and; + } return ret.slice(0, -L.ht_and.length); } From e9ecb2edc5378c9406064912772c6fb49c59eda7 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 22:13:52 +0000 Subject: [PATCH 61/66] v1.19.0 --- README.md | 2 +- copyparty/__main__.py | 2 +- copyparty/__version__.py | 6 +++--- docs/changelog.md | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 476d8ddc..8f470a50 100644 --- a/README.md +++ b/README.md @@ -437,7 +437,7 @@ upgrade notes * can I link someone to a password-protected volume/file by including the password in the URL? * yes, by adding `?pw=hunter2` to the end; replace `?` with `&` if there are parameters in the URL already, meaning it contains a `?` near the end - * if you have enabled `--accounts` then do `?pw=username:password` instead + * if you have enabled `--usernames` then do `?pw=username:password` instead * how do I stop `.hist` folders from appearing everywhere on my HDD? * by default, a `.hist` folder is created inside each volume for the filesystem index, thumbnails, audio transcodes, and markdown document history. Use the `--hist` global-option or the `hist` volflag to move it somewhere else; see [database location](#database-location) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 2b55b058..e87fe487 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -918,7 +918,7 @@ def get_sects(): copyparty will also hash and print any passwords that are non-hashed (password which do not start with '+') and then terminate afterwards - if you have enabled --accounts then the password + if you have enabled --usernames then the password must be provided as username:password for hashing \033[36m--ah-alg\033[0m specifies the hashing algorithm and a diff --git a/copyparty/__version__.py b/copyparty/__version__.py index 30bd3fd6..3350f413 100644 --- a/copyparty/__version__.py +++ b/copyparty/__version__.py @@ -1,8 +1,8 @@ # coding: utf-8 -VERSION = (1, 18, 10) -CODENAME = "logtail" -BUILD_DT = (2025, 8, 4) +VERSION = (1, 19, 0) +CODENAME = "usernames" +BUILD_DT = (2025, 8, 7) S_VERSION = ".".join(map(str, VERSION)) S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT) diff --git a/docs/changelog.md b/docs/changelog.md index 3cc8bdf1..a3c0aaae 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,39 @@ +▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ +# 2025-0804-0013 `v1.18.10` idp speedboost + +## 🧪 new features + +* #426 add Dutch translation (thx @DeStilleGast!) 3798e19a +* #458 add Italian translation (thx @AOTREVAI!) a38e6e65 +* #456 transcode to flac/wav (thx @missaustraliana!) b469db3c b2d48c64 0d09fb68 +* #439 config-file can be provided through `PRTY_CONFIG` (thx @icxes!) 971360e9 +* #459 videos can become folder thumbnails 16bbcce5 +* add `--idp-cookie`, session-tickets for IdP auth (performance boost) f9502c3d + * useful when the IdP-server becomes a bottleneck + +## 🩹 bugfixes + +* #412 fix PUT-uploads into volumes with `nosub` volflag 47fa4a92 +* #435 ignore spurious exceptions from browser extensions 39e55824 +* #449 IPv6 QR-Code didn't include port 66a5bf36 +* #295 do not force `d2d` in blank vfs (introduced in v1.18.3) 848315c0 + +## 🔧 other changes + +* #440 improved finnish translation (thx @icxes!) a68d5b03 +* point to the `-nc` option in the "at max connections" warning 153d240d +* the play-button now indicates "play-as-audio" for video-files 40d56bb3 +* docs: + * #411 improve password-hashing instructions (thx @chinponya!) c69c7c8a + * #429 improve `--cert` helptext (thx @kzshantonu!) 7e3825f8 + * #413 copyparty is Wii Internet Channel compatible! (thx @techflashYT!) 50f16293 + * #461 how to use groups without IdP e85a7107 + * mention that WebDAV and OpenGraph are incompatible by default (and how to fix that) 0bc1b8f7 + * #345 short explanation about the sfx in quickstart ae5eefc5 +* #398 pypi-package now has extra-group `all` 6eaf8af1 + + + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ # 2025-0801-2056 `v1.18.9` fix Denial-of-Service From 4eca4885f3d224c3c4b2c4e6e70e8923cbeaf147 Mon Sep 17 00:00:00 2001 From: ed <s@ocv.me> Date: Thu, 7 Aug 2025 22:43:08 +0000 Subject: [PATCH 62/66] update pkgs to 1.19.0 --- contrib/package/arch/PKGBUILD | 4 ++-- contrib/package/makedeb-mpr/PKGBUILD | 4 ++-- contrib/package/nix/copyparty/pin.json | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contrib/package/arch/PKGBUILD b/contrib/package/arch/PKGBUILD index 2673ec2a..e5896fd7 100644 --- a/contrib/package/arch/PKGBUILD +++ b/contrib/package/arch/PKGBUILD @@ -3,7 +3,7 @@ # NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead. pkgname=copyparty -pkgver="1.18.10" +pkgver="1.19.0" pkgrel=1 pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++" arch=("any") @@ -23,7 +23,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag ) source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") backup=("etc/${pkgname}/copyparty.conf" ) -sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99") +sha256sums=("179b027d51e4fe7ebdab2b18c07475d52c57e2ce69256292b157a8efacd82118") build() { cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web" diff --git a/contrib/package/makedeb-mpr/PKGBUILD b/contrib/package/makedeb-mpr/PKGBUILD index f16e5459..645623c0 100644 --- a/contrib/package/makedeb-mpr/PKGBUILD +++ b/contrib/package/makedeb-mpr/PKGBUILD @@ -2,7 +2,7 @@ pkgname=copyparty -pkgver=1.18.10 +pkgver=1.19.0 pkgrel=1 pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++" arch=("any") @@ -20,7 +20,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag ) source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz") backup=("/etc/${pkgname}.d/init" ) -sha256sums=("49c5fedf7619437bc0af125cb4e8360d9bda9d87ef45d6314d7acf163ab4cf99") +sha256sums=("179b027d51e4fe7ebdab2b18c07475d52c57e2ce69256292b157a8efacd82118") build() { cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web" diff --git a/contrib/package/nix/copyparty/pin.json b/contrib/package/nix/copyparty/pin.json index 70657f2c..c0d8c68a 100644 --- a/contrib/package/nix/copyparty/pin.json +++ b/contrib/package/nix/copyparty/pin.json @@ -1,5 +1,5 @@ { - "url": "https://github.com/9001/copyparty/releases/download/v1.18.10/copyparty-sfx.py", - "version": "1.18.10", - "hash": "sha256-2FdQ5aCwNdZ5Jy9mn8rr8g41+QHT5tsEc+GeAKvhGeg=" + "url": "https://github.com/9001/copyparty/releases/download/v1.19.0/copyparty-sfx.py", + "version": "1.19.0", + "hash": "sha256-9A+zPtkVtUuGHB/JJV3fhVtJderLUGxHqvuJQz0/1+Q=" } \ No newline at end of file From 0dd5987250274cc7006e9a1a355e388130d0e46f Mon Sep 17 00:00:00 2001 From: Vlad <vladislav.burzakovskij@satoshilabs.com> Date: Fri, 8 Aug 2025 09:53:50 +0200 Subject: [PATCH 63/66] add Ukrainian translations for control panel (#525) --- copyparty/web/browser.js | 2 +- copyparty/web/splash.js | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 986feb78..54029e9a 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -7087,7 +7087,7 @@ var Ls = { "ut_srch": "не завантажувати, а перевірити, чи файли вже $N існують на сервері (сканує всі папки, які ви можете читати)", "ut_par": "призупинити завантаження, встановивши 0$N$Nзбільшіть, якщо ваше з'єднання повільне / висока затримка$N$Nзалишіть 1 в локальній мережі або якщо HDD сервера є вузьким місцем", "ul_btn": "перетягніть файли / папки<br> (або клацніть сюди)", - "ul_btnu": "З А В А Н Т А Ж И Т И", + "ul_btnu": "ЗАВАНТАЖИТИ", "ul_btns": "П О Ш У К", "ul_hash": "хеш", diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 54eafc71..16d21185 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -385,6 +385,48 @@ var Ls = { "af1": "mostrar subidas recientes", "ag1": "mostrar usuarios IdP conocidos" }, + "ukr": { + "a1": "оновити", + "b1": "привітик, незнайомцю   <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": "авторизуйтесь для інших опцій:", + "m1": "з поверненням,", + "n1": "404 не знайдено  ┐( ´ -`)┌", + "o1": 'або у вас немає доступу -- спробуйте авторизуватися або <a href="' + SR + '/?h">повернутися на головну</a>', + "p1": "403 доступ заборонений  ~┻━┻", + "q1": 'авторизуйтесь або <a href="' + SR + '/?h">поверніться на головну</a>', + "r1": "повернутися на головну", + ".s1": "пересканувати", + "t1": "дія", + "u2": "час з останнього запису сервера$N( завантаження / перейменування / ... )$N$N17d = 17 днів$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": "приветик, незнакомец   <small>(вы не авторизованы)</small>", From f8a7c02f23996a1f14fc538d4cfcb04a44a86110 Mon Sep 17 00:00:00 2001 From: chamdim <94919340+chamdim@users.noreply.github.com> Date: Fri, 8 Aug 2025 10:54:11 +0300 Subject: [PATCH 64/66] Greek: fix typo (#528) Signed-off-by: chamdim <94919340+chamdim@users.noreply.github.com> --- copyparty/web/splash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index 16d21185..dc540fb4 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -222,7 +222,7 @@ var Ls = { "a1": "ανανέωση", "b1": "γεια σου ξένε!   <small>(δεν είσαι συνδεδεμένος)</small>", "c1": "αποσύνδεση", - "d1": "σωρός απορριμμάτων", + "d1": "λίστα διεργασιών", "d2": "εμφανίζει την κατάσταση όλων των ενεργών διεργασιών", "e1": "επαναφόρτωση του cfg", "e2": "φορτώνει ξανά τα αρχεία ρυθμίσεων (λογαριασμοί/τόμοι/volflags),$Nκαι κάνει επανεξέταση όλων των τόμων e2ds$N$Nσημείωση: οποιαδήποτε αλλαγή στις καθολικές ρυθμίσεις$Nαπαιτεί πλήρη επανεκκίνηση για να εφαρμοστεί", From bd514f066606d71e51a1914c3f07d070b7249ab3 Mon Sep 17 00:00:00 2001 From: chamdim <94919340+chamdim@users.noreply.github.com> Date: Fri, 8 Aug 2025 10:54:27 +0300 Subject: [PATCH 65/66] Greek: fix typos (#529) Signed-off-by: chamdim <94919340+chamdim@users.noreply.github.com> --- copyparty/web/browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 54029e9a..c9f9e70b 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -4005,7 +4005,7 @@ var Ls = { "ct_ttips": '◔ ◡ ◔">ℹ️ συμβουλές εργαλείων', "ct_thumb": 'σε προβολή πλέγματος, εναλλαγή εικονιδίων ή μικρογραφιών$NΠλήκτρο συντόμευσης: T">🖼️ μικρογραφίες', "ct_csel": 'χρησιμοποίησε CTRL και SHIFT για επιλογή αρχείων σε προβολή πλέγματος">επιλογή', - "ct_ihop": 'όταν η προβολή εικόνων κλείνει, κάνε scroll στο τελευταίο προβολόμενο αρχείο">g⮯', + "ct_ihop": 'όταν η προβολή εικόνων κλείνει, κάνε scroll στο τελευταίο προβαλλόμενο αρχείο">g⮯', "ct_dots": 'εμφάνιση κρυφών αρχείων (αν το επιτρέπει ο server)">dotfiles', "ct_qdel": 'όταν διαγράφεις αρχεία, ζήτα επιβεβαίωση μόνο μία φορά">γρήγορη διαγραφή', "ct_dir1st": 'ταξινόμηση φακέλων πριν από τα αρχεία">📁 πρώτα', @@ -4039,7 +4039,7 @@ var Ls = { "cft_bg": "χρώμα παρασκηνίου", "cdt_lim": "μέγιστος αριθμός αρχείων προς εμφάνιση σε ένα φάκελο", - "cdt_ask": "όταν φτάνεις στο τέλος,$Nαντί να φορτώσει περισσότερα αρχεία,$Nρώτα τι να κάνει", + "cdt_ask": "όταν φτάνεις στο τέλος,$Nαντί να φορτώσει περισσότερα αρχεία,$Nρωτά τι να κάνει", "cdt_hsort": "πόσους κανόνες ταξινόμησης (<code>,sorthref</code>) να συμπεριλάβει σε URLs πολυμέσων. Αν το βάλεις 0 αγνοεί και κανόνες ταξινόμησης στους συνδέσμους πολυμέσων", "tt_entree": "εμφάνιση navpane (δέντρο διαδρομών)$NΠλήκτρο συντόμευσης: B", From 3931bc27791658449f6dc3fc24e3a53d43d62a49 Mon Sep 17 00:00:00 2001 From: Kent Daleng <kent.daleng@nav.no> Date: Fri, 8 Aug 2025 22:54:24 +0200 Subject: [PATCH 66/66] =?UTF-8?q?legg=20=C3=A5t=20nynorskoversetjing=20(#5?= =?UTF-8?q?37)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * legg åt nynorskoversetjing, og fikser et par typos på bokmål også :) * add nno to splash, fix a few more stray typos * more til -> åt --------- Signed-off-by: Kent D <lolexplode@gmail.com> --- copyparty/web/browser.js | 640 ++++++++++++++++++++++++++++++++++++++- copyparty/web/splash.js | 42 +++ 2 files changed, 677 insertions(+), 5 deletions(-) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index c9f9e70b..70ee0acf 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -853,7 +853,7 @@ var Ls = { "cl_hcancel": "kolonne-skjuling avbrutt", "ct_grid": '田 ikoner', - "ct_ttips": 'hvis hjelpetekst ved å holde musen over ting">ℹ️ tips', + "ct_ttips": 'vis hjelpetekst ved å holde musen over ting">ℹ️ tips', "ct_thumb": 'vis miniatyrbilder istedenfor ikoner$NSnarvei: T">🖼️ bilder', "ct_csel": 'bruk tastene CTRL og SHIFT for markering av filer i ikonvisning">merk', "ct_ihop": 'bla ned til sist viste bilde når bildeviseren lukkes">g⮯', @@ -878,8 +878,8 @@ var Ls = { "cut_az": "last opp filer i alfabetisk rekkefølge, istedenfor minste-fil-først$N$Nalfabetisk kan gjøre det lettere å anslå om alt gikk bra, men er bittelitt tregere på fiber / LAN", - "cut_nag": "meldingsvarsel når opplastning er ferdig$N(kun on nettleserfanen ikke er synlig)", - "cut_sfx": "lydvarsel når opplastning er ferdig$N(kun on nettleserfanen ikke er synlig)", + "cut_nag": "meldingsvarsel når opplastning er ferdig$N(kun om nettleserfanen ikke er synlig)", + "cut_sfx": "lydvarsel når opplastning er ferdig$N(kun om nettleserfanen ikke er synlig)", "cut_mt": "raskere befaring ved å bruke hele CPU'en$N$Ndenne funksjonen anvender web-workers$Nog krever mer RAM (opptil 512 MiB ekstra)$N$Ngjør https 30% raskere, http 4.5x raskere\">mt", @@ -913,7 +913,7 @@ var Ls = { "mt_loop": "spill den samme sangen om og om igjen\">🔁", "mt_one": "spill kun én sang\">1️⃣", "mt_shuf": "sangene i hver mappe$Nspilles i tilfeldig rekkefølge\">🔀", - "mt_aplay": "forsøk å starte avspilling hvis linken du klikket på for å åpne nettsiden inneholder en sang-ID$N$Nhvis denne deaktiveres så vil heller ikke nettside-URLen bli oppdatert med sang-ID'er når musikk spilles, i tilfelle innstillingene skulle gå tapt og nettsiden lastes på ny\">a▶", + "mt_aplay": "forsøk å starte avspilling hvis linken du klikket på for å åpne nettsiden inneholder en sang-ID$N$Nhvis denne deaktiveres så vil heller ikke nettside-URL'en bli oppdatert med sang-ID'er når musikk spilles, i tilfelle innstillingene skulle gå tapt og nettsiden lastes på ny\">a▶", "mt_preload": "hent ned litt av neste sang i forkant,$Nslik at pausen i overgangen blir mindre\">forles", "mt_prescan": "ved behov, bla til neste mappe$Nslik at nettleseren lar oss$Nfortsette å spille musikk\">bla", "mt_fullpre": "hent ned hele neste sang, ikke bare litt:$N✅ skru på hvis nettet ditt er <b>ustabilt</b>,$N❌ skru av hvis nettet ditt er <b>tregt</b>\">full", @@ -5672,6 +5672,636 @@ var Ls = { "lang_set": "Vernieuw de pagina om de wijziging door te voeren?", }, + "nno": { + "tt": "Nynorsk", + + "cols": { + "c": "handlingsknappar", + "dur": "varigheit", + "q": "kvalitet / bitrate", + "Ac": "lydformat", + "Vc": "videoformat", + "Fmt": "format / innpakning", + "Ahash": "lydkontrollsum", + "Vhash": "videokontrollsum", + "Res": "oppløysing", + "T": "filtype", + "aq": "lydkvalitet / bitrate", + "vq": "videokvalitet / bitrate", + "pixfmt": "fargekoding / detaljnivå", + "resw": "horisontal oppløysing", + "resh": "vertikal oppløysing", + "chs": "lydkanaler", + "hz": "lydoppløsing" + }, + + "hks": [ + [ + "ymse", + ["ESC", "lukk saker og ting"], + + "filbehandlar", + ["G", "listevisning eller ikon"], + ["T", "miniatyrbilder på/av"], + ["⇧ A/D", "ikonstorleik"], + ["ctrl-K", "slett valde"], + ["ctrl-X", "klipp ut valde"], + ["ctrl-C", "kopiér åt utklippstavle"], + ["ctrl-V", "lim inn (flytt/kopiér)"], + ["Y", "last ned valde"], + ["F2", "endre namn på valde"], + + "filmarkering", + ["space", "markér fil"], + ["↑/↓", "flytt markør"], + ["ctrl ↑/↓", "flytt markør og scroll"], + ["⇧ ↑/↓", "velg forr./neste fil"], + ["ctrl-A", "velg alle filer / mapper"], + ], [ + "navigering", + ["B", "mappehierarki eller filsti"], + ["I/K", "forr./neste mappe"], + ["M", "eitt nivå opp (eller lukk)"], + ["V", "vis mapper eller tekstfiler"], + ["A/D", "panelstorleik"], + ], [ + "musikkspelar", + ["J/L", "forr./neste song"], + ["U/O", "hopp 10sek bak/fram"], + ["0..9", "hopp åt 0%..90%"], + ["P", "pause, eller start / fortsett"], + ["S", "marker spelande song"], + ["Y", "last ned song"], + ], [ + "bildevisar", + ["J/L, ←/→", "forr./neste bilde"], + ["Home/End", "første/siste bilde"], + ["F", "fullskjermvisning"], + ["R", "rotér åt høyre"], + ["⇧ R", "rotér åt venstre"], + ["S", "markér bilde"], + ["Y", "last ned bilde"], + ], [ + "videospelar", + ["U/O", "hopp 10sek bak/fram"], + ["P/K/Space", "pause / fortsett"], + ["C", "fortsett åt neste fil"], + ["V", "gjenta avspeling"], + ["M", "lyd av/på"], + ["[ og ]", "gjentaksintervall"], + ], [ + "dokumentvisar", + ["I/K", "forr./neste fil"], + ["M", "lukk tekstdokument"], + ["E", "redigér tekstdokument"], + ["S", "markér fil (for F2/ctrl-x/...)"], + ["Y", "last ned tekstfil"], + ] + ], + + "m_ok": "OK", + "m_ng": "Avbryt", + + "enable": "Aktiv", + "danger": "VARSKU", + "clipped": "kopiert åt utklippstavla", + + "ht_s1": "sekund", + "ht_s2": "sekund", + "ht_m1": "minutt", + "ht_m2": "minutt", + "ht_h1": "time", + "ht_h2": "timar", + "ht_d1": "dag", + "ht_d2": "dagar", + "ht_and": " og ", + + "goh": "kontrollpanel", + "gop": 'navigér åt mappa før den her">forr.', + "gou": 'navigér eitt nivå opp">opp', + "gon": 'navigér åt mappa etter den her">neste', + "logout": "Logg ut ", + "access": " åtgang", + "ot_close": "lukk reiskap", + "ot_search": "søk etter filer ved å angje filnamn, mappenamn, tid, storleik, eller metadata som songtittel / artist / osv.$N$N<code>foo bar</code> = inneheld båe «foo» og «bar»,$N<code>foo -bar</code> = innehold «foo» men ikkje «bar»,$N<code>^yana .opus$</code> = startar med «yana», filtype «opus»$N<code>"try unite"</code> = «try unite» eksakt$N$Ndatoformat er iso-8601, så f.eks.$N<code>2009-12-31</code> eller <code>2020-09-12 23:30:00</code>", + "ot_unpost": "unpost: slett filer som du nyleg har lastet opp; «angre-knappen»", + "ot_bup": "bup: tradisjonell / primitiv filopplasting,$N$Nfungerar i om lag samtlege nettlesarar", + "ot_mkdir": "mkdir: lag ei ny mappe", + "ot_md": "new-md: lag eit nytt markdown-dokument", + "ot_msg": "msg: send ein beskjed åt serverloggen", + "ot_mp": "musikkspelarinstillinger", + "ot_cfg": "andre innstillinger", + "ot_u2i": 'up2k: last opp filer (viss du har skriveåtgang) eller bytt åt søkemodus for å sjekke om filene finnast ein eller annan plass på serveren$N$Nopplastinger kan startast opp att etter avbrot, skjer stykkevis for potensielt høgare ytelse, og ivaretek datostempling -- men bruker litt meir prosessorkraft enn [🎈]  (den primitive opplastaren "bup")<br /><br />mens opplastinger føregår så visast framdrifta her oppe!', + "ot_u2w": 'up2k: filopplasting med støtte for å starte opp att avbrotne opplastinger -- steng ned nettlesaren og drage dei same filene inn i nettlesaren igjen for å plukke opp att der du slapp$N$Nopplastinger skjer stykkevis for potensielt høgare ytelse, og ivaretek datostempling -- men bruker litt meir prosessorkraft enn [🎈]  (den primitive opplastaren "bup")<br /><br />mens opplastinger føregår så visast framdrifta her oppe!', + "ot_noie": 'Fungerer mye betre i Chrome / Firefox / Edge', + + "ab_mkdir": "lag mappe", + "ab_mkdoc": "nytt dokument", + "ab_msg": "send melding", + + "ay_path": "gå videre åt mapper", + "ay_files": "gå videre åt filer", + + "wt_ren": "gje nye namn åt dei valde filene$NSnarvei: F2", + "wt_del": "slett dei valde filene$NSnarvei: ctrl-K", + "wt_cut": "klipp ut dei valde filene <small>(for å lime inn ein annan plass)</small>$NSnarvei: ctrl-X", + "wt_cpy": "kopiér dei valde filene åt utklippstavla$N(for å lime inn ein annan plass)$NSnarvei: ctrl-C", + "wt_pst": "lim inn filer (som tidligare blei klipt ut / kopiert ein annan plass)$NSnarvei: ctrl-V", + "wt_selall": "velg alle filer$NSnarvei: ctrl-A (mens fokus er på ei fil)", + "wt_selinv": "invertér utval", + "wt_zip1": "last ned denne mappa som eit arkiv", + "wt_selzip": "last ned dei valde filene som eit arkiv", + "wt_seldl": "last ned dei valde filene$NSnarvei: Y", + "wt_npirc": "kopiér songinfo (irc-formatert)", + "wt_nptxt": "kopiér songinfo", + "wt_m3ua": "legg song åt i m3u-speleliste$N(husk å klikk på <code>📻copy</code> senere)", + "wt_m3uc": "kopiér m3u-spelelista åt utklippstavla", + "wt_grid": "bytt mellom ikon og listevising$NSnarvei: G", + "wt_prev": "førre song$NSnarvei: J", + "wt_play": "play / pause$NSnarvei: P", + "wt_next": "neste song$NSnarvei: L", + + "ul_par": "samtidige handl.:", + "ut_rand": "finn opp nye tilfeldige filnamn", + "ut_u2ts": "gje fila på serveren same$Ntidsstempel som lokalt hos deg\">📅", + "ut_ow": "overskrive eksisterande filer på serveren?$N🛡️: aldri (finn på eit nytt filnamn i staden for)$N🕒: overskriv viss fila åt serveren er eldre$N♻️: alltid, gitt at innholdet er annleis", + "ut_mt": "fortsett å synfare køa mens opplasting føregår$N$Nskru denne av dersom du har ein$Ntreig prosessor eller harddisk", + "ut_ask": 'bekreft filutvalg før opplasting startar">💭', + "ut_pot": "forbetre ytinga på treige einheiter ved å$Nforenkle brukergrensesnittet", + "ut_srch": "gjer eit søk i staden for å laste opp --$Nleitar gjennom alle mappane du har lov åt å sjå", + "ut_par": "sett åt 0 for å midlertidig stoppe opplasting$N$Nhøge verdier (4 eller 8) kan gje betre yting,$Nspesielt på treige internettlinjer$N$Nbør ikkje vere høgare enn 1 på LAN$Neller viss serveren sin harddisk er treig", + "ul_btn": "slepp filer / mapper<br>her (eller klikk meg)", + "ul_btnu": "L A S T   O P P", + "ul_btns": "F I L S Ø K", + + "ul_hash": "synfar", + "ul_send": " send", + "ul_done": "total", + "ul_idle1": "ingen handlinger i køen", + "ut_etah": "snitthastigheit for <em>synfaring</em> samt gjenståande tid", + "ut_etau": "snitthastigheit for <em>opplasting</em> samt gjenståande tid", + "ut_etat": "<em>total</em> snitthastigheit og gjenståande tid", + + "uct_ok": "fullført uten problem", + "uct_ng": "fullført under tvil (duplikat, ikkje funne, ...)", + "uct_done": "fullført (enten <em>ok</em> eller <em>ng</em>)", + "uct_bz": "aktive handlinger (synfaring / opplasting)", + "uct_q": "køa", + + "utl_name": "filnamn", + "utl_ulist": "vis", + "utl_ucopy": "kopiér", + "utl_links": "lenker", + "utl_stat": "status", + "utl_prog": "fremdrift", + + // må vere korte: + "utl_404": "404", + "utl_err": "FEIL!", + "utl_oserr": "OS-feil", + "utl_found": "funnet", + "utl_defer": "seinare", + "utl_yolo": "YOLO", + "utl_done": "ferdig", + + "ul_flagblk": "filene har blitt lagd i køa</b><br>men det er ein anna nettlesarfane som held på med synfaring eller opplasting akkurat no,<br>så venter åt den er ferdig først", + "ul_btnlk": "brytaren har blitt låst åt denne tilstanden i serverens konfigurasjon", + + "udt_up": "Last opp", + "udt_srch": "Søk", + "udt_drop": "Slepp filene her", + + "u_nav_m": '<h6>kva har du?</h6><code>Enter</code> = Filer (éin eller fleire)\n<code>ESC</code> = Éi mappe (inkludert undermapper)', + "u_nav_b": '<a href="#" id="modal-ok">Filer</a><a href="#" id="modal-ng">Éi mappe</a>', + + "cl_opts": "brytarar", + "cl_themes": "utsjånad", + "cl_langs": "språk", + "cl_ziptype": "nedlasting av mapper", + "cl_uopts": "up2k-brytarar", + "cl_favico": "favicon", + "cl_bigdir": "store mapper", + "cl_hsort": "#sort", + "cl_keytype": "notasjon for musikalsk dur", + "cl_hiddenc": "skjulte kolonner", + "cl_hidec": "skjul", + "cl_reset": "nullstill", + "cl_hpick": "klikk på overskrifta åt kolonnene du ønskjer å skjule i tabellen nedanfor", + "cl_hcancel": "kolonne-skjuling avbrote", + + "ct_grid": '田 ikon', + "ct_ttips": 'vis hjelpetekst ved å holde musa over ting">ℹ️ tips', + "ct_thumb": 'vis miniatyrbilder i staden for ikon$NSnarvei: T">🖼️ bilder', + "ct_csel": 'bruk tastane CTRL og SHIFT for markering av filer i ikonvising">merk', + "ct_ihop": 'bla ned åt sist viste bilde når bildevisaren lukkast">g⮯', + "ct_dots": 'vis skjulte filer (gitt at serveren tillèt det)">.synlig', + "ct_qdel": 'sletteknappen spør berre éin gong om stadfesting">hurtig🗑️', + "ct_dir1st": 'sortér slik at mapper kjem framanfor filer">📁 først', + "ct_nsort": 'naturlig sortering (skjønar tal i filnamn)">nsort', + "ct_utc": 'bruk UTC for alle klokkeslett">UTC', + "ct_readme": 'vis README.md nedanfor filene">📜 readme', + "ct_idxh": 'vis index.html i staden for filliste">htm', + "ct_sbars": 'vis rullgardiner / skrollefelt">⟊', + + "cut_umod": 'i tilfelle ei fil du lastar opp alt finnast på serveren, så skal tidsstempelet åt serveren oppdaterast slik at det stemmer overeins med din lokale fil (krev rettigheitene write+delete)">re📅', + + "cut_turbo": "forenkla synfaring ved opplasting; bør etter alt å døme <em>ikkje</em> skruast på:$N$Nnyttig dersom du var midt i ei svær opplasting som måtte startast på nytt av ein eller annan grunn, og du vil komme i gang igjen så raskt som i det heile mulig.$N$Nnår denne er skrudd på så forenklast synfaringa kraftig; i staden for å utføre ein trygg sjekk på om filene finnast på serveren i god stand, så sjekkast det kun om <em>filstorleiken</em> stemmer. Så dersom ein korrupt fil vere på serveren allerede, på same plass, med same storleik og namn, så blir det <em>ikkje oppdaga</em>.$N$Ndet anbefalast å kun benytte denne funksjonen for å komme seg raskt gjennom sjølve opplastinga, for så å skru den av, og åt slutt "laste opp" dei same filene éin gong åt -- slik at integriteten kan verifiserast\">turbo", + + "cut_datechk": "har ingen effekt dersom turbo er skrudd av$N$Ngjer turbo bittelitt tryggare ved å sjekke datostemplinga på filene (i tillegg åt filstorleik)$N$N<em>burde</em> oppdage og gjenoppta dei fleste ufullstendige opplastinger, men er <em>ikkje</em> ein fullverdig erstatning for å deaktivere turbo og gjere ein skikkeleg sjekk\">date-chk", + + "cut_u2sz": "storleik i megabyte for kvart bruddstykke for opplasting. Store verdiar flyg betre over atlanteren. Små verdiar kan vere betre på flettande ustabile samband", + + "cut_flag": "samkøyrer nettlesarfaner slik at berre éin $N kan holde på med synfaring / opplasting $N -- andre faner må óg ha denne skrudd på $N -- fungerar kun innanom same domene", + + "cut_az": "last opp filer i alfabetisk rekkefølge, i staden for minste-fil-først$N$Nalfabetisk kan gjere det lettare å anslå om alt gjekk bra, men er bittelitt treigare på fiber / LAN", + + "cut_nag": "meldingsvarsel når opplasting er ferdig$N(kun om nettlesarfana ikkje er synlig)", + "cut_sfx": "lydvarsel når opplasting er ferdig$N(kun om nettlesarfanen ikkje er synlig)", + + "cut_mt": "raskere synfaring ved å bruke heile CPU'en$N$Ndenne funksjonen nytter web-workers$Nog krev meir RAM (opptil 512 MiB ekstra)$N$Ngjer https 30% raskare, http 4.5x raskare\">mt", + + "cut_wasm": "bruk wasm i staden for nettlesaren sin sha512-funksjon; gjev betre yting på chrome-baserte nettlesarar, men brukar meir CPU, og eldre versjoner av chrome toler det ikkje (et opp all RAM og kræsjer)\">wasm", + + "cft_text": "ikontekst (blank ut og last siden på nytt for å deaktivere)", + "cft_fg": "farge", + "cft_bg": "bakgrunnsfarge", + + "cdt_lim": "maks mengd filer å vise per mappe", + "cdt_ask": "vis knappar for å laste fleire filer nederst på sida i staden for å gradvis laste meir av mappea når man scroller ned", + "cdt_hsort": "antall sorteringsreglar (<code>,sorthref</code>) som skal inkluderast når media-URL'ar genererast. Dersom denne er 0 så vil sorteringsreglar i URL'ar korkje bli generert eller lest", + + "tt_entree": "bytt åt mappehierarki$NSnarvei: B", + "tt_detree": "bytt åt tradisjonell stivising$NSnarvei: B", + "tt_visdir": "bla ned åt den åpne mappa", + "tt_ftree": "bytt mellom filstruktur og tekstfiler$NSnarvei: V", + "tt_pdock": "vis dei overordna mappane i eit panel", + "tt_dynt": "øk bredda på panelet ettersom treet utvider seg", + "tt_wrap": "linjebryting", + "tt_hover": "vis heile mappenamnet når musepeikaren treff mappa$N( gjer diverre at scrollhjulet fusker dersom musepeikaren ikkje finn seg i grøfta )", + + "ml_pmode": "ved enden av mappa", + "ml_btns": "knapper", + "ml_tcode": "konvertering", + "ml_tcode2": "konvertér til", + "ml_tint": "tint", + "ml_eq": "audio equalizer (tonejustering)", + "ml_drc": "compressor (volumutjevning)", + + "mt_loop": "spel den same songen om og om igjen\">🔁", + "mt_one": "spel kun éin song\">1️⃣", + "mt_shuf": "songane i kvar mappe$Nspelast i tilfeldig rekkefølge\">🔀", + "mt_aplay": "prøv å starte avspeling viss linken du trykte på for å åpne nettsida inneheld ein song-ID$N$Nviss denne deaktiverast så vil heller ikkje nettside-URL'en bli oppdatert med song-ID'er når musikk spelast, i tilfelle innstillingane skulle gå tapt og nettsida lastast på ny\">a▶", + "mt_preload": "hent ned litt av neste song i forkant,$Nslik at pausa i overgangen blir mindre\">forsyn", + "mt_prescan": "ved behov, bla åt neste mappe$Nslik at nettlesaren lar oss$Nfortsetja å spele musikk\">bla", + "mt_fullpre": "hent ned heile neste song, ikkje berre litt:$N✅ skru på viss nettet ditt er <b>ustabilt</b>,$N❌ skru av viss nettet ditt er <b>treigt</b>\">full", + "mt_fau": "for telefoner: forhindre at avspeling stoppar viss nettet er for treigt åt å laste neste song i tide. Viss påskrudd kan det forårsake at songinfo ikkje visast korrekt i OS'et\">☕️", + "mt_waves": "waveform seekbar:$Nvis volumkurve i avspelingsfeltet\">~s", + "mt_npclip": "vis knappar for å kopiere info om songen du høyrer på\">/np", + "mt_m3u_c": "vis knapper for å kopiere dei valde$Nsongene som innslag i ei m3u8-speleliste\">📻", + "mt_octl": "integrering med operativsystemet (fjernkontroll, infoskjerm)\">os-ctl", + "mt_oseek": "gje løyve åt spoling med fjernkontroll$N$Nmerk: på nokon eininger (iPhones) så vil$Ndette erstatte knappen for neste song\">spoling", + "mt_oscv": "vis albumcover på infoskjermen\">bilde", + "mt_follow": "bla slik at songen som spelast alltid er synleg\">🎯", + "mt_compact": "tettpakka spelarpanel\">⟎", + "mt_uncache": "prøv denne viss ein song ikkje spelar riktig\">oppfrisk", + "mt_mloop": "repetér heile mappa\">🔁 gjenta", + "mt_mnext": "hopp åt neste mappe og fortsett\">📂 neste", + "mt_mstop": "stopp avspeling\">⏸ stopp", + "mt_cflac": "konvertér flac / wav-filer åt opus\">flac", + "mt_caac": "konvertér aac / m4a-filer åt to opus\">aac", + "mt_coth": "konvertér alt anna (men ikkje mp3) åt opus\">andre", + "mt_c2opus": "det beste valget for alle PCar og Android\">opus", + "mt_c2owa": "opus-weba, for iOS 17.5 og nyare\">owa", + "mt_c2caf": "opus-caf, for iOS 11 åt og med 17\">caf", + "mt_c2mp3": "bra valg for steinalder-utstyr (slår aldri feil)\">mp3", + "mt_c2flac": "gir best lydkvalitet, men et nettet ditt\">flac", + "mt_c2wav": "heilt rå lydstrøm (bruker enda meir data enn flac)\">wav", + "mt_c2ok": "bra valg!", + "mt_c2nd": "ikkje det føretrekte valget for din einheit, men funker sikkert greit", + "mt_c2ng": "ser verkelig ikkje ut som enheiten din taklar dette formatet... men ok, vi prøver", + "mt_xowa": "iOS har fortsatt problem med avspeling av owa-musikk i bakgrunnen. Bruk caf eller mp3 i staden for", + "mt_tint": "nivå av bakgrunnsfarge på søkestripa (0-100),$Ngjer oppdateringer mindre distraherande", + "mt_eq": "aktivér tonekontroll og forsterker;$N$Nboost <code>0</code> = normal volumskala$N$Nwidth <code>1  </code> = normal stereo$Nwidth <code>0.5</code> = 50% blanding venstre-høgre$Nwidth <code>0  </code> = mono$N$Nboost <code>-0.8</code> & width <code>10</code> = instrumental :^)$N$Nreduserer óg daudtid mellom songfiler", + "mt_drc": "aktivér volum-utjevning (dynamic range compressor); vil óg aktivere tonejustering, så sett alle EQ-feltene bortsett frå 'width' åt 0 viss du ikkje vil ha nokon EQ$N$Nfilteret vil dempe volumet på alt som er høgare enn TRESH dB; for kvar RATIO dB over grensa er det 1dB som treff høgtalarane, så standardverdiane tresh -24 og ratio 12 skal bety at volumet ikkje gjeng høgare enn -22 dB, slik at ein trygt kan øke boost-verdien i equalizeren åt rundt 0.8, eller 1.8 kombinert med ATK 0 og RLS 90 (berre mulig i firefox; andre nettlesarar tek ikkje høgare RLS enn 1)$N$Nwikipedia forklarar dette mykje betre forresten", + + "mb_play": "lytt", + "mm_hashplay": "spel denne songen?", + "mm_m3u": "trykk <code>Enter/OK</code> for å spele\ntrykk <code>ESC/Avbryt</code> for å redigere", + "mp_breq": "krev firefox 82+, chrome 73+, eller iOS 15+", + "mm_bload": "lastar inn...", + "mm_bconv": "konverterer åt {0}, vent litt...", + "mm_opusen": "nettlesaren din skjønar ikkje aac / m4a;\nkonvertering åt opus er no aktivert", + "mm_playerr": "avspeling feilet: ", + "mm_eabrt": "Avspelingsforespørselen blei avbroten", + "mm_enet": "Nettet ditt er ustabilt", + "mm_edec": "Noko er galt med musikkfila", + "mm_esupp": "Nettleseren din skjønar ikkje filtypen", + "mm_eunk": "Ukjent feil", + "mm_e404": "Avspeling feilet: Fil ikkje funnet.", + "mm_e403": "Avspeling feilet: Høve nekta.\n\nKanskje du blei logget ut?\nPrøv å trykk F5 for å laste sida på nytt.", + "mm_e500": "Avspeling feilet: Rusk i maskineriet, sjekk serverloggen.", + "mm_e5xx": "Avspeling feilet: ", + "mm_nof": "finn ikkje flere songer i nærheita", + "mm_prescan": "Leitar etter neste song...", + "mm_scank": "Fann neste song:", + "mm_uncache": "alle songer vil lastast på nytt ved neste avspeling", + "mm_hnf": "songen finnast ikkje lenger", + + "im_hnf": "bildet finnast ikkje lenger", + + "f_empty": 'denne mappa er tom', + "f_chide": 'dette vil skjule kolonna «{0}»\n\nfana for "andre innstillinger" let deg vise kolonna igjen', + "f_bigtxt": "denne fila er heeile {0} MiB -- vis som tekst?", + "f_bigtxt2": "vil du sjå bunnen av filen i staden for? du vil da óg sjå nye linjer som blir lagd åt på slutten av filen i sanntid", + "fbd_more": '<div id="blazy">visar <code>{0}</code> av <code>{1}</code> filer; <a href="#" id="bd_more">vis {2}</a> eller <a href="#" id="bd_all">vis alle</a></div>', + "fbd_all": '<div id="blazy">visar <code>{0}</code> av <code>{1}</code> filer; <a href="#" id="bd_all">vis alle</a></div>', + "f_anota": "kun {0} av totalt {1} element blei markert;\nfor å velje alt må du bla åt bunnen av mappa først", + + "f_dls": 'lenkane i denne mappa er no\nomgjort åt nedlastingsknappar', + + "f_partial": "For å laste ned ei fil som enda ikkje er ferdig opplasta, klikk på filen som har same filnamn som denne, men uten <code>.PARTIAL</code> på slutten. Da vil serveren passe på at nedlastinga går bra. Derfor anbefalast det sterkt å trykkje AVBRYT eller Escape-tasten.\n\nViss du verkelig ønskjer å laste ned denne <code>.PARTIAL</code>-filen på ein ukontrollert måte, trykk OK / Enter for å ignorere denne advarselen. Slik vil du høgst sannsynleg motta korrupt data.", + + "ft_paste": "Lim inn {0} filer$NSnarvei: ctrl-V", + "fr_eperm": 'kan ikkje endre namn:\ndu har ikkje høve åt “move” i denne mappa', + "fd_eperm": 'kan ikkje slette:\ndu har ikkje høve åt “delete” i denne mappa', + "fc_eperm": 'kan ikkje klippe ut:\ndu har ikkje høve åt “move” i denne mappa', + "fp_eperm": 'kan ikkje lime inn:\ndu har ikkje høve åt “write” i denne mappa', + "fr_emore": "vel minst éi fil som skal få nytt namn", + "fd_emore": "vel minst éi fil som skal slettast", + "fc_emore": "vel minst éi fil som skal klippast ut", + "fcp_emore": "vel minst éi fil som skal kopierast åt utklippstavla", + + "fs_sc": "del mappa du er i no", + "fs_ss": "del dei valde filene", + "fs_just1d": "du kan ikkje markere flere mapper samtidig,\neller kombinere mapper og filer", + "fs_abrt": "❌ avbryt", + "fs_rand": "🎲 tilfeldig namn", + "fs_go": "✅ opprett deling", + "fs_name": "namn", + "fs_src": "kjelde", + "fs_pwd": "passord", + "fs_exp": "varigheit", + "fs_tmin": "min", + "fs_thrs": "timar", + "fs_tdays": "dagar", + "fs_never": "for evig", + "fs_pname": "valfri namn (blir litt tilfeldig ellers)", + "fs_tsrc": "fil/mappe som skal delast", + "fs_ppwd": "valfri passord", + "fs_w8": "opprettar deling...", + "fs_ok": "trykk <code>Enter/OK</code> for å kopiere lenka (for CTRL-V)\ntrykk <code>ESC/Avbryt</code> for å kun bekrefta", + + "frt_dec": "kan korrigere visse ødelagte filnamn\">url-decode", + "frt_rst": "nullstillar endringar (tilbake åt dei originale filnamna)\">↺ reset", + "frt_abrt": "avbryt og lukk dette vindauget\">❌ avbryt", + "frb_apply": "IVERKSETT", + "fr_adv": "automasjon basert på metadata<br>og / eller mønster (regulære uttrykk)\">avansert", + "fr_case": "versalfølsomme uttrykk\">Aa", + "fr_win": "bytt ut bokstavane <code><>:"\\|?*</code> med$Ntilsvarande som windows ikkje får panikk av\">win", + "fr_slash": "bytt ut bokstaven <code>/</code> slik at den ikkje forårsakar at nye mapper opprettes\">ikke /", + "fr_re": "regex-mønster som køyrast på kvart filnamn. Grupper kan leses ut i format-feltet nedanfor, f.eks. <code>(1)</code> og <code>(2)</code> osv.", + "fr_fmt": "inspirert av foobar2000:$N<code>(title)</code> byttast ut med songtittel,$N<code>[(artist) - ](title)</code> dropper [dette] viss artist er blank$N<code>$lpad((tn),2,0)</code> visar songnr. med 2 siffer", + "fr_pdel": "slett", + "fr_pnew": "lagre som", + "fr_pname": "gje innstillingane dine eit namn", + "fr_aborted": "avbrote", + "fr_lold": "gamalt namn", + "fr_lnew": "nytt namn", + "fr_tags": "metadata for dei valde filene (kun for referanse):", + "fr_busy": "endrar namn på {0} filer...\n\n{1}", + "fr_efail": "endring av namn feila:\n", + "fr_nchg": "{0} av namna blei justert pga. <code>win</code> og/eller <code>ikkje /</code>\n\nvil du fortsetja med dei nye namna som blei valde?", + + "fd_ok": "sletting OK", + "fd_err": "sletting feila:\n", + "fd_none": "ingenting blei sletta; kanskje avvist av serverkonfigurasjon (xbd)?", + "fd_busy": "slettar {0} filer...\n\n{1}", + "fd_warn1": "SLETT disse {0} filene?", + "fd_warn2": "<b>Siste sjanse!</b> Dette kan ikkje angrast. Slett?", + + "fc_ok": "klipte ut {0} filer", + "fc_warn": 'klipte ut {0} filer\n\nmen: kun <b>denne</b> nettlesarfana har muligheit åt å lime dei inn ein annan plass, siden antallet filer er helt hinsides', + + "fcc_ok": "kopierte {0} filer åt utklippstavla", + "fcc_warn": 'kopierte {0} filer åt utklippstavla\n\nmen: kun <b>denne</b> nettlesarfana har muligheit åt å lime dei inn ein annan plass, sidan antallet filer er heilt på hi sida', + + "fp_apply": "bekreft og lim inn no", + "fp_ecut": "du må klippe ut eller kopiere nokre filer / mapper først\n\nmerk: du kan gjerne jobbe på kryss av nettlesarfaner; klippe ut i éi fane, lime inn i ei anna", + "fp_ename": "{0} filer kan ikkje flyttast åt målmappa fordi det allereie finnast filer med same namn. Gi dei nye namn nedanfor, eller gje dei eit blankt namn for å hoppe over dei:", + "fcp_ename": "{0} filer kan ikkje kopierast åt målmappa fordi det allereie finnast filer med same namn. Gi dei nye namn nedanfor, eller gje dei eit blankt namn for å hoppe over dei:", + "fp_emore": "det er fortsatt fleire namn som må endrast", + "fp_ok": "flytting OK", + "fcp_ok": "kopiering OK", + "fp_busy": "flyttar {0} filer...\n\n{1}", + "fcp_busy": "kopierar {0} filer...\n\n{1}", + "fp_err": "flytting feila:\n", + "fcp_err": "kopiering feila:\n", + "fp_confirm": "flytt disse {0} filene hit?", + "fcp_confirm": "kopiér disse {0} filene hit?", + "fp_etab": 'kunne ikkje lese lista med filer frå den andre nettlesarfana', + "fp_name": "Lastar opp éi fil frå einheita di. Velg filnamn:", + "fp_both_m": '<h6>kva skal limast inn her?</h6><code>Enter</code> = Flytt {0} filer frå «{1}»\n<code>ESC</code> = Last opp {2} filer frå einheita din', + "fcp_both_m": '<h6>kva skal limes inn her?</h6><code>Enter</code> = Kopiér {0} filer frå «{1}»\n<code>ESC</code> = Last opp {2} filer frå einheita din', + "fp_both_b": '<a href="#" id="modal-ok">Flytt</a><a href="#" id="modal-ng">Last opp</a>', + "fcp_both_b": '<a href="#" id="modal-ok">Kopiér</a><a href="#" id="modal-ng">Last opp</a>', + + "mk_noname": "skriv inn eit namn i tekstboksa åt venstre først :p", + + "tv_load": "Lastar inn tekstfil:\n\n{0}\n\n{1}% ({2} av {3} MiB lasta ned)", + "tv_xe1": "kunne ikkje laste tekstfil:\n\nfeil ", + "tv_xe2": "404, Fil ikkje funne", + "tv_lst": "tekstfiler i mappa", + "tvt_close": "gå tilbake åt mappa$NSnarvei: M (eller Esc)\">❌ lukk", + "tvt_dl": "last ned denne fila$NSnarvei: Y\">💾 last ned", + "tvt_prev": "vis førre dokument$NSnarvei: i\">⬆ forr.", + "tvt_next": "vis neste dokument$NSnarvei: K\">⬇ neste", + "tvt_sel": "markér fila   ( for utklipp / sletting / ... )$NSnarvei: S\">merk", + "tvt_edit": "redigér fila$NSnarvei: E\">✏️ endre", + "tvt_tail": "overvak fila for endringar og vis nye linjer i sanntid\">📡 følg", + "tvt_wrap": "tekstbryting\">↵", + "tvt_atail": "hald dei nyaste linjene synlege (lås åt botnen av sida)\">⚓", + "tvt_ctail": "skjøn og vis terminalfargar (ansi-sekvensar)\">🌈", + "tvt_ntail": "maksgrense for antal bokstavar som skal visast i vindauget", + + "m3u_add1": "songen blei lagd åt i m3u-spelelista", + "m3u_addn": "{0} songer blei lagde åt i m3u-spelelista", + "m3u_clip": "m3u-spelelista blei kopiert åt utklippstavla\n\nneste steg er å oppretta eit tekstdokument med filnamn som sluttar på <code>.m3u</code> og lime inn spelelista der", + + "gt_vau": "ikkje vis videofiler, berre spel lyden\">🎧", + "gt_msel": "markér filer i staden for å åpne dei; ctrl-klikk filer for å overstyre$N$N<em>når aktiv: dobbelklikk ei fil / mappe for å åpne</em>$N$NSnarvei: S\">markering", + "gt_crop": "skjer ikona slik at dei passar betre\">✂", + "gt_3x": "høgare oppløysing på ikon\">3x", + "gt_zoom": "zoom", + "gt_chop": "trim", + "gt_sort": "sortér", + "gt_name": "namn", + "gt_sz": "størr.", + "gt_ts": "dato", + "gt_ext": "type", + "gt_c1": "redusér makslengde på filnamn", + "gt_c2": "auk makslengde på filnamn", + + "sm_w8": "søker...", + "sm_prev": "søkeresultata er frå eit tidlegare søk:\n ", + "sl_close": "lukk søkeresultat", + "sl_hits": "visar {0} treff", + "sl_moar": "hent fleire", + + "s_sz": "størr.", + "s_dt": "dato", + "s_rd": "sti", + "s_fn": "namn", + "s_ta": "meta", + "s_ua": "up@", + "s_ad": "avns.", + "s_s1": "større enn ↓ MiB", + "s_s2": "mindre enn ↓ MiB", + "s_d1": "nyare enn <dato>", + "s_d2": "eldre enn", + "s_u1": "lasta opp etter", + "s_u2": "og/eller før", + "s_r1": "mappaamn inneheld", + "s_f1": "filnamn inneheld", + "s_t1": "song-info inneheld", + "s_a1": "konkrete eigenskapar", + + "md_eshow": "visar forenkla ", + "md_off": "[📜<em>readme</em>] er skrudd av i [⚙️] -- dokument skjult", + + "badreply": "Ugyldig svar frå serveren", + + "xhr403": "403: Høve nekta\n\nkanskje du blei logga ut? prøv å trykk F5", + "xhr0": "ukjend (enten nettverksproblem eller serverkræsj)", + "cf_ok": "om orsak -- liten tilfeldig kontroll, alt OK\n\nting skal fortsetja om ca. 30 sekund\n\nviss ikkje noko skjer, trykk F5 for å laste sida på nytt", + "tl_xe1": "kunne ikkje hente undermapper:\n\nfeil ", + "tl_xe2": "404: Mappa finnast ikkje", + "fl_xe1": "kunne ikkje hente filer i mappa:\n\nfeil ", + "fl_xe2": "404: Mappa finnast ikkje", + "fd_xe1": "kan ikkje opprette ny mappe:\n\nfeil ", + "fd_xe2": "404: Den overordna mappa finnast ikkje", + "fsm_xe1": "kunne ikkje sende melding:\n\nfeil ", + "fsm_xe2": "404: Den overordna mappa finnast ikkje", + "fu_xe1": "kunne ikkje hente lista med nyleg opplastede filer frå serveren:\n\nfeil ", + "fu_xe2": "404: Fila finnast ikkje??", + + "fz_tar": "ukomprimert gnu-tar arkiv, for linux og mac", + "fz_pax": "ukomprimert pax-tar arkiv, litt treigare", + "fz_targz": "gnu-tar pakket med gzip (nivå 3)$N$NNB: denne er veldig treig;$Nukomprimert tar er betre", + "fz_tarxz": "gnu-tar pakket med xz (nivå 1)$N$NNB: denne er veldig treig;$Nukomprimert tar er betre", + "fz_zip8": "zip med filnamn i utf8 (noko problematisk på windows 7 og eldre)", + "fz_zipd": "zip med filnamn i cp437, for høggamle maskiner", + "fz_zipc": "cp437 med tidlig crc32,$Nfor MS-DOS PKZIP v2.04g (oktober 1993)$N(øker behandlingstid på server)", + + "un_m1": "nedanfor kan du angre / slette filer som du nyleg har lastet opp, eller avbryte ufullstendige opplastinger", + "un_upd": "oppdater", + "un_m4": "eller viss du vil dele nedlastings-lenkene:", + "un_ulist": "vis", + "un_ucopy": "kopiér", + "un_flt": "valgfritt filter:  filnamn / filsti må inneholde", + "un_fclr": "nullstill filter", + "un_derr": 'unpost-sletting feilet:\n', + "un_f5": 'noko gjekk galt, prøv å oppdatere lista eller trykk F5', + "un_uf5": "om orsak, men du må laste sida på nytt (f.eks. ved å trykkje F5 eller CTRL-R) før denne opplastinga kan avbrytast", + "un_nou": '<b>advarsel:</b> kan ikkje vise ufullstendige opplastingar akkurat no; klikk på oppdater-lenka om litt', + "un_noc": '<b>advarsel:</b> angring av fullførte opplastingar er deaktivert i serverkonfigurasjonen', + "un_max": "visar dei første 2000 filene (bruk filteret for å snevre inn)", + "un_avail": "{0} nyleg opplasta filer kan slettast<br />{1} ufullstendige opplastingar kan avbrytast", + "un_m2": "sortert etter opplastingstid; nyaste først:", + "un_no1": "men nei, her var det jaggu ikkje noko som slettast kan", + "un_no2": "men nei, her var det jaggu ingenting som passa overens med filteret", + "un_next": "slett dei neste {0} filene nedanfor", + "un_abrt": "avbryt", + "un_del": "slett", + "un_m3": "hentar lista med nyleg opplasta filer...", + "un_busy": "slettar {0} filer...", + "un_clip": "{0} lenkar kopiert åt utklippstavla", + + "u_https1": "du burde", + "u_https2": "bytte åt https", + "u_https3": "for høgare hastigheit", + "u_ancient": 'nettlesaren din er prehistorisk -- mulig du burde <a href="#" onclick="goto(\'bup\')">bruke bup i staden for</a>', + "u_nowork": "krev firefox 53+, chrome 57+, eller iOS 11+", + "tail_2old": "krev firefox 105+, chrome 71+, eller iOS 14.5+", + "u_nodrop": 'nettlesaren din er for gamal åt å laste opp filer ved å drage dei inn i vindauget', + "u_notdir": "mottok ikkje mappa!\n\nnettlesaren din er for gamal,\nprøv å drage mappa inn i vindauget i staden for", + "u_uri": "for å laste opp bilder frå andre nettlesarvindauge,\nslipp bildet rett på den store last-opp-knappen", + "u_enpot": 'bytt åt <a href="#">enkelt UI</a> (gir sannsynleg raskere opplasting)', + "u_depot": 'bytt åt <a href="#">snæsent UI</a> (gir sannsynleg treigare opplasting)', + "u_gotpot": 'bytta åt eit enklare UI for å laste opp raskere,\n\ndu kan gjerne bytte tilbake altså!', + "u_pott": "<p>filer:   <b>{0}</b> ferdig,   <b>{1}</b> feilet,   <b>{2}</b> behandlast,   <b>{3}</b> i kø</p>", + "u_ever": "dette er den primitive opplastaren; up2k krev minst:<br>chrome 21 // firefox 13 // edge 12 // opera 12 // safari 5.1", + "u_su2k": 'dette er den primitive opplastaren; <a href="#" id="u2yea">up2k</a> er betre', + "u_uput": 'litt raskare (uten sha512)', + "u_ewrite": 'du har ikkje høve til å skrive i denne mappa', + "u_eread": 'du har ikkje høve til å lese i denne mappa', + "u_enoi": 'filsøk er deaktivert i serverkonfigurasjonen', + "u_enoow": "kan ikkje overskrive filer her (Delete-rettigheiten er nødvendig)", + "u_badf": 'Disse {0} filene (av totalt {1}) kan ikkje leses, kanskje pga rettigheitsproblem i filsystemet på datamaskinen din:\n\n', + "u_blankf": 'Disse {0} filene (av totalt {1}) er blanke / uten innhald; ønskjer du å laste dei opp uansett?\n\n', + "u_applef": 'Disse {0} filene (av totalt {1}) er antakeleg uønska;\nTrykk <code>OK/Enter</code> for å HOPPE OVER disse filene,\nTrykk <code>Avbryt/ESC</code> for å LASTE OPP disse filene óg:\n\n', + "u_just1": '\nFunkar kanskje betre viss du berre tar éi fil om gangen', + "u_ff_many": 'Viss du bruker <b>Linux / MacOS / Android,</b> så kan dette antalet filer<br /><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank"><em>kanskje</em> kræsje Firefox!</a> Viss det skjer, så prøv igjen (eller bruk Chrome).', + "u_up_life": "Filene slettast frå serveren {0}\netter at opplastingen er fullført", + "u_asku": 'Laste opp disse {0} filene åt <code>{1}</code>', + "u_unpt": "Du kan angre / slette opplastinga med 🧯 oppe åt venstre", + "u_bigtab": 'Vil no vise {0} filer...\n\nDette kan kræsje nettlesaren din. Fortsette?', + "u_scan": 'Les mappane...', + "u_dirstuck": 'Nettleseren din fekk ikkje høve åt å lese følgande {0} filer/mapper, så dei blir hoppa over:', + "u_etadone": 'Ferdig ({0}, {1} filer)', + "u_etaprep": '(forberedar opplasting)', + "u_hashdone": 'synfaring ferdig', + "u_hashing": 'les', + "u_hs": 'serveren tenkjer...', + "u_started": "filene blir no lasta opp 🚀", + "u_dupdefer": "duplikat; vil bli håndtert åt slutt", + "u_actx": "klikk her for å forhindre tap av<br />yting ved bytte åt andre vindauge/faner", + "u_fixed": "OK!  Løyste seg 👍", + "u_cuerr": "kunne ikkje laste opp del {0} av {1};\nsikkert greit, fortsetjar\n\nfil: {2}", + "u_cuerr2": "server nekta opplastinga (del {0} av {1});\nprøver igjen senere\n\nfil: {2}\n\nerror ", + "u_ehstmp": "prøver igjen; se mld nederst", + "u_ehsfin": "server nekta forespørselen om å ferdigstille filen; prøver igjen...", + "u_ehssrch": "server nekta forespørselen om å utføre søk; prøver igjen...", + "u_ehsinit": "server nekta forespørselen om å begynne ei ny opplasting; prøver igjen...", + "u_eneths": "eit problem med nettverket gjorde at avtale om opplasting ikkje kunne inngås; prøver igjen...", + "u_enethd": "eit problem med nettverket gjorde at filsjekk ikkje kunne utførast; prøver igjen...", + "u_cbusy": "ventar på klarering frå server etter eit lite nettverksglipp...", + "u_ehsdf": "serveren er full!\n\nprøver igjen regelmessig,\ni tilfelle nokon ryddar litt...", + "u_emtleak1": "uff, det er mulig at nettlesaren din har ei minnelekkasje...\nForeslår", + "u_emtleak2": ' helst at du <a href="{0}">byttar åt https</a>, eller ', + "u_emtleak3": ' at du ', + "u_emtleakc": 'prøver følgande:\n<ul><li>trykk F5 for å laste sida på nytt</li><li>så skru av  <code>mt</code>  brytaren under  <code>⚙️ innstillinger</code></li><li>og prøv den same opplastinga igjen</li></ul>Opplasting vil gå litt treigare, men det får så vere.\nBeklager bryderiet!\n\nPS: feilen <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354816" target="_blank">skal vere fikset</a> i chrome v107', + "u_emtleakf": 'prøver følgende:\n<ul><li>trykk F5 for å laste sida på nytt</li><li>så skru på <code>🥔</code> ("enkelt UI") i opplastaren</li><li>og prøv den same opplastingen igjen</li></ul>\nPS: Firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1790500" target="_blank">fiksar forhåpentligvis feilen</a> ein eller annen gong', + "u_s404": "ikkje funne på serveren", + "u_expl": "forklar", + "u_maxconn": "dei fleste nettlesarar tillet ikkje meir enn 6, men firefox lar deg øke grensen med <code>connections-per-server</code> i <code>about:config</code>", + "u_tu": '<p class="warn">ADVARSEL: turbo er på, <span> avbrotne opplastingar vil muligens ikkje oppdagast og gjenopptakast; hald musepeikaren over turbo-knappen for meir info</span></p>', + "u_ts": '<p class="warn">ADVARSEL: turbo er på, <span> søkeresultat kan vere feil; hold musepeikaren over turbo-knappen for meir info</span></p>', + "u_turbo_c": "turbo er deaktivert i serverkonfigurasjonen", + "u_turbo_g": 'turbo blei deaktivert fordi du ikkje har\nhøve åt å sjå mappeinnhold i dette volumet', + "u_life_cfg": 'slett opplasting etter <input id="lifem" p="60" /> min (eller <input id="lifeh" p="3600" /> timar)', + "u_life_est": 'opplastingen slettast <span id="lifew" tt="lokal tid">---</span>', + "u_life_max": 'denne mappa tillet ikkje å \noppbevare filer i meir enn {0}', + "u_unp_ok": 'opplasting kan angrast i {0}', + "u_unp_ng": 'opplasting kan IKKE angrast', + "ue_ro": 'du har ikkje høve åt skriving i denne mappa\n\n', + "ue_nl": 'du er ikkje logga inn', + "ue_la": 'du er logga inn som "{0}"', + "ue_sr": 'du er i filsøk-modus\n\nbytt åt opplasting ved å klikke på forstørringsglaset 🔎 (ved siden av den store FILSØK-knappen) og prøv igjen\n\nsorry', + "ue_ta": 'prøv å last opp igjen, det burde fungere no', + "ue_ab": "den same filen er under opplasting åt ei anna mappe, og den må fullførast der før fila kan lastast opp andre plassar.\n\nDu kan avbryte og gløyme den påbegynte opplastinga ved hjelp av 🧯 oppe åt venstre", + "ur_1uo": "OK: Fila blei lastet opp", + "ur_auo": "OK: Alle {0} filene blei lastet opp", + "ur_1so": "OK: Fila blei funne på serveren", + "ur_aso": "OK: Alle {0} filene blei funne på serveren", + "ur_1un": "Opplasting feila!", + "ur_aun": "Alle {0} opplastingene gjekk feil!", + "ur_1sn": "Fila finnast IKKE på serveren", + "ur_asn": "Fann INGEN av dei {0} filene på serveren", + "ur_um": "Ferdig;\n{0} opplastingar gjekk bra,\n{1} opplastingar gjekk feil", + "ur_sm": "Ferdig;\n{0} filer blei funne,\n{1} filer finnast IKKJE på serveren", + + "lang_set": "passar det å laste sida på nytt?", + }, "rus": { "tt": "Русский", @@ -7560,7 +8190,7 @@ var Ls = { }, }; -var LANGS = ["eng", "nor", "chi", "cze", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"]; +var LANGS = ["eng", "nor", "nno", "chi", "cze", "deu", "fin", "grc", "ita", "nld", "rus", "spa", "ukr"]; if (window.langmod) langmod(); diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js index dc540fb4..6ffd95f6 100644 --- a/copyparty/web/splash.js +++ b/copyparty/web/splash.js @@ -343,6 +343,48 @@ var Ls = { "af1": "Recent geüploade bestanden weergeven", "ag1": "Bekende IdP-gebruikers weergeven", }, + "nno": { + "a1": "oppdatér", + "b1": "heisann   <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:", + "m1": "velkomen attende,", + "n1": "404: filen finnast ikkje  ┐( ´ -`)┌", + "o1": 'eller kanskje du ikkje har høve? prøv eit passord eller <a href="' + SR + '/?h">gå heim</a>', + "p1": "403: tilgang nektet  ~┻━┻", + "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", + }, "spa": { "a1": "actualizar", "b1": "hola   <small>(no has iniciado sesión)</small>",