]>
Commit | Line | Data |
---|---|---|
dcddc10a PH |
1 | from __future__ import unicode_literals |
2 | ||
496c1923 PH |
3 | import os |
4 | import subprocess | |
5 | import sys | |
6 | ||
7 | from .common import PostProcessor | |
8c25f81b PH |
8 | from ..compat import ( |
9 | subprocess_check_output | |
10 | ) | |
496c1923 | 11 | from ..utils import ( |
168da92b | 12 | check_executable, |
496c1923 | 13 | hyphenate_date, |
8c882617 | 14 | version_tuple, |
496c1923 PH |
15 | ) |
16 | ||
17 | ||
18 | class XAttrMetadataPP(PostProcessor): | |
19 | ||
20 | # | |
21 | # More info about extended attributes for media: | |
22 | # http://freedesktop.org/wiki/CommonExtendedAttributes/ | |
23 | # http://www.freedesktop.org/wiki/PhreedomDraft/ | |
24 | # http://dublincore.org/documents/usageguide/elements.shtml | |
25 | # | |
26 | # TODO: | |
27 | # * capture youtube keywords and put them in 'user.dublincore.subject' (comma-separated) | |
28 | # * figure out which xattrs can be used for 'duration', 'thumbnail', 'resolution' | |
29 | # | |
30 | ||
31 | def run(self, info): | |
32 | """ Set extended attributes on downloaded file (if xattr support is found). """ | |
33 | ||
34 | # This mess below finds the best xattr tool for the job and creates a | |
35 | # "write_xattr" function. | |
36 | try: | |
37 | # try the pyxattr module... | |
38 | import xattr | |
168da92b | 39 | |
8c882617 YCH |
40 | # Unicode arguments are not supported in python-pyxattr until |
41 | # version 0.5.0 | |
42 | # See https://github.com/rg3/youtube-dl/issues/5498 | |
43 | pyxattr_required_version = '0.5.0' | |
44 | if version_tuple(xattr.__version__) < version_tuple(pyxattr_required_version): | |
45 | self._downloader.report_warning( | |
46 | 'python-pyxattr is detected but is too old. ' | |
47 | 'yourube-dl requires %s or above while your version is %s. ' | |
48 | 'Falling back to other xattr implementations' % ( | |
49 | pyxattr_required_version, xattr.__version__)) | |
50 | ||
51 | raise ImportError | |
52 | ||
496c1923 PH |
53 | def write_xattr(path, key, value): |
54 | return xattr.setxattr(path, key, value) | |
55 | ||
56 | except ImportError: | |
168da92b PH |
57 | if os.name == 'nt': |
58 | # Write xattrs to NTFS Alternate Data Streams: | |
59 | # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29 | |
60 | def write_xattr(path, key, value): | |
a9ce0c63 PH |
61 | assert ':' not in key |
62 | assert os.path.exists(path) | |
496c1923 | 63 | |
168da92b | 64 | ads_fn = path + ":" + key |
a9ce0c63 | 65 | with open(ads_fn, "wb") as f: |
168da92b PH |
66 | f.write(value) |
67 | else: | |
68 | user_has_setfattr = check_executable("setfattr", ['--version']) | |
69 | user_has_xattr = check_executable("xattr", ['-h']) | |
496c1923 PH |
70 | |
71 | if user_has_setfattr or user_has_xattr: | |
72 | ||
73 | def write_xattr(path, key, value): | |
496c1923 PH |
74 | if user_has_setfattr: |
75 | cmd = ['setfattr', '-n', key, '-v', value, path] | |
76 | elif user_has_xattr: | |
77 | cmd = ['xattr', '-w', key, value, path] | |
78 | ||
0a871f68 | 79 | subprocess_check_output(cmd) |
496c1923 PH |
80 | |
81 | else: | |
82 | # On Unix, and can't find pyxattr, setfattr, or xattr. | |
83 | if sys.platform.startswith('linux'): | |
2a2e2770 PH |
84 | self._downloader.report_error( |
85 | "Couldn't find a tool to set the xattrs. " | |
86 | "Install either the python 'pyxattr' or 'xattr' " | |
87 | "modules, or the GNU 'attr' package " | |
88 | "(which contains the 'setfattr' tool).") | |
89 | else: | |
90 | self._downloader.report_error( | |
91 | "Couldn't find a tool to set the xattrs. " | |
92 | "Install either the python 'xattr' module, " | |
93 | "or the 'xattr' binary.") | |
496c1923 PH |
94 | |
95 | # Write the metadata to the file's xattrs | |
168da92b | 96 | self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs') |
496c1923 PH |
97 | |
98 | filename = info['filepath'] | |
99 | ||
100 | try: | |
101 | xattr_mapping = { | |
102 | 'user.xdg.referrer.url': 'webpage_url', | |
103 | # 'user.xdg.comment': 'description', | |
104 | 'user.dublincore.title': 'title', | |
105 | 'user.dublincore.date': 'upload_date', | |
106 | 'user.dublincore.description': 'description', | |
107 | 'user.dublincore.contributor': 'uploader', | |
108 | 'user.dublincore.format': 'format', | |
109 | } | |
110 | ||
111 | for xattrname, infoname in xattr_mapping.items(): | |
112 | ||
113 | value = info.get(infoname) | |
114 | ||
115 | if value: | |
116 | if infoname == "upload_date": | |
117 | value = hyphenate_date(value) | |
118 | ||
afc7bc33 | 119 | byte_value = value.encode('utf-8') |
42cc71e8 | 120 | write_xattr(filename, xattrname, byte_value) |
496c1923 | 121 | |
592e97e8 | 122 | return [], info |
496c1923 | 123 | |
168da92b | 124 | except (subprocess.CalledProcessError, OSError): |
496c1923 | 125 | self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)") |
592e97e8 | 126 | return [], info |