changeset 2e06b12f3938 in /home/hg/repos/gajim-plugins
author: lovetox forenjunkie@chelo.at branches: details:gajim-plugins?cmd=changeset;node=2e06b12f3938 description: Add file storing to harddisk and thumbnail cache
diffstat:
url_image_preview/manifest.ini | 2 +- url_image_preview/url_image_preview.py | 392 ++++++++++++++++++++------------ 2 files changed, 241 insertions(+), 153 deletions(-)
diffs (truncated from 651 to 300 lines):
diff -r 1938ce0462db -r 2e06b12f3938 url_image_preview/manifest.ini --- a/url_image_preview/manifest.ini Fri Sep 02 22:33:45 2016 +0200 +++ b/url_image_preview/manifest.ini Sun Sep 04 23:30:39 2016 +0200 @@ -1,7 +1,7 @@ [info] name: Url image preview short_name: url_image_preview -version: 0.7.5 +version: 0.8.0 description: Url image preview in chatbox.<br/> Based on patch in <a href="http://trac.gajim.org/attachment/ticket/5300">ticket #5300</a>. authors = Denis Fomin fominde@gmail.com diff -r 1938ce0462db -r 2e06b12f3938 url_image_preview/url_image_preview.py --- a/url_image_preview/url_image_preview.py Fri Sep 02 22:33:45 2016 +0200 +++ b/url_image_preview/url_image_preview.py Sun Sep 04 23:30:39 2016 +0200 @@ -4,7 +4,9 @@ import gobject import re import os +import sys import urllib2 +import hashlib from urlparse import urlparse
import logging @@ -12,6 +14,7 @@ from common import gajim from common import ged from common import helpers +from common import configpaths from plugins import GajimPlugin from plugins.helpers import log_calls, log from plugins.gui import GajimPluginConfigDialog @@ -24,6 +27,12 @@
log = logging.getLogger('gajim.plugin_system.url_image_preview')
+try: + from PIL import Image + pil_available = True +except: + pil_available = False + log.debug('PIL not available')
try: if os.name == 'nt': @@ -53,13 +62,11 @@ self.gui_extension_points = { 'chat_control_base': (self.connect_with_chat_control, self.disconnect_from_chat_control), - 'print_special_text': (self.print_special_text, - self.print_special_text1), } + 'print_special_text': (self.print_special_text, None), } self.config_default_values = { 'PREVIEW_SIZE': (150, 'Preview size(10-512)'), 'MAX_FILE_SIZE': (524288, 'Max file size for image preview')} - self.chat_control = None - self.controls = [] + self.controls = {}
# remove oob tag if oob url == message text def handle_message_received(self, event): @@ -69,37 +76,35 @@ if oob_node: oob_url = oob_node.getTagData('url') oob_desc = oob_node.getTagData('desc') - if oob_url and oob_url == event.msgtxt and (not oob_desc or oob_desc == ""): - log.debug("Detected oob tag containing same url as the message text, deleting oob tag...") + if oob_url and oob_url == event.msgtxt and \ + (not oob_desc or oob_desc == ""): + log.debug("Detected oob tag containing same" + "url as the message text, deleting oob tag...") event.stanza.delChild(oob_node)
@log_calls('UrlImagePreviewPlugin') def connect_with_chat_control(self, chat_control): - - self.chat_control = chat_control - control = Base(self, self.chat_control) - self.controls.append(control) + account = chat_control.contact.account.name + jid = chat_control.contact.jid + if account not in self.controls: + self.controls[account] = {} + self.controls[account][jid] = Base(self, chat_control)
@log_calls('UrlImagePreviewPlugin') def disconnect_from_chat_control(self, chat_control): - for control in self.controls: - control.disconnect_from_chat_control() - self.controls = [] + account = chat_control.contact.account.name + jid = chat_control.contact.jid + del self.controls[account][jid]
def print_special_text(self, tv, special_text, other_tags, graphics=True, iter_=None): - for control in self.controls: - if control.chat_control.conv_textview != tv: + account = tv.account + for jid in self.controls[account]: + if self.controls[account][jid].chat_control.conv_textview != tv: continue - control.print_special_text(special_text, other_tags, graphics=True, - iter_=iter_) - - def print_special_text1(self, chat_control, special_text, other_tags=None, - graphics=True, iter_=None): - for control in self.controls: - if control.chat_control == chat_control: - control.disconnect_from_chat_control() - self.controls.remove(control) + self.controls[account][jid].print_special_text( + special_text, other_tags, graphics=True, iter_=iter_) + return
class Base(object): @@ -112,6 +117,15 @@ else: self.backend = default_backend()
+ self.directory = os.path.join(configpaths.gajimpaths['MY_CACHE'], + 'downloads') + self.thumbpath = os.path.join(self.directory, 'thumb') + + try: + self.create_path(self.thumbpath) + except Exception as e: + log.debug(e) + def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): # remove qip bbcode @@ -122,9 +136,9 @@ if special_text.startswith('ftp.'): special_text = 'ftp://' + special_text
- parts = urlparse(special_text) - if parts.scheme not in ["https", "http", "ftp", "ftps"] or \ - not parts.netloc: + urlparts = urlparse(special_text) + if urlparts.scheme not in ["https", "http", "ftp", "ftps"] or \ + not urlparts.netloc: log.info("Not accepting URL for image preview: %s" % special_text) return
@@ -132,96 +146,113 @@ if not iter_: iter_ = buffer_.get_end_iter()
- # Detect XHTML-IM link + # Show URL, until image is loaded (if ever) ttt = buffer_.get_tag_table() - tags_ = [(ttt.lookup(t) if isinstance(t, str) else t) for t in other_tags] - for t in tags_: - is_xhtml_link = getattr(t, 'href', None) - if is_xhtml_link: - break - - # Show URL, until image is loaded (if ever) repl_start = buffer_.create_mark(None, iter_, True) - buffer_.insert_with_tags(iter_, special_text, \ + buffer_.insert_with_tags(iter_, special_text, *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True)
- # First get the http head request with does not fetch data, just headers - gajim.thread_interface(self._get_http_head, [self.textview.account, - special_text], self._check_mime_size, [special_text, repl_start, repl_end]) + filename = os.path.basename(urlparts.path) + ext = os.path.splitext(filename)[1] + name = os.path.splitext(filename)[0] + namehash = hashlib.sha1(special_text).hexdigest() + newfilename = name + '_' + namehash + ext + thumbfilename = name + '_' + namehash + '_thumb' + ext + + filepath = os.path.join(self.directory, newfilename) + thumbpath = os.path.join(self.thumbpath, thumbfilename) + filepaths = [filepath, thumbpath] + + if os.path.exists(filepath): + def open_file(): + with open(filepath, 'rb') as f: + mem = f.read() + f.closed + log.debug('File from disk') + return (mem, '') + + if pil_available: + if not os.path.exists(thumbpath): + self.save_thumbnail(filepaths) + tup = (True, '') + gajim.thread_interface(self._update_img, + [tup, special_text, repl_start, + repl_end, filepaths]) + else: + gajim.thread_interface( + open_file, [], + self._update_img, [special_text, repl_start, + repl_end, filepaths]) + + else: + key = '' + iv = '' + encrypted = False + if len(urlparts.fragment): + fragment = [] + for i in range(0, len(urlparts.fragment), 2): + fragment.append(chr(int(urlparts.fragment[i:i + 2], 16))) + fragment = ''.join(fragment) + key = fragment[16:] + iv = fragment[:16] + if len(key) == 32 and len(iv) == 16: + encrypted = True + + if encrypted: + if decryption_available: + # First get the http head request + # which does not fetch data, just headers + gajim.thread_interface( + self._get_http_head, + [self.textview.account, special_text], + self._check_mime_size, + [special_text, repl_start, repl_end, + filepaths, key, iv, encrypted]) + else: + log.debug('Please install Crytography to decrypt pictures') + else: + # First get the http head request + # which does not fetch data, just headers + gajim.thread_interface( + self._get_http_head, [self.textview.account, special_text], + self._check_mime_size, [special_text, repl_start, repl_end, + filepaths, key, iv, encrypted])
# Don't print the URL in the message window (in the calling function) self.textview.plugin_modified = True
- def _check_mime_size(self, (file_mime, file_size), url, repl_start, repl_end): + def _check_mime_size(self, (file_mime, file_size), + url, repl_start, repl_end, filepaths, + key, iv, encrypted): # Check if mime type is acceptable if file_mime == '' and file_size == 0: - log.info("Failed to load HEAD Request for URL: '%s' (see debug log for more info)" % url) + log.info("Failed to load HEAD Request for URL: '%s'" + "(see debug log for more info)" % url) # URL is already displayed return if file_mime.lower() not in ACCEPTED_MIME_TYPES: - log.info("Not accepted mime type '%s' for URL: '%s'" % (file_mime.lower(), url)) + log.info("Not accepted mime type '%s' for URL: '%s'" + % (file_mime.lower(), url)) # URL is already displayed return # Check if file size is acceptable if file_size > self.plugin.config['MAX_FILE_SIZE'] or file_size == 0: - log.info("File size (%s) too big or unknown (zero) for URL: '%s'" % (str(file_size), url)) + log.info("File size (%s) too big or unknown (zero) for URL: '%s'" + % (str(file_size), url)) # URL is already displayed return
- # check for encryption (conversations mode) - urlparts = urlparse(url) - key = '' - iv = '' - if len(urlparts.fragment): - fragment = [] - for i in range(0, len(urlparts.fragment), 2): - fragment.append(chr(int(urlparts.fragment[i:i + 2], 16))) - fragment = ''.join(fragment) - key = fragment[16:] - iv = fragment[:16] + attributes = {'src': url, + 'max_size': self.plugin.config['MAX_FILE_SIZE'], + 'filepaths': filepaths, + 'key': key, + 'iv': iv}
- # decrypt if the encryption parameters are correct - if len(urlparts.fragment) and len(key) == 32 and len(iv) == 16: - def _decryptor((mem, alt), url, file_mime, repl_start, repl_end, key, iv): - if not mem: - log.error('Could not download image for URL: %s -- %s' % (url, alt)) - return - # start self._decrypt_url() in own thread and self._update_img() afterwards - gajim.thread_interface( - self._decrypt_url, - [(mem, alt), key, iv, url], - self._update_img, - [url, file_mime, repl_start, repl_end, True]) - - # Start downloading image (_decryptor is callback when download has finished) - gajim.thread_interface(self._download_image, [ self.textview.account, { - 'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'] } ], - _decryptor, [url, file_mime, repl_start, repl_end, key, iv]) - else: - # Start downloading image (self._update_img() is callback when download has finished)