You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.1 KiB

  1. from __future__ import unicode_literals
  2. import os
  3. import subprocess
  4. import sys
  5. from .common import PostProcessor
  6. from ..compat import (
  7. subprocess_check_output
  8. )
  9. from ..utils import (
  10. check_executable,
  11. hyphenate_date,
  12. )
  13. class XAttrMetadataPP(PostProcessor):
  14. #
  15. # More info about extended attributes for media:
  16. # http://freedesktop.org/wiki/CommonExtendedAttributes/
  17. # http://www.freedesktop.org/wiki/PhreedomDraft/
  18. # http://dublincore.org/documents/usageguide/elements.shtml
  19. #
  20. # TODO:
  21. # * capture youtube keywords and put them in 'user.dublincore.subject' (comma-separated)
  22. # * figure out which xattrs can be used for 'duration', 'thumbnail', 'resolution'
  23. #
  24. def run(self, info):
  25. """ Set extended attributes on downloaded file (if xattr support is found). """
  26. # This mess below finds the best xattr tool for the job and creates a
  27. # "write_xattr" function.
  28. try:
  29. # try the pyxattr module...
  30. import xattr
  31. def write_xattr(path, key, value):
  32. return xattr.setxattr(path, key, value)
  33. except ImportError:
  34. if os.name == 'nt':
  35. # Write xattrs to NTFS Alternate Data Streams:
  36. # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29
  37. def write_xattr(path, key, value):
  38. assert ':' not in key
  39. assert os.path.exists(path)
  40. ads_fn = path + ":" + key
  41. with open(ads_fn, "wb") as f:
  42. f.write(value)
  43. else:
  44. user_has_setfattr = check_executable("setfattr", ['--version'])
  45. user_has_xattr = check_executable("xattr", ['-h'])
  46. if user_has_setfattr or user_has_xattr:
  47. def write_xattr(path, key, value):
  48. if user_has_setfattr:
  49. cmd = ['setfattr', '-n', key, '-v', value, path]
  50. elif user_has_xattr:
  51. cmd = ['xattr', '-w', key, value, path]
  52. subprocess_check_output(cmd)
  53. else:
  54. # On Unix, and can't find pyxattr, setfattr, or xattr.
  55. if sys.platform.startswith('linux'):
  56. self._downloader.report_error(
  57. "Couldn't find a tool to set the xattrs. "
  58. "Install either the python 'pyxattr' or 'xattr' "
  59. "modules, or the GNU 'attr' package "
  60. "(which contains the 'setfattr' tool).")
  61. else:
  62. self._downloader.report_error(
  63. "Couldn't find a tool to set the xattrs. "
  64. "Install either the python 'xattr' module, "
  65. "or the 'xattr' binary.")
  66. # Write the metadata to the file's xattrs
  67. self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs')
  68. filename = info['filepath']
  69. try:
  70. xattr_mapping = {
  71. 'user.xdg.referrer.url': 'webpage_url',
  72. # 'user.xdg.comment': 'description',
  73. 'user.dublincore.title': 'title',
  74. 'user.dublincore.date': 'upload_date',
  75. 'user.dublincore.description': 'description',
  76. 'user.dublincore.contributor': 'uploader',
  77. 'user.dublincore.format': 'format',
  78. }
  79. for xattrname, infoname in xattr_mapping.items():
  80. value = info.get(infoname)
  81. if value:
  82. if infoname == "upload_date":
  83. value = hyphenate_date(value)
  84. byte_value = value.encode('utf-8')
  85. write_xattr(filename, xattrname, byte_value)
  86. return True, info
  87. except (subprocess.CalledProcessError, OSError):
  88. self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)")
  89. return False, info