Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0446.py @ 3896:dbf0c7faaf49
plugin XEP-0446: File Metadata implementation:
rel 379
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 21 Sep 2022 22:27:28 +0200 |
parents | |
children | 0ff265725489 |
comparison
equal
deleted
inserted
replaced
3895:eb0a77bea363 | 3896:dbf0c7faaf49 |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 # Copyright (C) 2009-2022 Jérôme Poisson (goffi@goffi.org) | |
4 | |
5 # This program is free software: you can redistribute it and/or modify | |
6 # it under the terms of the GNU Affero General Public License as published by | |
7 # the Free Software Foundation, either version 3 of the License, or | |
8 # (at your option) any later version. | |
9 | |
10 # This program is distributed in the hope that it will be useful, | |
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 # GNU Affero General Public License for more details. | |
14 | |
15 # You should have received a copy of the GNU Affero General Public License | |
16 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | |
18 from logging import exception | |
19 from typing import Optional, Union, Tuple, Dict, Any | |
20 from pathlib import Path | |
21 | |
22 from twisted.words.xish import domish | |
23 | |
24 from sat.core.constants import Const as C | |
25 from sat.core.i18n import _ | |
26 from sat.core.log import getLogger | |
27 from sat.core import exceptions | |
28 from sat.tools import utils | |
29 | |
30 log = getLogger(__name__) | |
31 | |
32 | |
33 PLUGIN_INFO = { | |
34 C.PI_NAME: "File Metadata Element", | |
35 C.PI_IMPORT_NAME: "XEP-0446", | |
36 C.PI_TYPE: "XEP", | |
37 C.PI_MODES: C.PLUG_MODE_BOTH, | |
38 C.PI_PROTOCOLS: ["XEP-0446"], | |
39 C.PI_DEPENDENCIES: ["XEP-0300"], | |
40 C.PI_MAIN: "XEP_0446", | |
41 C.PI_HANDLER: "no", | |
42 C.PI_DESCRIPTION: _("""Implementation of XEP-0446 (File Metadata Element)"""), | |
43 } | |
44 | |
45 NS_FILE_METADATA = "urn:xmpp:file:metadata:0" | |
46 | |
47 | |
48 class XEP_0446: | |
49 | |
50 def __init__(self, host): | |
51 log.info(_("XEP-0446 (File Metadata Element) plugin initialization")) | |
52 host.registerNamespace("file-metadata", NS_FILE_METADATA) | |
53 self._hash = host.plugins["XEP-0300"] | |
54 | |
55 def get_file_metadata_elt( | |
56 self, | |
57 name: Optional[str] = None, | |
58 media_type: Optional[str] = None, | |
59 desc: Optional[str] = None, | |
60 size: Optional[int] = None, | |
61 file_hash: Optional[Tuple[str, str]] = None, | |
62 date: Optional[Union[float, int]] = None, | |
63 width: Optional[int] = None, | |
64 height: Optional[int] = None, | |
65 length: Optional[int] = None, | |
66 thumbnail: Optional[str] = None, | |
67 ) -> domish.Element: | |
68 """Generate the element describing a file | |
69 | |
70 @param name: name of the file | |
71 @param media_type: media-type | |
72 @param desc: description | |
73 @param size: size in bytes | |
74 @param file_hash: (algo, hash) | |
75 @param date: timestamp of the last modification datetime | |
76 @param width: image width in pixels | |
77 @param height: image height in pixels | |
78 @param length: video length in seconds | |
79 @param thumbnail: URL to a thumbnail | |
80 @return: ``<file/>`` element | |
81 """ | |
82 if name: | |
83 name = Path(name).name | |
84 file_elt = domish.Element((NS_FILE_METADATA, "file")) | |
85 for name, value in ( | |
86 ("name", name), | |
87 ("media-type", media_type), | |
88 ("desc", desc), | |
89 ("size", size), | |
90 ("width", width), | |
91 ("height", height), | |
92 ("length", length), | |
93 ): | |
94 if value is not None: | |
95 file_elt.addElement(name, content=str(value)) | |
96 if file_hash is not None: | |
97 hash_algo, hash_ = file_hash | |
98 file_elt.addChild(self._hash.buildHashElt(hash_, hash_algo)) | |
99 if date is not None: | |
100 file_elt.addElement("date", utils.xmpp_date(date)) | |
101 if thumbnail is not None: | |
102 # TODO: implement thumbnails | |
103 log.warning("thumbnail is not implemented yet") | |
104 return file_elt | |
105 | |
106 def parse_file_metadata_elt( | |
107 self, | |
108 file_metadata_elt: domish.Element | |
109 ) -> Dict[str, Any]: | |
110 """Parse <file-metadata/> element | |
111 | |
112 @param file_metadata_elt: <file-metadata/> element | |
113 a parent element can also be used | |
114 @return: file-metadata data. It's a dict whose keys correspond to | |
115 [get_file_metadata_elt] parameters | |
116 @raise exceptions.NotFound: no <file-metadata/> element has been found | |
117 """ | |
118 | |
119 if file_metadata_elt.name != "file-metadata": | |
120 try: | |
121 file_metadata_elt = next( | |
122 file_metadata_elt.elements(NS_FILE_METADATA, "file-metadata") | |
123 ) | |
124 except StopIteration: | |
125 raise exceptions.NotFound | |
126 data: Dict[str, Any] = {} | |
127 | |
128 for key, type_ in ( | |
129 ("name", str), | |
130 ("media-type", str), | |
131 ("desc", str), | |
132 ("size", int), | |
133 ("date", "timestamp"), | |
134 ("width", int), | |
135 ("height", int), | |
136 ("length", int), | |
137 ): | |
138 elt = next(file_metadata_elt.elements(NS_FILE_METADATA, key), None) | |
139 if elt is not None: | |
140 if type_ in (str, int): | |
141 content = str(elt) | |
142 if key == "name": | |
143 # we avoid malformed names or names containing path elements | |
144 content = Path(content).name | |
145 elif key == "media-type": | |
146 key = "media_type" | |
147 data[key] = type_(content) | |
148 elif type == "timestamp": | |
149 data[key] = utils.parse_xmpp_date(str(elt)) | |
150 else: | |
151 raise exceptions.InternalError | |
152 | |
153 try: | |
154 algo, hash_ = self._hash.parseHashElt(file_metadata_elt) | |
155 except exceptions.NotFound: | |
156 pass | |
157 except exceptions.DataError: | |
158 from sat.tools.xml_tools import pFmtElt | |
159 log.warning("invalid <hash/> element:\n{pFmtElt(file_metadata_elt)}") | |
160 else: | |
161 data["file_hash"] = (algo, hash_.decode()) | |
162 | |
163 # TODO: thumbnails | |
164 | |
165 return data |