From 1460fe97acc4fb8f0ca143c7be73ad5687a345cd Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 21 Sep 2025 21:21:41 +0000 Subject: [PATCH] rotf timezone option; closes #802 --- README.md | 1 + copyparty/__main__.py | 1 + copyparty/authsrv.py | 11 ++++++++--- copyparty/cfg.py | 1 + tests/util.py | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 54723946..ca397b25 100644 --- a/README.md +++ b/README.md @@ -1637,6 +1637,7 @@ set upload rules using volflags, some examples: * `:c,nosub` disallow uploading into subdirectories; goes well with `rotn` and `rotf`: * `:c,rotn=1000,2` moves uploads into subfolders, up to 1000 files in each folder before making a new one, two levels deep (must be at least 1) * `:c,rotf=%Y/%m/%d/%H` enforces files to be uploaded into a structure of subfolders according to that date format + * `:c,rotf_tz=Europe/Oslo` sets the timezone (default is UTC unless global-option `rotf-tz` is changed) * if someone uploads to `/foo/bar` the path would be rewritten to `/foo/bar/2021/08/06/23` for example * but the actual value is not verified, just the structure, so the uploader can choose any values which conform to the format string * just to avoid additional complexity in up2k which is enough of a mess already diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 1605d55b..ac46d39e 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1232,6 +1232,7 @@ def add_upload(ap): ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every \033[33mSEC\033[0m seconds; allows resuming incomplete uploads after a server crash") ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440.0, help="forget unfinished uploads after \033[33mMIN\033[0m minutes; impossible to resume them after that (360=6h, 1440=24h)") ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)") + ap2.add_argument("--rotf-tz", metavar="TXT", type=u, default="UTC", help="default timezone for the rotf upload rule; examples: [\033[32mEurope/Oslo\033[0m], [\033[32mAmerica/Toronto\033[0m], [\033[32mAntarctica/South_Pole\033[0m] (volflag=rotf_tz)") ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)") ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)") ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 4dd16804..96613d21 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -169,14 +169,19 @@ class Lim(object): self.rotn = 0 # rot num files self.rotl = 0 # rot depth self.rotf = "" # rot datefmt + self.rotf_tz = UTC # rot timezone self.rot_re = re.compile("") # rotf check def log(self, msg: str, c: Union[int, str] = 0) -> None: if self.log_func: self.log_func("up-lim", msg, c) - def set_rotf(self, fmt: str) -> None: + def set_rotf(self, fmt: str, tz: str) -> None: self.rotf = fmt + if tz != "UTC": + from zoneinfo import ZoneInfo + + self.rotf_tz = ZoneInfo(tz) r = re.escape(fmt).replace("%Y", "[0-9]{4}").replace("%j", "[0-9]{3}") r = re.sub("%[mdHMSWU]", "[0-9]{2}", r) self.rot_re = re.compile("(^|/)" + r + "$") @@ -280,7 +285,7 @@ class Lim(object): if self.rot_re.search(path.replace("\\", "/")): return path, "" - suf = datetime.now(UTC).strftime(self.rotf) + suf = datetime.now(self.rotf_tz).strftime(self.rotf) if path: path += "/" @@ -2218,7 +2223,7 @@ class AuthSrv(object): zs = vol.flags.get("rotf") if zs: use = True - lim.set_rotf(zs) + lim.set_rotf(zs, vol.flags.get("rotf_tz") or "UTC") zs = vol.flags.get("maxn") if zs: diff --git a/copyparty/cfg.py b/copyparty/cfg.py index bfeda5bf..1fb5f193 100644 --- a/copyparty/cfg.py +++ b/copyparty/cfg.py @@ -219,6 +219,7 @@ flagcats = { "upload rotation\n(moves all uploads into the specified folder structure)": { "rotn=100,3": "3 levels of subfolders with 100 entries in each", "rotf=%Y-%m/%d-%H": "date-formatted organizing", + "rotf_tz=Europe/Oslo": "timezone (default=UTC)", "lifetime=3600": "uploads are deleted after 1 hour", }, "database, general": { diff --git a/tests/util.py b/tests/util.py index ddbd6631..c82daf21 100644 --- a/tests/util.py +++ b/tests/util.py @@ -207,6 +207,7 @@ class Cfg(Namespace): put_name="put-{now.6f}-{cip}.bin", mv_retry="0/0", rm_retry="0/0", + rotf_tz="UTC", s_rd_sz=256 * 1024, s_wr_sz=256 * 1024, shr_who="auth",