Compare commits

...

6 Commits

9 changed files with 109 additions and 112 deletions

View File

@ -1,14 +1,16 @@
Appname:=$(shell cat appname.txt) Appname:=$(shell cat appname.txt)
prefix:=/usr
temp:=/tmp/fpm-jolla temp:=/tmp/fpm-jolla
sourcePath:=$(shell pwd) sourcePath:=$(shell pwd)
output:=$(sourcePath)/output
dependencies=$(shell for file in `cat dependencies.txt`;do echo "-d "$${file};done;) dependencies=$(shell for file in `cat dependencies.txt`;do echo "-d "$${file};done;)
version:=0.4.5 version:=0.5.0
iteration:=5 iteration:=0
fpmExec:=$(shell echo "$${FPM_BIN:=fpm}")
all: clean build-tmp rpm-i686 rpm-jolla rpm-aarch64 all: clean build-tmp rpm-i686 rpm-jolla rpm-aarch64
build-tmp: build-tmp:
mkdir -p $(output)
mkdir -p $(temp)/usr/share/applications mkdir -p $(temp)/usr/share/applications
mkdir -p $(temp)/usr/share/icons/hicolor/86x86/apps mkdir -p $(temp)/usr/share/icons/hicolor/86x86/apps
mkdir -p $(temp)/usr/share/$(Appname)/src mkdir -p $(temp)/usr/share/$(Appname)/src
@ -19,10 +21,10 @@ build-tmp:
cp -ar ./dat/appicon.png $(temp)/usr/share/icons/hicolor/86x86/apps/$(Appname).png cp -ar ./dat/appicon.png $(temp)/usr/share/icons/hicolor/86x86/apps/$(Appname).png
install -m 755 ./dat/$(Appname).sh $(temp)/usr/bin/$(Appname) install -m 755 ./dat/$(Appname).sh $(temp)/usr/bin/$(Appname)
rpm-i686: arch:=i686 build: rpmname=$(Appname)-$(version)-$(iteration).$(arch).rpm
rpm-i686: rpmname:=$(Appname)-$(version)-$(iteration).$(arch).rpm build: build-tmp
rpm-i686: build-tmp cd $(temp); \
cd $(temp);fpm -f -s dir -t rpm \ $(fpmExec) -f -s dir -t rpm \
--after-install $(sourcePath)/dat/upgradeScript.sh \ --after-install $(sourcePath)/dat/upgradeScript.sh \
--after-remove $(sourcePath)/dat/removeScript.sh \ --after-remove $(sourcePath)/dat/removeScript.sh \
--rpm-changelog $(sourcePath)/changelog.txt \ --rpm-changelog $(sourcePath)/changelog.txt \
@ -33,39 +35,17 @@ rpm-i686: build-tmp
-p $(temp)/$(rpmname) \ -p $(temp)/$(rpmname) \
-n $(Appname) \ -n $(Appname) \
-a $(arch) \ -a $(arch) \
--prefix / * --prefix / *; \
mv $(temp)/*.rpm $(output)
rpm-jolla: arch:=armv7hl rpm-i686: arch=i686
rpm-jolla: rpmname:=$(Appname)-$(version)-$(iteration).$(arch).rpm rpm-i686: build
rpm-jolla: build-tmp
cd $(temp);fpm -f -s dir -t rpm \
--after-install $(sourcePath)/dat/upgradeScript.sh \
--after-remove $(sourcePath)/dat/removeScript.sh \
--rpm-changelog $(sourcePath)/changelog.txt \
--directories "/usr/share/$(Appname)" \
-v $(version) \
--iteration $(iteration) \
$(dependencies) \
-p $(temp)/$(rpmname) \
-n $(Appname) \
-a $(arch) \
--prefix / *
rpm-aarch64: arch:=aarch64 rpm-jolla: arch=armv7hl
rpm-aarch64: rpmname:=$(Appname)-$(version)-$(iteration).$(arch).rpm rpm-jolla: build
rpm-aarch64: build-tmp
cd $(temp);fpm -f -s dir -t rpm \ rpm-aarch64: arch=aarch64
--after-install $(sourcePath)/dat/upgradeScript.sh \ rpm-aarch64: build
--after-remove $(sourcePath)/dat/removeScript.sh \
--rpm-changelog $(sourcePath)/changelog.txt \
--directories "/usr/share/$(Appname)" \
-v $(version) \
--iteration $(iteration) \
$(dependencies) \
-p $(temp)/$(rpmname) \
-n $(Appname) \
-a $(arch) \
--prefix / *
clean: clean:
rm -rf $(temp) rm -rf $(temp)

View File

@ -1,5 +1,7 @@
# Muchkin icons # Muchkin icons
============== ==============
Make your webapps icons in the app box look better with the rest of your native apps by choosing whether the corners are rounded or pointed Make your webapps icons in the app box look better with the rest of your native apps by choosing whether the corners are rounded or pointed
## Dependencies ## Dependencies
@ -12,19 +14,21 @@ Make your webapps icons in the app box look better with the rest of your native
- [rpm-tools](http://rpm.org/) - [rpm-tools](http://rpm.org/)
## Build your own RPM package ## Build your own RPM package
1. Clone the repository: `git clone https://gitlab.com/kirbylife/harbour-muchkin` 1. Clone the repository: `git clone https://git.kirbylife.dev/kirbylife/harbour-muchkin`
1. Go to the directory: `cd harbour-muchkin` 1. Go to the directory: `cd harbour-muchkin`
1. Build the package. 1. Build the package:
1. armv7hl: `make rpm-jolla` 1. armv7hl: `make rpm-jolla`
1. i686: `make rpm-virt` 1. i686: `make rpm-i686`
1. aarch64: `make rpm-aarch64` 1. aarch64: `make rpm-aarch64`
1. the .rpm file will be on `/tmp/fpm-jolla/` 1. (if fpm is not in `PATH` or has a different name you can set the env var "FPM_BIN" with the path to the binary).
1. the .rpm file will be on `output/`.
## TO-DO ## TO-DO
- [x] Support to aarch64 arquitecture - [x] Support to aarch64 arquitecture
- [x] Choice non-transparent color to fill the empty spaces - [x] Choice non-transparent color to fill the empty spaces
- [x] Fix the issue with sailjail - [x] Fix the issue with sailjail
- [ ] Make betters Make commands - [x] Make betters Make commands
- [ ] Add SVG support
- [ ] Add option to request favicon - [ ] Add option to request favicon
- [ ] Add option to restore the original icon - [ ] Add option to restore the original icon
- [ ] Make all icons in the main grid the same size - [ ] Make all icons in the main grid the same size

View File

@ -4,7 +4,8 @@ X-Nemo-Application-Type=silica-qt5
Name=Muchkin Name=Muchkin
Icon=harbour-muchkin Icon=harbour-muchkin
Exec=sailfish-qml harbour-muchkin Exec=sailfish-qml harbour-muchkin
[X-Sailjail] [X-Sailjail]
Sandboxing=Disabled Sandboxing=Disabled
OrganizationName=org.kirbylife OrganizationName=dev.kirbylife
ApplicationName=harbour-muchkin ApplicationName=harbour-muchkin

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
echo "removing /usr/share/harbour-muchkin" # echo "removing /usr/share/harbour-muchkin"
rm -rf /usr/share/harbour-muchkin # rm -rf /usr/share/harbour-muchkin

View File

@ -1,5 +1,7 @@
libsailfishapp-launcher libsailfishapp-launcher
sailfish-svg2png
pyotherside-qml-plugin-python3-qt5 pyotherside-qml-plugin-python3-qt5
python3-base python3-base
python3-imaging python3-imaging
python3-requests python3-requests
python3-lxml

View File

@ -11,28 +11,28 @@ Page {
anchors.top: header.bottom anchors.top: header.bottom
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
width: parent.width width: parent.width
text: "this application was created by\nkirbylife\nunder the GPL V2.0 license,\nanyone is free to view\nthe code and modify it." text: "this application was created by\nkirbylife\nunder the GPL V3 license,\nanyone is free to view\nthe code and modify it."
truncationMode: TruncationMode.Elide truncationMode: TruncationMode.Elide
} }
Button { Button {
id: btnCode id: btnCode
anchors.bottom: btnTwitter.top anchors.bottom: btnMastodon.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: 50 anchors.bottomMargin: 50
text: "Code" text: "Code"
onClicked: { onClicked: {
Qt.openUrlExternally("https://gitlab.com/kirbylife/harbour-muchkin") Qt.openUrlExternally("https://git.kirbylife.dev/kirbylife/harbour-muchkin")
} }
} }
Button { Button {
id: btnTwitter id: btnMastodon
anchors.bottom: btnDonate.top anchors.bottom: btnDonate.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: 50 anchors.bottomMargin: 50
text: "Twitter" text: "Mastodon"
onClicked: { onClicked: {
Qt.openUrlExternally("https://twitter.com/kirbylife") Qt.openUrlExternally("https://mstdn.mx/@kirbylife")
} }
} }
Button { Button {

View File

@ -47,7 +47,7 @@ Page {
activated = !activated activated = !activated
iconEditor.corners[idCell] = activated iconEditor.corners[idCell] = activated
py.importModule("main", function(){ py.importModule("main", function(){
py.call("main.sailify", [(iconEditor.attrs.old_icon || iconEditor.attrs.Icon).toString(), iconEditor.corners], function(result){ py.call("main.sailify", [(iconEditor.attrs.old_icon || iconEditor.attrs.Icon).toString(), iconEditor.corners, size.value], function(result){
icon.source = result icon.source = result
}) })
}) })
@ -62,10 +62,30 @@ Page {
height: width height: width
} }
Button { Slider {
id: size
anchors.top: icon.bottom anchors.top: icon.bottom
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10 anchors.topMargin: 10
label: "Size:"
width: parent.width
minimumValue: 0
maximumValue: 100
stepSize: 10
value: 100
onReleased: {
py.importModule("main", function(){
py.call("main.sailify", [(iconEditor.attrs.old_icon || iconEditor.attrs.Icon).toString(), iconEditor.corners, size.value], function(result){
icon.source = result
})
})
}
}
Button {
anchors.top: size.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
text: "Save" text: "Save"
onClicked: { onClicked: {
if(iconEditor.attrs.old_icon === undefined) { if(iconEditor.attrs.old_icon === undefined) {
@ -89,7 +109,7 @@ Page {
Component.onCompleted: { Component.onCompleted: {
py.addImportPath(Qt.resolvedUrl("../src")); py.addImportPath(Qt.resolvedUrl("../src"));
py.importModule("main", function(){ py.importModule("main", function(){
py.call("main.sailify", [(iconEditor.attrs.old_icon || iconEditor.attrs.Icon).toString(), [1, 1, 1, 1]], function(result){ py.call("main.sailify", [(iconEditor.attrs.old_icon || iconEditor.attrs.Icon).toString(), [1, 1, 1, 1], size.value], function(result){
icon.source = result icon.source = result
}) })
}) })

View File

@ -49,6 +49,8 @@ Page {
Image { Image {
anchors.centerIn: parent anchors.centerIn: parent
source: attrs.Icon source: attrs.Icon
width: parent.width
height: width
} }
onClicked: { onClicked: {

View File

@ -4,34 +4,59 @@ from PIL.Image import Image as ImageType
from io import BytesIO from io import BytesIO
from glob import glob from glob import glob
from collections import Counter from collections import Counter
from subprocess import getstatusoutput
from urllib.parse import urlparse
from functools import lru_cache
import requests import requests
import base64 import base64
import os import os
import shutil import shutil
import logging import logging
import tempfile
ICON_SIZE = (256, 256)
logging_filename = os.path.join(os.path.expanduser("~"), logging_filename = os.path.join(os.path.expanduser("~"),
".local", ".local",
"share", "share",
"org.kirbylife", "dev.kirbylife",
"harbour-muchkin", "harbour-muchkin",
"muchkin.log") "muchkin.log")
os.makedirs(os.path.dirname(logging_filename), exist_ok=True) os.makedirs(os.path.dirname(logging_filename), exist_ok=True)
logging.basicConfig(filename=logging_filename, filemode="w", level=logging.DEBUG) logging.basicConfig(filename=logging_filename, filemode="w", level=logging.DEBUG)
@lru_cache(maxsize=50)
def download_icon(url) -> ImageType: def download_icon(url) -> ImageType:
response = requests.get(url) response = requests.get(url)
img = Image.open(BytesIO(response.content)) img = Image.open(BytesIO(response.content))
img.thumbnail(ICON_SIZE)
img = img.convert("RGBA") img = img.convert("RGBA")
return img return img
@lru_cache(maxsize=50)
def base64_to_img(base64_bytes: bytes) -> ImageType: def base64_to_img(base64_bytes: bytes) -> ImageType:
img_bytes = base64.b64decode(base64_bytes) img_bytes = base64.b64decode(base64_bytes)
img_buffer = BytesIO(img_bytes) img_buffer = BytesIO(img_bytes)
img = Image.open(img_buffer) img = Image.open(img_buffer)
img.thumbnail(ICON_SIZE)
img = img.convert("RGBA") img = img.convert("RGBA")
return img return img
@lru_cache(maxsize=50)
def svg_to_img(svg_url: str) -> ImageType:
response = requests.get(svg_url)
with tempfile.TemporaryDirectory() as d:
with open(os.path.join(d, "icon.svg"), "w") as f:
f.write(response.text)
status, output = getstatusoutput(f"sailfish_svg2png -z 16 {d} {d}")
logging.info("Converted svg to png")
logging.info(f"sailfish_svg2png status {status}: {output}")
img = Image.open(os.path.join(d, "icon.png"))
img.thumbnail(ICON_SIZE)
img = img.convert("RGBA")
return img
def avg_colors(img): def avg_colors(img):
counter = Counter() counter = Counter()
width, height = img.size width, height = img.size
@ -42,9 +67,12 @@ def avg_colors(img):
counter[pixel] += 1 counter[pixel] += 1
return counter.most_common(1)[0][0] return counter.most_common(1)[0][0]
def add_background(img: ImageType, bg_tuple: tuple) -> ImageType: def add_background(img: ImageType, bg_tuple: tuple, size: float) -> ImageType:
img = img.copy()
size = size / 100
bg = Image.new("RGBA", img.size, bg_tuple) bg = Image.new("RGBA", img.size, bg_tuple)
bg.paste(img, (0, 0), img) 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)
return bg return bg
def crop_to_circle(im, template): def crop_to_circle(im, template):
@ -70,9 +98,7 @@ def parse_file(desktop_path):
output = {} output = {}
with open(desktop_path, "r") as f: with open(desktop_path, "r") as f:
for line in f: for line in f:
if not line: if not line or line.startswith("["):
continue
if line.startswith("["):
continue continue
key, value = line.split("=", 1) key, value = line.split("=", 1)
output[key] = value.strip() output[key] = value.strip()
@ -97,21 +123,23 @@ def get_web_icons():
return list(map(parse_file, apps)) return list(map(parse_file, apps))
def sailify(raw_str, pattern): def sailify(raw_str, pattern, size) -> str:
try: url_parsed = urlparse(raw_str)
# New versions of Sailfish has the url on the icons if url_parsed.scheme == "data":
img = download_icon(raw_str)
logging.info("Downloaded from url: " + raw_str)
except requests.exceptions.InvalidSchema:
# The old ones converted the icon to base64 # The old ones converted the icon to base64
base64_bytes = raw_str.replace("data:image/png;base64,", "", 1).encode() base64_bytes = raw_str.replace("data:image/png;base64,", "", 1).encode()
img = base64_to_img(base64_bytes) img = base64_to_img(base64_bytes)
logging.info("Converted from base64") logging.info("Converted from base64")
except Exception as e: # New versions of Sailfish has the url on the icons
logging.error(e) elif url_parsed.path.split("/")[-1].split(".")[-1].upper() == "SVG":
raise e img = svg_to_img(raw_str)
logging.info("Downloaded from url: " + raw_str)
else:
img = download_icon(raw_str)
logging.info("Downloaded from url: " + raw_str)
bg_tuple = avg_colors(img) bg_tuple = avg_colors(img)
img = add_background(img, bg_tuple) img = add_background(img, bg_tuple, size)
img = crop_to_circle(img, pattern) img = crop_to_circle(img, pattern)
output_buffer = BytesIO() output_buffer = BytesIO()
img.save(output_buffer, format="PNG") img.save(output_buffer, format="PNG")
@ -133,43 +161,3 @@ def save_icon(app):
f.write(new_content) f.write(new_content)
logging.info("Icon saved on: " + app["path"]) logging.info("Icon saved on: " + app["path"])
return True return True
def main():
import shutil
while True:
apps = get_web_icons()
while True:
for n, app in enumerate(apps):
print(f"{n}) {app['Name']}")
index = input("select an application (the index):\n>>> ")
index = int(index)
if index >= len(apps):
print("Select a valid index")
continue
break
app = apps[index]
if app["Icon"] == "icon-launcher-bookmark":
print("this webapp is using the generic icon of a bookmark and not a favicon so it is not possible to modify")
continue
while True:
pattern = input("Enter the pattern (0 = round, 1 = peak):\n>>> ")
if len(pattern) != 4:
print("it is necessary to enter 4 characters")
pattern = tuple(map(int, pattern))
new_icon = sailify(app.get("old_icon", app["Icon"]), pattern)
# Backup the original .desktop
shutil.copyfile(app["path"], app["path"] + "_backup")
app["old_icon"] = app.get("old_icon", app["Icon"])
app["Icon"] = new_icon
new_content = deparse_file(app)
with open(app["path"], "w") as f:
f.write(new_content)
print(f"{app['Name']} sailified correctly")
break
if __name__ == "__main__":
main()