mirror of
				https://github.com/9001/copyparty.git
				synced 2025-10-31 04:32:20 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			137 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env python
 | |
| # coding: utf-8
 | |
| # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 | |
| from __future__ import print_function, unicode_literals
 | |
| 
 | |
| import json
 | |
| import os
 | |
| import sys
 | |
| import time
 | |
| 
 | |
| try:
 | |
|     from datetime import datetime, timezone
 | |
| except:
 | |
|     from datetime import datetime
 | |
| 
 | |
| 
 | |
| _ = r"""
 | |
| use copyparty as a dumb messaging server / guestbook thing;
 | |
| accepts guestbook entries from 📟 (message-to-server-log) in the web-ui
 | |
| initially contributed by @clach04 in https://github.com/9001/copyparty/issues/35 (thanks!)
 | |
| 
 | |
| example usage as global config:
 | |
|     python copyparty-sfx.py --xm j,bin/hooks/msg-log.py
 | |
| 
 | |
| parameters explained,
 | |
|     xm = execute on message (📟)
 | |
|     j  = this hook needs message information as json (not just the message-text)
 | |
| 
 | |
| example usage as a volflag (per-volume config):
 | |
|     python copyparty-sfx.py -v srv/log:log:r:c,xm=j,bin/hooks/msg-log.py
 | |
|                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
| 
 | |
|     (share filesystem-path srv/log as volume /log, readable by everyone,
 | |
|      running this plugin on all messages with the params explained above)
 | |
| 
 | |
| example usage as a volflag in a copyparty config file:
 | |
|     [/log]
 | |
|       srv/log
 | |
|       accs:
 | |
|         r: *
 | |
|       flags:
 | |
|         xm: j,bin/hooks/msg-log.py
 | |
| """
 | |
| 
 | |
| 
 | |
| # output filename
 | |
| FILENAME = os.environ.get("COPYPARTY_MESSAGE_FILENAME", "") or "README.md"
 | |
| 
 | |
| # set True to write in descending order (newest message at top of file);
 | |
| # note that this becomes very slow/expensive as the file gets bigger
 | |
| DESCENDING = True
 | |
| 
 | |
| # the message template; the following parameters are provided by copyparty and can be referenced below:
 | |
| # 'ap' = absolute filesystem path where the message was posted
 | |
| # 'vp' = virtual path (URL 'path') where the message was posted
 | |
| # 'mt' = 'at' = unix-timestamp when the message was posted
 | |
| # 'datetime' = ISO-8601 time when the message was posted
 | |
| # 'sz' = message size in bytes
 | |
| # 'host' = the server hostname which the user was accessing (URL 'host')
 | |
| # 'user' = username (if logged in), otherwise '*'
 | |
| # 'txt' = the message text itself
 | |
| # (uncomment the print(msg_info) to see if additional information has been introduced by copyparty since this was written)
 | |
| TEMPLATE = """
 | |
| 🕒 %(datetime)s, 👤 %(user)s @ %(ip)s
 | |
| %(txt)s
 | |
| """
 | |
| 
 | |
| 
 | |
| def write_ascending(filepath, msg_text):
 | |
|     with open(filepath, "a", encoding="utf-8", errors="replace") as outfile:
 | |
|         outfile.write(msg_text)
 | |
| 
 | |
| 
 | |
| def write_descending(filepath, msg_text):
 | |
|     lockpath = filepath + ".lock"
 | |
|     got_it = False
 | |
|     for _ in range(16):
 | |
|         try:
 | |
|             os.mkdir(lockpath)
 | |
|             got_it = True
 | |
|             break
 | |
|         except:
 | |
|             time.sleep(0.1)
 | |
|             continue
 | |
| 
 | |
|     if not got_it:
 | |
|         return sys.exit(1)
 | |
| 
 | |
|     try:
 | |
|         oldpath = filepath + ".old"
 | |
|         os.rename(filepath, oldpath)
 | |
|         with open(oldpath, "r", encoding="utf-8", errors="replace") as infile, open(
 | |
|             filepath, "w", encoding="utf-8", errors="replace"
 | |
|         ) as outfile:
 | |
|             outfile.write(msg_text)
 | |
|             while True:
 | |
|                 buf = infile.read(4096)
 | |
|                 if not buf:
 | |
|                     break
 | |
|                 outfile.write(buf)
 | |
|     finally:
 | |
|         try:
 | |
|             os.unlink(oldpath)
 | |
|         except:
 | |
|             pass
 | |
|         os.rmdir(lockpath)
 | |
| 
 | |
| 
 | |
| def main(argv=None):
 | |
|     if argv is None:
 | |
|         argv = sys.argv
 | |
| 
 | |
|     msg_info = json.loads(sys.argv[1])
 | |
|     # print(msg_info)
 | |
| 
 | |
|     try:
 | |
|         dt = datetime.fromtimestamp(msg_info["at"], timezone.utc)
 | |
|     except:
 | |
|         dt = datetime.utcfromtimestamp(msg_info["at"])
 | |
| 
 | |
|     msg_info["datetime"] = dt.strftime("%Y-%m-%d, %H:%M:%S")
 | |
| 
 | |
|     msg_text = TEMPLATE % msg_info
 | |
| 
 | |
|     filepath = os.path.join(msg_info["ap"], FILENAME)
 | |
| 
 | |
|     if DESCENDING and os.path.exists(filepath):
 | |
|         write_descending(filepath, msg_text)
 | |
|     else:
 | |
|         write_ascending(filepath, msg_text)
 | |
| 
 | |
|     print(msg_text)
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |