| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | import os | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .common import PostProcessor | 
					
						
							|  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |     check_executable, | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  |     hyphenate_date, | 
					
						
							| 
									
										
										
										
											2014-05-16 12:03:59 +02:00
										 |  |  |     subprocess_check_output | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class XAttrMetadataPP(PostProcessor): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # More info about extended attributes for media: | 
					
						
							|  |  |  |     #   http://freedesktop.org/wiki/CommonExtendedAttributes/ | 
					
						
							|  |  |  |     #   http://www.freedesktop.org/wiki/PhreedomDraft/ | 
					
						
							|  |  |  |     #   http://dublincore.org/documents/usageguide/elements.shtml | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # TODO: | 
					
						
							|  |  |  |     #  * capture youtube keywords and put them in 'user.dublincore.subject' (comma-separated) | 
					
						
							|  |  |  |     #  * figure out which xattrs can be used for 'duration', 'thumbnail', 'resolution' | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run(self, info): | 
					
						
							|  |  |  |         """ Set extended attributes on downloaded file (if xattr support is found). """ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # This mess below finds the best xattr tool for the job and creates a | 
					
						
							|  |  |  |         # "write_xattr" function. | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # try the pyxattr module... | 
					
						
							|  |  |  |             import xattr | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  |             def write_xattr(path, key, value): | 
					
						
							|  |  |  |                 return xattr.setxattr(path, key, value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except ImportError: | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |             if os.name == 'nt': | 
					
						
							|  |  |  |                 # Write xattrs to NTFS Alternate Data Streams: | 
					
						
							|  |  |  |                 # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29 | 
					
						
							|  |  |  |                 def write_xattr(path, key, value): | 
					
						
							| 
									
										
										
										
											2014-01-07 06:50:24 +01:00
										 |  |  |                     assert ':' not in key | 
					
						
							|  |  |  |                     assert os.path.exists(path) | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |                     ads_fn = path + ":" + key | 
					
						
							| 
									
										
										
										
											2014-01-07 06:50:24 +01:00
										 |  |  |                     with open(ads_fn, "wb") as f: | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |                         f.write(value) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 user_has_setfattr = check_executable("setfattr", ['--version']) | 
					
						
							|  |  |  |                 user_has_xattr = check_executable("xattr", ['-h']) | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if user_has_setfattr or user_has_xattr: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     def write_xattr(path, key, value): | 
					
						
							|  |  |  |                         if user_has_setfattr: | 
					
						
							|  |  |  |                             cmd = ['setfattr', '-n', key, '-v', value, path] | 
					
						
							|  |  |  |                         elif user_has_xattr: | 
					
						
							|  |  |  |                             cmd = ['xattr', '-w', key, value, path] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-16 12:03:59 +02:00
										 |  |  |                         subprocess_check_output(cmd) | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     # On Unix, and can't find pyxattr, setfattr, or xattr. | 
					
						
							|  |  |  |                     if sys.platform.startswith('linux'): | 
					
						
							| 
									
										
										
										
											2014-01-07 06:12:28 +01:00
										 |  |  |                         self._downloader.report_error( | 
					
						
							|  |  |  |                             "Couldn't find a tool to set the xattrs. " | 
					
						
							|  |  |  |                             "Install either the python 'pyxattr' or 'xattr' " | 
					
						
							|  |  |  |                             "modules, or the GNU 'attr' package " | 
					
						
							|  |  |  |                             "(which contains the 'setfattr' tool).") | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         self._downloader.report_error( | 
					
						
							|  |  |  |                             "Couldn't find a tool to set the xattrs. " | 
					
						
							|  |  |  |                             "Install either the python 'xattr' module, " | 
					
						
							|  |  |  |                             "or the 'xattr' binary.") | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Write the metadata to the file's xattrs | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |         self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs') | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         filename = info['filepath'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             xattr_mapping = { | 
					
						
							|  |  |  |                 'user.xdg.referrer.url': 'webpage_url', | 
					
						
							|  |  |  |                 # 'user.xdg.comment':            'description', | 
					
						
							|  |  |  |                 'user.dublincore.title': 'title', | 
					
						
							|  |  |  |                 'user.dublincore.date': 'upload_date', | 
					
						
							|  |  |  |                 'user.dublincore.description': 'description', | 
					
						
							|  |  |  |                 'user.dublincore.contributor': 'uploader', | 
					
						
							|  |  |  |                 'user.dublincore.format': 'format', | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for xattrname, infoname in xattr_mapping.items(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 value = info.get(infoname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if value: | 
					
						
							|  |  |  |                     if infoname == "upload_date": | 
					
						
							|  |  |  |                         value = hyphenate_date(value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-07 06:49:15 +01:00
										 |  |  |                     byte_value = value.encode('utf-8') | 
					
						
							| 
									
										
										
										
											2014-01-07 06:11:21 +01:00
										 |  |  |                     write_xattr(filename, xattrname, byte_value) | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return True, info | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-07 06:34:55 +01:00
										 |  |  |         except (subprocess.CalledProcessError, OSError): | 
					
						
							| 
									
										
										
										
											2014-01-07 05:59:22 +01:00
										 |  |  |             self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)") | 
					
						
							|  |  |  |             return False, info | 
					
						
							|  |  |  | 
 |