Nils
2 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