Commit e73114c0 authored by Daniel Brötzmann's avatar Daniel Brötzmann Committed by Philipp Hörist
Browse files

[preview] Cleanup code

parent 1a690149
......@@ -91,8 +91,8 @@ class UrlImagePreviewConfigDialog(SettingsDialog):
]
SettingsDialog.__init__(self, parent, _('UrlImagePreview Configuration'),
Gtk.DialogFlags.MODAL, settings, None,
extend=[
Gtk.DialogFlags.MODAL, settings, None,
extend=[
('PreviewSizeSpinSetting', SizeSpinSetting)])
def on_setting(self, value, data):
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-open</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-copy</property>
</object>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-symbolic-link</property>
</object>
<object class="GtkImage" id="image5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-symbolic-link</property>
</object>
<object class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">folder-download</property>
</object>
<requires lib="gtk+" version="3.20"/>
<object class="GtkMenu" id="context_menu">
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="open_menuitem">
<property name="label" translatable="yes">_Open</property>
<object class="GtkMenuItem" id="open_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Open</property>
<property name="use_underline">True</property>
<property name="image">image1</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="save_as_menuitem">
<property name="label" translatable="yes">_Save as</property>
<object class="GtkMenuItem" id="save_as_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Save as</property>
<property name="use_underline">True</property>
<property name="image">image2</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="open_folder_menuitem">
<property name="label" translatable="yes">Open _Folder</property>
<object class="GtkMenuItem" id="open_folder_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Open _Folder</property>
<property name="use_underline">True</property>
<property name="image">image6</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
<child>
......@@ -74,25 +35,19 @@
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="copy_link_location_menuitem">
<property name="label" translatable="yes">_Copy Link Location</property>
<object class="GtkMenuItem" id="copy_link_location_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Copy Link</property>
<property name="use_underline">True</property>
<property name="image">image3</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="open_link_in_browser_menuitem">
<property name="label" translatable="yes">Open Link in _Browser</property>
<object class="GtkMenuItem" id="open_link_in_browser_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Open Link in _Browser</property>
<property name="use_underline">True</property>
<property name="image">image4</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
<child>
......@@ -102,14 +57,11 @@
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="open_file_in_browser_menuitem">
<property name="label" translatable="yes">Open _Downloaded File in Browser</property>
<object class="GtkMenuItem" id="open_file_in_browser_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Open _Downloaded File in Browser</property>
<property name="use_underline">True</property>
<property name="image">image5</property>
<property name="use_stock">False</property>
<property name="always_show_image">True</property>
</object>
</child>
</object>
......
......@@ -47,17 +47,17 @@ def _get_http_head_direct(url, verify):
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
log.warning('CERT Verification disabled')
f = urllib2.urlopen(req, timeout=30, context=context)
file_ = urllib2.urlopen(req, timeout=30, context=context)
else:
if os.name == 'nt':
f = urllib2.urlopen(req, cafile=certifi.where())
file_ = urllib2.urlopen(req, cafile=certifi.where())
else:
f = urllib2.urlopen(req)
file_ = urllib2.urlopen(req)
except Exception as ex:
log.debug('Error', exc_info=True)
return ('', 0)
ctype = f.headers['Content-Type']
clen = f.headers['Content-Length']
ctype = file_.headers['Content-Type']
clen = file_.headers['Content-Length']
try:
clen = int(clen)
except (TypeError, ValueError):
......@@ -65,10 +65,10 @@ def _get_http_head_direct(url, verify):
return (ctype, clen)
def _get_http_direct(attrs):
"""
'''
Download a file. This function should
be launched in a separated thread.
"""
'''
log.info('Get request direct for URL: %s', attrs['src'])
mem, alt, max_size = b'', '', 2 * 1024 * 1024
if 'max_size' in attrs:
......@@ -81,12 +81,12 @@ def _get_http_direct(attrs):
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
log.warning('CERT Verification disabled')
f = urllib2.urlopen(req, timeout=30, context=context)
file_ = urllib2.urlopen(req, timeout=30, context=context)
else:
if os.name == 'nt':
f = urllib2.urlopen(req, cafile=certifi.where())
file_ = urllib2.urlopen(req, cafile=certifi.where())
else:
f = urllib2.urlopen(req)
file_ = urllib2.urlopen(req)
except Exception as ex:
log.debug('Error', exc_info=True)
pixbuf = None
......@@ -94,7 +94,7 @@ def _get_http_direct(attrs):
else:
while True:
try:
temp = f.read(100)
temp = file_.read(100)
except socket.timeout as ex:
log.debug('Timeout loading image %s', attrs['src'] + str(ex))
alt = attrs.get('alt', '')
......
......@@ -17,11 +17,11 @@ def resize_gif(mem, path, resize_to):
def analyse_image(mem):
"""
'''
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
"""
'''
image = Image.open(BytesIO(mem))
results = {
'size': image.size,
......
......@@ -20,11 +20,12 @@ import hashlib
import binascii
import logging
import math
import shutil
from functools import partial
from urllib.parse import urlparse
from urllib.parse import unquote
from io import BytesIO
import shutil
from functools import partial
from gi.repository import Gtk
from gi.repository import Gdk
......@@ -34,9 +35,10 @@ from gi.repository import GdkPixbuf
from gajim.common import app
from gajim.common import helpers
from gajim.common import configpaths
from gajim import dialogs
from gajim import gtkgui_helpers
from gajim.gtkgui_helpers import add_css_to_widget
from gajim.gtk.dialogs import ErrorDialog
from gajim.gtk.filechoosers import FileSaveDialog
from gajim.gtk.util import get_cursor
from gajim.plugins import GajimPlugin
from gajim.plugins.helpers import log_calls
......@@ -46,9 +48,6 @@ from url_image_preview.http_functions import get_http_head
from url_image_preview.http_functions import get_http_file
from url_image_preview.config_dialog import UrlImagePreviewConfigDialog
from gajim.gtk.filechoosers import FileSaveDialog
from gajim.gtk.util import get_cursor
log = logging.getLogger('gajim.p.preview')
......@@ -56,9 +55,9 @@ ERROR_MSG = None
try:
from PIL import Image
from url_image_preview.resize_gif import resize_gif
except:
except ImportError:
log.debug('Pillow not available')
ERROR_MSG = 'Please install python-pillow'
ERROR_MSG = _('Please install python-pillow')
try:
if os.name == 'nt':
......@@ -70,8 +69,8 @@ try:
from cryptography.hazmat.primitives.ciphers.modes import GCM
decryption_available = True
except Exception:
DEP_MSG = 'For preview of encrypted images, ' \
'please install python-cryptography!'
DEP_MSG = _('To enable previews for encrypted images, '
'please install python-cryptography!')
log.exception('Error')
log.info('Decryption/Encryption disabled due to errors')
decryption_available = False
......@@ -152,7 +151,7 @@ class UrlImagePreviewPlugin(GajimPlugin):
return
class Base(object):
class Base:
def __init__(self, plugin, textview):
self.plugin = plugin
self.textview = textview
......@@ -167,11 +166,11 @@ class Base(object):
self._create_path(self.directory)
self._create_path(self.thumbpath)
except Exception:
log.error("Error creating download and/or thumbnail folder!")
log.error('Error creating download and/or thumbnail folder!')
raise
def deinit_handlers(self):
# remove all register handlers on wigets, created by self.xml
# Remove all register handlers on wigets, created by self.xml
# to prevent circular references among objects
for i in list(self.handlers.keys()):
if self.handlers[i].handler_is_connected(i):
......@@ -182,7 +181,7 @@ class Base(object):
additional_data):
if len(real_text.split(' ')) > 1:
# urlparse dont recognises spaces as URL delimiter
# urlparse doesn't recognise spaces as URL delimiter
log.debug('Url with text will not be displayed: %s', real_text)
return
......@@ -200,8 +199,10 @@ class Base(object):
# Show URL, until image is loaded (if ever)
ttt = buffer_.get_tag_table()
repl_start = buffer_.create_mark(None, iter_, True)
buffer_.insert_with_tags(iter_, real_text,
*[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]])
buffer_.insert_with_tags(
iter_,
real_text,
*[(ttt.lookup(t) if isinstance(t, str) else t) for t in ['url']])
repl_end = buffer_.create_mark(None, iter_, True)
# Handle geo:-URIs
......@@ -221,11 +222,17 @@ class Base(object):
if lon == '':
return
filename = 'location_' + geo_provider + '_' \
+ location.replace(',', '_').replace('.', '-')
filename = 'location_%(provider)s_%(location)s' % {
'provider': geo_provider,
'location': location.replace(',', '_').replace('.', '-')
}
newfilename = filename + ext
thumbfilename = filename + '_thumb_' \
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
thumbfilename = '%(filename)s_thumb_%(size)s%(ext)s' % {
'filename': filename,
'size': str(self.plugin.config['PREVIEW_SIZE']),
'ext': ext
}
filepath = os.path.join(self.directory, newfilename)
thumbpath = os.path.join(self.thumbpath, thumbfilename)
filepaths = [filepath, thumbpath]
......@@ -264,9 +271,17 @@ class Base(object):
# so the filename should not exceed 90
name = name[:90]
namehash = hashlib.sha1(real_text.encode('utf-8')).hexdigest()
newfilename = name + '_' + namehash + ext
thumbfilename = name + '_' + namehash + '_thumb_' \
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
newfilename = '%(name)s_%(namehash)s%(ext)s' % {
'name': name,
'namehash': namehash,
'ext': ext
}
thumbfilename = '%(name)s_%(namehash)s_thumb_%(size)s%(ext)s' % {
'name': name,
'namehash': namehash,
'size': str(self.plugin.config['PREVIEW_SIZE']),
'ext': ext
}
filepath = os.path.join(self.directory, newfilename)
thumbpath = os.path.join(self.thumbpath, thumbfilename)
......@@ -287,19 +302,19 @@ class Base(object):
if len(key) == 32 and len(iv) == 12:
encrypted = True
# file exists but thumbnail got deleted
# File exists but thumbnail got deleted
if os.path.exists(filepath) and not os.path.exists(thumbpath):
if urlparts.scheme == 'geo':
real_text = weburl
with open(filepath, 'rb') as f:
mem = f.read()
real_text = weburl
with open(filepath, 'rb') as file_to_preview:
mem = file_to_preview.read()
app.thread_interface(
self._save_thumbnail, [thumbpath, mem],
self._update_img, [real_text, repl_start,
repl_end, filepath, encrypted])
# display thumbnail if already downloadeded
# (but only if file also exists)
# Display thumbnail if already downloaded
# (but only if file exists)
elif os.path.exists(filepath) and os.path.exists(thumbpath):
if urlparts.scheme == 'geo':
real_text = weburl
......@@ -308,7 +323,7 @@ class Base(object):
self._update_img, [real_text, repl_start,
repl_end, filepath, encrypted])
# or download file, calculate thumbnail and finally display it
# Or download file, calculate thumbnail, and finally display it
else:
if encrypted and not decryption_available:
log.debug('Please install Crytography to decrypt pictures')
......@@ -327,7 +342,7 @@ class Base(object):
def _accept_uri(self, urlparts, real_text, additional_data):
try:
oob_url = additional_data["gajim"]["oob_url"]
oob_url = additional_data['gajim']['oob_url']
except (KeyError, AttributeError):
oob_url = None
......@@ -336,7 +351,7 @@ class Base(object):
return False
# geo
if urlparts.scheme == "geo":
if urlparts.scheme == 'geo':
if self.plugin.config['GEO_PREVIEW_PROVIDER'] == 'no_preview':
log.info('geo: link preview is disabled')
return False
......@@ -353,7 +368,7 @@ class Base(object):
log.info('Incorrect oob data found')
return False
log.info('Not supported URI scheme found: %s', real_text)
log.info('Unsupported URI scheme found: %s', real_text)
return False
def _save_thumbnail(self, thumbpath, mem):
......@@ -372,7 +387,7 @@ class Base(object):
log.debug(error)
# Try Pillow
image = Image.open(BytesIO(mem)).convert("RGBA")
image = Image.open(BytesIO(mem)).convert('RGBA')
array = GLib.Bytes.new(image.tobytes())
width, height = image.size
pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(
......@@ -430,30 +445,20 @@ class Base(object):
@staticmethod
def _write_file(path, data):
log.info("Writing '%s' of size %d...", path, len(data))
log.info('Writing \'%s\' of size %d...', path, len(data))
try:
with open(path, "wb") as output_file:
with open(path, 'wb') as output_file:
output_file.write(data)
output_file.closed
except Exception as e:
log.error("Failed to write file '%s'!", path)
log.error('Failed to write file \'%s\'!', path)
raise
def _get_at_end(self):
try:
# Gajim 1.0.0
return self.textview.at_the_end()
except AttributeError:
# Gajim 1.0.1
return self.textview.autoscroll
return self.textview.autoscroll
def _scroll_to_end(self):
try:
# Gajim 1.0.0
self.textview.scroll_to_end_iter()
except AttributeError:
# Gajim 1.0.1
self.textview.scroll_to_end()
self.textview.scroll_to_end()
def _update_img(self, pixbuf, url, repl_start, repl_end,
filepath, encrypted):
......@@ -473,7 +478,7 @@ class Base(object):
buffer_ = repl_start.get_buffer()
iter_ = buffer_.get_iter_at_mark(repl_start)
buffer_.insert(iter_, "\n")
buffer_.insert(iter_, '\n')
anchor = buffer_.create_child_anchor(iter_)
anchor.plaintext = url
......@@ -491,9 +496,9 @@ class Base(object):
if at_end:
self._scroll_to_end()
except Exception as ex:
log.exception("Exception while loading %s: %s", url, ex)
log.exception('Exception while loading %s: %s', url, ex)
return False
# add to mainloop --> make call threadsafe
# Add to mainloop --> make call threadsafe
GLib.idle_add(add_to_textview)
def _create_clickable_image(self, pixbuf, url):
......@@ -505,7 +510,7 @@ class Base(object):
css = '''#Preview {
box-shadow: 0px 0px 3px 0px alpha(@theme_text_color, 0.2);
margin: 5px 10px 5px 10px; }'''
gtkgui_helpers.add_css_to_widget(image, css)
add_css_to_widget(image, css)
image.set_name('Preview')
event_box = Gtk.EventBox()
......@@ -520,19 +525,19 @@ class Base(object):
file_mime, file_size = tuple_arg
# Check if mime type is acceptable
if not file_mime or not file_size:
log.info("Failed to load HEAD Request for URL: '%s' "
"mime: %s, size: %s", url, file_mime, file_size)
log.info('Failed to load HEAD Request for URL: \'%s\' '
'mime: %s, size: %s', url, file_mime, file_size)
# URL is already displayed
return
if file_mime.lower() not in ACCEPTED_MIME_TYPES:
log.info("Not accepted mime type '%s' for URL: '%s'",
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
max_size = int(self.plugin.config['MAX_FILE_SIZE'])
if file_size > max_size or file_size == 0:
log.info("File size (%s) too big or unknown (zero) for URL: '%s'",
log.info('File size (%s) too big or unknown (zero) for URL: \'%s\'',
file_size, url)
# URL is already displayed
return
......@@ -572,17 +577,17 @@ class Base(object):
' (see error log for more information)'))
log.error(str(e))
# Create thumbnail, write it to harddisk and return it
# Create thumbnail, write to disk and return it
return self._save_thumbnail(thumbpath, mem)
def _create_path(self, folder):
if os.path.exists(folder):
return
log.debug("creating folder '%s'" % folder)
log.debug('Creating folder \'%s\'' % folder)
os.mkdir(folder, 0o700)
def _aes_decrypt_fast(self, key, iv, payload):
# Use AES128 GCM with the given key and iv to decrypt the payload.
# Use AES128 GCM with the given key and iv to decrypt the payload
if os.name == 'nt':
be = backend
else:
......@@ -612,7 +617,7 @@ class Base(object):
'open_file_in_browser_menuitem')
extras_separator = xml.get_object('extras_separator')
if data["encrypted"]:
if data['encrypted']:
open_link_in_browser_menuitem.hide()
if app.config.get('autodetect_browser_mailer') \
or app.config.get('custombrowser') == '':
......@@ -641,25 +646,26 @@ class Base(object):
return menu
def _on_open_menuitem_activate(self, menu, data):
filepath = data["filepath"]
original_filename = data["original_filename"]
url = data["url"]
filepath = data['filepath']
original_filename = data['original_filename']
url = data['url']
if original_filename.startswith('location_'):
helpers.open_uri(url)
return
helpers.launch_file_manager(filepath)
def _on_save_as_menuitem_activate(self, menu, data):
filepath = data["filepath"]
original_filename = data["original_filename"]
filepath = data['filepath']
original_filename = data['original_filename']
def on_ok(target_path):
dirname = os.path.dirname(target_path)
if not os.access(dirname, os.W_OK):
dialogs.ErrorDialog(
_('Directory "%s" is not writable') % dirname,
_('You do not have permission to '
'create files in this directory.'))
ErrorDialog(
_('Directory \'%s\' is not writable') % dirname,
_('You do not have the proper permissions to '
'create files in this directory.'),
transient_for=app.app.get_active_window())
return
shutil.copy(filepath, target_path)
......@@ -672,29 +678,29 @@ class Base(object):
helpers.launch_file_manager(self.directory)
def _on_copy_link_location_menuitem_activate(self, menu, data):
url = data["url"]
url = data['url']
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
clipboard.set_text(url, -1)
clipboard.store()
def _on_open_link_in_browser_menuitem_activate(self, menu, data):
url = data["url"]
if data["encrypted"]:
url = data['url']
if data['encrypted']:
self._on_open_menuitem_activate(self, data)
else:
helpers.open_uri(url)
def _on_open_file_in_browser_menuitem_activate(self, menu, data):
if os.name == "nt":
filepath = "file://" + os.path.abspath(data["filepath"])
if os.name == 'nt':
filepath = 'file://' + os.path.abspath(data['filepath'])
else:
filepath = "file://" + data["filepath"]
filepath = 'file://' + data['filepath']
if app.config.get('autodetect_browser_mailer') \
or app.config.get('custombrowser') == '':
dialogs.ErrorDialog(
ErrorDialog(