| 
					
				 | 
			
			
				@@ -5,13 +5,16 @@ import mutagen 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import mutagen.id3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import mutagen.mp4 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import os 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import re 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import subprocess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # http://id3.org/id3v2.4.0-frames#4.1. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 TRACK_UUID_ID3_OWNER_ID = 'symuid' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # freeform keys start with '----' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # http://mutagen.readthedocs.io/en/latest/api/mp4.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 TRACK_UUID_MP4_TAG = '----:symuid:uuid' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+PATH_DEFAULT_IGNORE_REGEX = r'\.(itdb|itc2|itl|jpg|midi?|plist|xml|zip)$' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 def generate_uuid(): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -58,18 +61,27 @@ def get_or_assign_uuid_mp4(mp4_file): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return mp4_file[TRACK_UUID_MP4_TAG][0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-def symuid_sync(path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if os.path.isdir(path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def symuid_sync(path, path_ignore_regex, show_ignored=False): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if path_ignore_regex.search(path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if show_ignored: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            print("{!r}: path matches ignore pattern".format(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    elif os.path.isdir(path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for dirpath, dirnames, filenames in os.walk(path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             for filename in filenames: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                symuid_sync(os.path.join(dirpath, filename)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                symuid_sync( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    os.path.join(dirpath, filename), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    path_ignore_regex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    show_ignored, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             f = mutagen.File(filename=path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         except Exception: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             raise Exception(path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if not f: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            print("{!r}: unsupported filetype, ignored".format(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sys.stderr.write( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "{!r}: unsupported filetype, skipped\n".format(path), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         elif isinstance(f, mutagen.mp4.MP4): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             get_or_assign_uuid_mp4(f) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         elif isinstance(f.tags, mutagen.id3.ID3): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -82,6 +94,19 @@ def _init_argparser(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     import argparse 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     argparser = argparse.ArgumentParser(description=None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     argparser.add_argument('path') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    argparser.add_argument( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        '--path-ignore-regex', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        default=PATH_DEFAULT_IGNORE_REGEX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        nargs=1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        metavar='pattern', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dest='path_ignore_regex', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type=lambda pattern: re.compile(pattern), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        help='(default: %(default)s)', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    argparser.add_argument( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        '--show-ignored', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        action='store_true', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return argparser 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -92,5 +117,4 @@ def main(argv): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 if __name__ == "__main__": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     sys.exit(main(sys.argv)) 
			 |