mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
hooks can now interrupt or redirect actions, and initiate related actions, by printing json on stdout with commands mainly to mitigate limitations such as sharex/sharex#3992 xbr/xau can redirect uploads to other destinations with `reloc` and most hooks can initiate indexing or deletion of additional files by giving a list of vpaths in json-keys `idx` or `del` there are limitations; * xbu/xau effects don't apply to ftp, tftp, smb * xau will intentionally fail if a reloc destination exists * xau effects do not apply to up2k also provides more details for hooks: * xbu/xau: basic-uploader vpath with filename * xbr/xar: add client ip
141 lines
3.5 KiB
Python
141 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
import json
|
|
import shutil
|
|
import platform
|
|
import subprocess as sp
|
|
from urllib.parse import quote
|
|
|
|
|
|
_ = r"""
|
|
try to avoid race conditions in caching proxies
|
|
(primarily cloudflare, but probably others too)
|
|
by means of the most obvious solution possible:
|
|
|
|
just as each file has finished uploading, use
|
|
the server's external URL to download the file
|
|
so that it ends up in the cache, warm and snug
|
|
|
|
this intentionally delays the upload response
|
|
as it waits for the file to finish downloading
|
|
before copyparty is allowed to return the URL
|
|
|
|
NOTE: you must edit this script before use,
|
|
replacing https://example.com with your URL
|
|
|
|
NOTE: if the files are only accessible with a
|
|
password and/or filekey, you must also add
|
|
a cromulent password in the PASSWORD field
|
|
|
|
NOTE: needs either wget, curl, or "requests":
|
|
python3 -m pip install --user -U requests
|
|
|
|
|
|
example usage as global config:
|
|
--xau j,t10,bin/hooks/into-the-cache-it-goes.py
|
|
|
|
parameters explained,
|
|
xau = execute after upload
|
|
j = this hook needs upload information as json (not just the filename)
|
|
t10 = abort download and continue if it takes longer than 10sec
|
|
|
|
example usage as a volflag (per-volume config):
|
|
-v srv/inc:inc:r:rw,ed:c,xau=j,t10,bin/hooks/into-the-cache-it-goes.py
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
(share filesystem-path srv/inc as volume /inc,
|
|
readable by everyone, read-write for user 'ed',
|
|
running this plugin on all uploads with params explained above)
|
|
|
|
example usage as a volflag in a copyparty config file:
|
|
[/inc]
|
|
srv/inc
|
|
accs:
|
|
r: *
|
|
rw: ed
|
|
flags:
|
|
xau: j,t10,bin/hooks/into-the-cache-it-goes.py
|
|
"""
|
|
|
|
|
|
# replace this with your site's external URL
|
|
# (including the :portnumber if necessary)
|
|
SITE_URL = "https://example.com"
|
|
|
|
# if downloading is protected by passwords or filekeys,
|
|
# specify a valid password between the quotes below:
|
|
PASSWORD = ""
|
|
|
|
# if file is larger than this, skip download
|
|
MAX_MEGABYTES = 8
|
|
|
|
# =============== END OF CONFIG ===============
|
|
|
|
|
|
WINDOWS = platform.system() == "Windows"
|
|
|
|
|
|
def main():
|
|
fun = download_with_python
|
|
if shutil.which("curl"):
|
|
fun = download_with_curl
|
|
elif shutil.which("wget"):
|
|
fun = download_with_wget
|
|
|
|
inf = json.loads(sys.argv[1])
|
|
|
|
if inf["sz"] > 1024 * 1024 * MAX_MEGABYTES:
|
|
print("[into-the-cache] file is too large; will not download")
|
|
return
|
|
|
|
file_url = "/"
|
|
if inf["vp"]:
|
|
file_url += inf["vp"] + "/"
|
|
file_url += inf["ap"].replace("\\", "/").split("/")[-1]
|
|
file_url = SITE_URL.rstrip("/") + quote(file_url, safe=b"/")
|
|
|
|
print("[into-the-cache] %s(%s)" % (fun.__name__, file_url))
|
|
fun(file_url, PASSWORD.strip())
|
|
|
|
print("[into-the-cache] Download OK")
|
|
|
|
|
|
def download_with_curl(url, pw):
|
|
cmd = ["curl"]
|
|
|
|
if pw:
|
|
cmd += ["-HPW:%s" % (pw,)]
|
|
|
|
nah = sp.DEVNULL
|
|
sp.check_call(cmd + [url], stdout=nah, stderr=nah)
|
|
|
|
|
|
def download_with_wget(url, pw):
|
|
cmd = ["wget", "-O"]
|
|
|
|
cmd += ["nul" if WINDOWS else "/dev/null"]
|
|
|
|
if pw:
|
|
cmd += ["--header=PW:%s" % (pw,)]
|
|
|
|
nah = sp.DEVNULL
|
|
sp.check_call(cmd + [url], stdout=nah, stderr=nah)
|
|
|
|
|
|
def download_with_python(url, pw):
|
|
import requests
|
|
|
|
headers = {}
|
|
if pw:
|
|
headers["PW"] = pw
|
|
|
|
with requests.get(url, headers=headers, stream=True) as r:
|
|
r.raise_for_status()
|
|
for _ in r.iter_content(chunk_size=1024 * 256):
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|