| 
					
				 | 
			
			
				@@ -1,13 +1,21 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# Usage: sonarr_sync.py my-seedbox /seedbox/path/to/data /local/working /local/metadata /local/data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# Get all file names in HOST:HOST_DATA_PATH 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# Get all previously processed file names in LOCAL_METADATA_PATH 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# Diff the above to get newly added files 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-# For each new file: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#   Copy file to LOCAL_WORKING_PATH (used in case of transfer failure) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#   Add file name to LOCAL_METADATA_PATH 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#   Move file to LOCAL_DATA_PATH 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# rsync files from a seedbox to a local machine, exactly once, over SSH. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# Why? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  sonarr requires that any Remote Path Mappings have a local path reflecting its contents. This can be done with NFS or SSHFS, but those are difficult to set up in containers, and get wonky when the remote server reboots. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  rsync over SSH + cron doesn't care if the remote machine reboots, + easily runs in a container. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# How? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  Usage: sonarr_sync.py my-seedbox /seedbox/path/to/data /local/working /local/metadata /local/data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  - Get all file names in my-seedbox:/seedbox/path/to/data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  - Get all previously processed file names in /local/metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  - Diff the above to get newly added files 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#  - For each new file: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#    - Copy file from my-seedbox to /local/working (used in case of transfer failure) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#    - Add file name to /local/metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#    - Move file to /local/data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # */1 * * * * /usr/bin/run-one /usr/bin/python3 /path/to/seedbox_sync.py <seedbox host> /seedbox/path/to/completed/ /local/path/to/downloading /local/path/to/processed /local/path/to/ready 2>&1 | /usr/bin/logger -t seedbox 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# Or run it in a k8s cronjob. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import subprocess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import sys 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -23,6 +31,7 @@ r = subprocess.run(["ssh", host, "bash", "-c", f"IFS=$'\n'; ls {host_data_path}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 available = {f for f in r.stdout.decode().split('\n') if f} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# There's better ways to list a dir locally, but using bash +ls again avoids any possible formatting discrepencies. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 r = subprocess.run(["bash", "-c", f"IFS=$'\n'; ls {local_metadata_path}"], stdout=subprocess.PIPE, check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 processed = {f for f in r.stdout.decode().split('\n') if f} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -36,8 +45,14 @@ for new_file in new: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     print(f"Processing: {new_file}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     subprocess.run(["rsync", "-rsvv", f'{host}:{host_data_path}/{new_file}', f'{local_working_path}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    r = subprocess.run(["touch", f'{local_metadata_path}/{new_file}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subprocess.run(["touch", f'{local_metadata_path}/{new_file}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     print(f"Moving to ready: {new_file}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    subprocess.run(["rsync", "-r", f'{local_working_path}/{new_file}', f'{local_data_path}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # rsync here is probably overkill 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        subprocess.run(["rsync", "-r", f'{local_working_path}/{new_file}', f'{local_data_path}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    except: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        subprocess.run(["rm", f'{local_metadata_path}/{new_file}'], check=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        raise 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     subprocess.run(["rm", "-rf", f'{local_working_path}/{new_file}'], check=True) 
			 |