mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-04 05:43:17 +00: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()
 |