From 1654ceecf301a88cea79a7d54b7fa958fed2cda4 Mon Sep 17 00:00:00 2001 From: Danielle McLean Date: Fri, 20 Apr 2018 12:35:51 +1000 Subject: [PATCH] Switch from django-favicon-plus to django-super-favicon, it performs better and doesn't require a DB table --- Pipfile | 2 +- Pipfile.lock | 22 ++++------ lemoncurry/settings/base.py | 3 ++ lemoncurry/templates/lemoncurry/layout.html | 4 +- wellknowns/favicons.py | 45 +++++++++++++++++++++ wellknowns/views/manifest.py | 26 +++++++----- 6 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 wellknowns/favicons.py diff --git a/Pipfile b/Pipfile index 424e59e..6de67e4 100644 --- a/Pipfile +++ b/Pipfile @@ -13,7 +13,6 @@ gunicorn = "*" "psycopg2" = "*" pillow = "*" python-memcached = "*" -django-favicon-plus = "*" django-meta = "*" django-redis-cache = "*" django-activeurl = "*" @@ -44,5 +43,6 @@ pytest-django = "*" python-baseconv = "*" django-computed-property = "*" docutils = "*" +django-super-favicon = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 6cd8fa6..ae8c207 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "4df43e91dcd5baca07940a89c9f23c321de025dd3454739f4266fcbe4490da2d" + "sha256": "ff6bfe755c0aaf4328e61d282a464f6bc86731fdd077f04aad1f0ebabacee6d6" }, "pipfile-spec": 6, "requires": { @@ -188,12 +188,6 @@ ], "version": "==0.8.0" }, - "django-compat": { - "hashes": [ - "sha256:3ac9a3bedc56b9365d9eb241bc5157d0c193769bf995f9a78dc1bc24e7c2331b" - ], - "version": "==1.0.15" - }, "django-compressor": { "hashes": [ "sha256:7732676cfb9d58498dfb522b036f75f3f253f72ea1345ac036434fdc418c2e57", @@ -225,13 +219,6 @@ "index": "pypi", "version": "==1.9.1" }, - "django-favicon-plus": { - "hashes": [ - "sha256:3394a951d8dc611eb1ea027ad1181d7f650ca234506585b27e93d7ed06b981bf" - ], - "index": "pypi", - "version": "==0.0.8" - }, "django-meta": { "hashes": [ "sha256:21fc5d0d5fcacda5d038af0babd08afaa4d5bed1b746edb6522c4d3435da8db6", @@ -287,6 +274,13 @@ "index": "pypi", "version": "==1.1.0" }, + "django-super-favicon": { + "hashes": [ + "sha256:56cb5268ea73ef3cbde5cb01fef02fea2ec00739cdae0566d3102009f052f683" + ], + "index": "pypi", + "version": "==0.6.1" + }, "docutils": { "hashes": [ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", diff --git a/lemoncurry/settings/base.py b/lemoncurry/settings/base.py index c5001fa..e68d1b2 100644 --- a/lemoncurry/settings/base.py +++ b/lemoncurry/settings/base.py @@ -263,3 +263,6 @@ PUSH_HUB = 'https://00dani.superfeedr.com/' # django-rq # https://github.com/ui/django-rq RQ_QUEUES = {'default': {'USE_REDIS_CACHE': 'default'}} + +# django-super-favicon +FAVICON_STORAGE = 'django.core.files.storage.DefaultStorage' diff --git a/lemoncurry/templates/lemoncurry/layout.html b/lemoncurry/templates/lemoncurry/layout.html index 658428b..e9ed97b 100644 --- a/lemoncurry/templates/lemoncurry/layout.html +++ b/lemoncurry/templates/lemoncurry/layout.html @@ -1,4 +1,4 @@ -{% load analytical compress favtags lemoncurry_tags meta static theme_colour %} +{% load analytical compress favicon lemoncurry_tags meta static theme_colour %} {% site_name as site_name %}{% request_uri request as uri %}{% request_origin request as origin %} @@ -28,7 +28,7 @@ {% include 'meta/meta.html' %} - {% placeFavicon %} + {% get_favicons 'favicon/' %} diff --git a/wellknowns/favicons.py b/wellknowns/favicons.py new file mode 100644 index 0000000..27f7a5f --- /dev/null +++ b/wellknowns/favicons.py @@ -0,0 +1,45 @@ +from itertools import chain +from django.core.files.storage import default_storage + + +class Favicon: + def __init__(self, size, rel='icon', mime='image/png'): + self.rel = rel + self.mime = mime + if not isinstance(size, tuple): + size = (size, size) + self.size = size + + @property + def url(self): + return default_storage.url('favicon/' + self.filename) + + @property + def filename(self): + return 'favicon-{0}.png'.format(*self.size) + + @property + def sizes(self): + return 'x'.join(str(s) for s in self.size) + + +tile_sizes = {'small': 128, 'medium': 270, 'wide': (558, 270), 'large': 558} + + +class Tile(Favicon): + def __init__(self, size_name): + super().__init__(tile_sizes[size_name]) + self.size_name = size_name + + @property + def filename(self): + return '{0}tile.png'.format(self.size_name) + + +sizes = (32, 57, 76, 96, 120, 128, 144, 180, 195, 228) +icons = tuple(chain( + (Favicon(s) for s in sizes), + (Tile(s) for s in tile_sizes.keys()), + (Favicon(152, rel='apple-touch-icon-precomposed'), + Favicon(196, rel='shortcut icon')) +)) diff --git a/wellknowns/views/manifest.py b/wellknowns/views/manifest.py index 11e4d1e..d50cf16 100644 --- a/wellknowns/views/manifest.py +++ b/wellknowns/views/manifest.py @@ -1,12 +1,16 @@ from django.http import JsonResponse from django.urls import reverse -from favicon.models import FaviconImg +from ..favicons import icons from lemoncurry import utils from lemoncurry.theme import color from urllib.parse import urljoin from textwrap import shorten +def manifest_icons(base): + return [{'src': i.url, 'type': i.mime, 'sizes': i.sizes} for i in sorted(icons, key=lambda i: i.size)] + + def manifest(request): base = utils.origin(request) start_url = reverse('home:index') + '?utm_source=homescreen' @@ -14,6 +18,7 @@ def manifest(request): app = { 'name': request.site.name, 'short_name': shorten(request.site.name, width=20, placeholder=''), + 'icons': manifest_icons(base), 'display': 'browser', 'start_url': urljoin(base, start_url), @@ -22,15 +27,14 @@ def manifest(request): 'theme_color': color(2), } - rels = ('shortcut icon', 'apple-touch-icon') - icons = FaviconImg.objects.filter( - faviconFK__isFavicon=True, - rel__in=rels, - ).order_by('size') - app['icons'] = [{ - 'type': 'image/png', - 'sizes': '{0}x{0}'.format(icon.size), - 'src': urljoin(base, icon.faviconImage.url), - } for icon in icons] + # icons = FaviconImg.objects.filter( + # faviconFK__isFavicon=True, + # rel__in=rels, + # ).order_by('size') + # app['icons'] = [{ + # 'type': 'image/png', + # 'sizes': '{0}x{0}'.format(icon.size), + # 'src': urljoin(base, icon.faviconImage.url), + # } for icon in icons] return JsonResponse(app, content_type='application/manifest+json')