Nils
3 years ago
7 changed files with 134 additions and 18086 deletions
@ -1,187 +0,0 @@ |
|||
#! /usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
""" |
|||
Copyright 2022, Nils Hilbricht, Germany ( https://www.hilbricht.net ) |
|||
|
|||
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ), |
|||
|
|||
This is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
""" |
|||
|
|||
import logging; logger = logging.getLogger(__name__); logger.info("import") |
|||
|
|||
from os import getenv |
|||
import os |
|||
import pathlib |
|||
import re |
|||
|
|||
""" |
|||
https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html |
|||
https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#icon_lookup |
|||
|
|||
$HOME/.icons (for backwards compatibility) |
|||
$XDG_DATA_DIRS/icons |
|||
/usr/share/pixmaps |
|||
""" |
|||
|
|||
EXTENSIONS = [".png", ".xpm", ".svg"] |
|||
|
|||
SEARCH_DIRECTORIES = [pathlib.Path(pathlib.Path.home(), ".icons")] |
|||
|
|||
XDG_DATA_DIRS = getenv("XDG_DATA_DIRS") #colon : separated, most likely empty |
|||
if XDG_DATA_DIRS: |
|||
SEARCH_DIRECTORIES += [pathlib.Path(p, "icons/hicolor") for p in XDG_DATA_DIRS.split(":")] |
|||
SEARCH_DIRECTORIES += [pathlib.Path(p, "icons/scalable") for p in XDG_DATA_DIRS.split(":")] |
|||
else: |
|||
#If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. |
|||
SEARCH_DIRECTORIES += [pathlib.Path(p, "icons/hicolor") for p in "/usr/local/share/:/usr/share/".split(":")] |
|||
SEARCH_DIRECTORIES += [pathlib.Path(p, "icons/scalable") for p in "/usr/local/share/:/usr/share/".split(":")] |
|||
|
|||
SEARCH_DIRECTORIES.append(pathlib.Path("/usr/share/pixmaps")) |
|||
SEARCH_DIRECTORIES.append(pathlib.Path("/usr/share/icons")) #for icons wrongly put directly there. But many do. |
|||
SEARCH_DIRECTORIES.append(pathlib.Path("/usr/local/share/icons")) #for icons wrongly put directly there. |
|||
#TODO: this may become a problem in the future. If a user has *MANY* icon themes installed this might take too long. And all because we wanted the Shuriken icon in Archlinux... |
|||
|
|||
SEARCH_DIRECTORIES = set(p.resolve() for p in SEARCH_DIRECTORIES) #resolve follows symlinks, set() makes it unique |
|||
|
|||
|
|||
def run_fast_scandir(dir, ext): |
|||
""" |
|||
https://stackoverflow.com/questions/18394147/recursive-sub-folder-search-and-return-files-in-a-list-python |
|||
""" |
|||
subfolders, files = [], [] |
|||
|
|||
try: |
|||
for f in os.scandir(dir): |
|||
if f.is_dir(): |
|||
subfolders.append(f.path) |
|||
if f.is_file(): |
|||
if os.path.splitext(f.name)[1].lower() in ext: |
|||
files.append(f.path) |
|||
|
|||
for dir in list(subfolders): |
|||
sf, f = run_fast_scandir(dir, ext) |
|||
subfolders.extend(sf) |
|||
files.extend(f) |
|||
|
|||
except PermissionError: |
|||
pass |
|||
|
|||
except FileNotFoundError: |
|||
pass |
|||
|
|||
return subfolders, files |
|||
|
|||
|
|||
def _buildCache()->set: |
|||
result = [] |
|||
for basePath in SEARCH_DIRECTORIES: |
|||
forget, files = run_fast_scandir(basePath, EXTENSIONS) |
|||
result += files |
|||
|
|||
#Convert str to real paths |
|||
result = [pathlib.Path(r) for r in result if pathlib.Path(r).is_file()] |
|||
|
|||
return set(result) |
|||
|
|||
global _cache |
|||
_cache = None |
|||
def updateCache(serializedCache:list=None): |
|||
global _cache |
|||
|
|||
if serializedCache: |
|||
#Convert str to real paths |
|||
logger.info("Filling icon cache with previously serialized data") |
|||
_cache = set([pathlib.Path(r) for r in serializedCache if pathlib.Path(r).is_file()]) |
|||
else: |
|||
#Already real paths as a set |
|||
logger.info("Building icon cache from scratch") |
|||
_cache = _buildCache() |
|||
logger.info("Icon cache complete") |
|||
|
|||
def getSerializedCache()->list: #list of strings, not paths. This is for saving in global system config for faster startup |
|||
global _cache |
|||
return [str(p) for p in _cache] |
|||
|
|||
rePattern = re.compile("\d+x\d+") #we don't put .* around this because we are searching for the subpattern |
|||
|
|||
def findIconPath(executableName:str)->list: |
|||
""" |
|||
Parameter executableName can be a direct icon name as well, from the .desktop icon path. |
|||
|
|||
Return order is: svg first, then highest resolution first, then the rest unordered. |
|||
so you can use result[0] for the best variant. |
|||
It is not guaranteed that [1], or even [0] exists. |
|||
This is not a sorted list, these extra variants are just added to the front of the list again""" |
|||
global _cache |
|||
if not _cache: |
|||
raise ValueError("You need to call updateCache() first") |
|||
|
|||
svg = None |
|||
bestr = 0 #resolution |
|||
best = None |
|||
|
|||
#Did we get an icon name directly? Remove the extension |
|||
#For example "ams_32.xpm" becomes "ams_32" |
|||
exeAsPath = pathlib.Path(executableName) |
|||
if exeAsPath.suffix in EXTENSIONS: |
|||
executableName = exeAsPath.stem |
|||
|
|||
#for ext in EXTENSIONS: #all extensions |
|||
# if executableName.endswith(ext): |
|||
# executableName = executableName[:-4] |
|||
|
|||
result = [] |
|||
for f in _cache: |
|||
if f.stem == executableName: |
|||
if f.suffix == ".svg": |
|||
svg = f |
|||
else: |
|||
match = re.search(rePattern, str(f)) #find resolution dir like /48x48/ |
|||
if match: |
|||
resolutionAsNumber = int(match.group().split("x")[0]) |
|||
if resolutionAsNumber > bestr: #new best one |
|||
bestr = resolutionAsNumber |
|||
best = f |
|||
result.append(f) |
|||
|
|||
|
|||
if best: |
|||
result.insert(0, best) |
|||
if svg: |
|||
result.insert(0, svg) |
|||
|
|||
if not result: |
|||
logger.warning(f"Did not find an icon for {executableName}") |
|||
|
|||
return result |
|||
|
|||
if __name__ == "__main__": |
|||
"""Example that tries to find a few icons""" |
|||
|
|||
updateCache() |
|||
|
|||
print("Search paths:") |
|||
print(SEARCH_DIRECTORIES) |
|||
print() |
|||
|
|||
for exe in ("zynaddsubfx", "patroneo", "jack_mixer", "carla", "ardour6", "synthv1", "ams_32.xpm", "shuriken.png"): |
|||
r = findIconPath(exe) |
|||
if r: |
|||
print (f"{exe} Best resolution: {r[0]}") |
|||
else: |
|||
print (f"{exe}: No icon found ") |
|||
|
|||
|
|||
|
@ -1,17 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
sudo pacman -Fy |
|||
pacman -Fx "/usr/bin/([A-Z])" | cut -d " " -f1 | uniq | sort > allexe.txt |
|||
pacman -Fl $(pacman -Sg pro-audio |cut -d " " -f2) | cut -d " " -f2 | grep "usr/bin" | uniq | sort > audioexe.txt |
|||
sed -i -e 's/usr\/bin\///g' audioexe.txt #strip usr/bin yes, the initial / from usr is missing |
|||
sed '/^[[:space:]]*$/d' -i audioexe.txt #remove empty lines |
|||
|
|||
grep -vFf audioexe.txt allexe.txt > grepexcluded2.txt |
|||
grep '^usr\/bin\/' grepexcluded2.txt > grepexcluded.txt #only keep lines that start with usr/bin. There are some false positives in there |
|||
|
|||
sed -i -e 's/usr\/bin\///g' grepexcluded.txt #strip usr/bin yes, the initial / from usr is missing |
|||
sed '/^[[:space:]]*$/d' -i grepexcluded.txt #remove empty lines |
|||
|
|||
rm grepexcluded2.txt |
|||
rm allexe.txt |
|||
rm audioexe.txt |
File diff suppressed because it is too large
Loading…
Reference in new issue