Add the option to search a better icon on the html page
parent
33ebb4bdd4
commit
4c9b7da927
|
@ -1,2 +1,17 @@
|
||||||
*Mon Apr 27 2015 Tobi Sim 0.0.1-1
|
*Mon Feb 13 2023 kirbylife <hola@kirbylife.dev> 0.5.0-7
|
||||||
-initial commit
|
- Add SVG support
|
||||||
|
- Improve performance
|
||||||
|
- Add resize slider
|
||||||
|
- Fix irregluar size of icons on the main grid
|
||||||
|
- Add the option to search a better icon directly on the html page
|
||||||
|
- Improve a bit the logging
|
||||||
|
|
||||||
|
*Mon Feb 13 2023 kirbylife <hola@kirbylife.dev> 0.4.5-5
|
||||||
|
- Add aarch64 support
|
||||||
|
- Add logging file
|
||||||
|
- Skip the sailjail permissions
|
||||||
|
- Remove all the third-repo dependencies
|
||||||
|
- Now, when you re-edit an icon, the original icon is used instead of the edited one
|
||||||
|
|
||||||
|
*Mon May 17 2021 kirbylife <hola@kirbylife.dev> 0.4.0-1
|
||||||
|
- First published version
|
||||||
|
|
38
qml/Icon.qml
38
qml/Icon.qml
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick 2.0
|
import QtQuick 2.0
|
||||||
import Sailfish.Silica 1.0
|
import Sailfish.Silica 1.0
|
||||||
import io.thp.pyotherside 1.3
|
import io.thp.pyotherside 1.3
|
||||||
|
import Nemo.Notifications 1.0
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: iconEditor
|
id: iconEditor
|
||||||
|
@ -8,6 +9,40 @@ Page {
|
||||||
property var attrs
|
property var attrs
|
||||||
property var corners: [true, true, true, true]
|
property var corners: [true, true, true, true]
|
||||||
|
|
||||||
|
Notification {
|
||||||
|
id: notification
|
||||||
|
appIcon: "/usr/share/icons/hicolor/86x86/apps/harbour-muchkin"
|
||||||
|
expireTimeout: 5000
|
||||||
|
|
||||||
|
function sendMessage(msg) {
|
||||||
|
notification.previewBody = msg
|
||||||
|
notification.publish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SilicaFlickable {
|
||||||
|
id: mainList
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
PullDownMenu {
|
||||||
|
MenuItem {
|
||||||
|
text: "Search a better icon"
|
||||||
|
onClicked: {
|
||||||
|
py.importModule("main", function(){
|
||||||
|
py.call("main.scrape_icon", [iconEditor.attrs.URL], function(result){
|
||||||
|
if(result) {
|
||||||
|
icon.source = result;
|
||||||
|
iconEditor.attrs.Icon = result;
|
||||||
|
notification.sendMessage("A better icon found");
|
||||||
|
} else {
|
||||||
|
notification.sendMessage("Not better icon found");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PageHeader {
|
PageHeader {
|
||||||
id: header
|
id: header
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
@ -115,4 +150,7 @@ Page {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def log_error(f):
|
||||||
|
def wrap(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error on: {f.__name__}")
|
||||||
|
logging.error(f"args: {args}")
|
||||||
|
logging.error(f"kwargs: {kwargs}")
|
||||||
|
logging.error(f"Exception: {e}")
|
||||||
|
raise e
|
||||||
|
return wrap
|
42
src/main.py
42
src/main.py
|
@ -1,4 +1,5 @@
|
||||||
import pyotherside # pyright: ignore reportMissingImports
|
import pyotherside # pyright: ignore reportMissingImports
|
||||||
|
from decorators import log_error
|
||||||
from PIL import Image, ImageDraw, ImageChops
|
from PIL import Image, ImageDraw, ImageChops
|
||||||
from PIL.Image import Image as ImageType
|
from PIL.Image import Image as ImageType
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
@ -6,7 +7,9 @@ from glob import glob
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from subprocess import getstatusoutput
|
from subprocess import getstatusoutput
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
from urllib.parse import urljoin
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from lxml import etree
|
||||||
import requests
|
import requests
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
|
@ -16,6 +19,10 @@ import tempfile
|
||||||
|
|
||||||
ICON_SIZE = (256, 256)
|
ICON_SIZE = (256, 256)
|
||||||
|
|
||||||
|
HEADERS = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0"
|
||||||
|
}
|
||||||
|
|
||||||
logging_filename = os.path.join(os.path.expanduser("~"),
|
logging_filename = os.path.join(os.path.expanduser("~"),
|
||||||
".local",
|
".local",
|
||||||
"share",
|
"share",
|
||||||
|
@ -69,7 +76,7 @@ def avg_colors(img):
|
||||||
|
|
||||||
def add_background(img: ImageType, bg_tuple: tuple, size: float) -> ImageType:
|
def add_background(img: ImageType, bg_tuple: tuple, size: float) -> ImageType:
|
||||||
img = img.copy()
|
img = img.copy()
|
||||||
size = size / 100
|
size = max(size, 1) / 100
|
||||||
bg = Image.new("RGBA", img.size, bg_tuple)
|
bg = Image.new("RGBA", img.size, bg_tuple)
|
||||||
img.thumbnail((value * size for value in img.size))
|
img.thumbnail((value * size for value in img.size))
|
||||||
bg.paste(img, ((bg.size[0] - img.size[0]) // 2, (bg.size[1] - img.size[1]) // 2), img)
|
bg.paste(img, ((bg.size[0] - img.size[0]) // 2, (bg.size[1] - img.size[1]) // 2), img)
|
||||||
|
@ -123,6 +130,39 @@ def get_web_icons():
|
||||||
|
|
||||||
return list(map(parse_file, apps))
|
return list(map(parse_file, apps))
|
||||||
|
|
||||||
|
@log_error
|
||||||
|
def scrape_icon(url: str) -> str:
|
||||||
|
url_parsed = urlparse(url)
|
||||||
|
origin = f"{url_parsed.scheme}://{url_parsed.netloc}"
|
||||||
|
html = etree.HTML(requests.get(origin, headers=HEADERS).text)
|
||||||
|
|
||||||
|
possible_svg = None
|
||||||
|
possible_icon = None
|
||||||
|
max_size = 0
|
||||||
|
|
||||||
|
for icon in html.xpath("//link[contains(@rel, 'icon')]"):
|
||||||
|
if "SVG" in next(iter(icon.xpath("@type")), "").upper():
|
||||||
|
possible_svg = icon.xpath("@href")[0]
|
||||||
|
break
|
||||||
|
possible_href = next(iter(icon.xpath("@href")), None)
|
||||||
|
possible_size = next(iter(icon.xpath("@sizes")), None)
|
||||||
|
possible_rel = next(iter(icon.xpath("@rel")), "")
|
||||||
|
if possible_size and possible_href and possible_size != "any":
|
||||||
|
size = int(possible_size.split("x")[0])
|
||||||
|
if size > max_size:
|
||||||
|
max_size = size
|
||||||
|
possible_icon = possible_href
|
||||||
|
if possible_href and not possible_size and possible_rel.upper() == "apple-touch-icon".upper():
|
||||||
|
possible_icon = possible_href
|
||||||
|
|
||||||
|
new_icon = possible_svg or possible_icon
|
||||||
|
if new_icon:
|
||||||
|
parsed_new_icon = urlparse(new_icon)
|
||||||
|
if not parsed_new_icon.scheme or not parsed_new_icon.netloc:
|
||||||
|
new_icon = urljoin(origin, new_icon)
|
||||||
|
return sailify(new_icon, [True] * 4, 100)
|
||||||
|
|
||||||
|
@log_error
|
||||||
def sailify(raw_str, pattern, size) -> str:
|
def sailify(raw_str, pattern, size) -> str:
|
||||||
url_parsed = urlparse(raw_str)
|
url_parsed = urlparse(raw_str)
|
||||||
if url_parsed.scheme == "data":
|
if url_parsed.scheme == "data":
|
||||||
|
|
Loading…
Reference in New Issue