Skip to content

Instantly share code, notes, and snippets.

@Chocimier
Last active August 29, 2015 14:22
Show Gist options
  • Save Chocimier/633ff525eb87e7d4a3f5 to your computer and use it in GitHub Desktop.
Save Chocimier/633ff525eb87e7d4a3f5 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import os
import re
import sys
from curses.ascii import isblank
class DesktopEntry:
name = ''
icon = ''
executable = ''
identifier = ''
path = ''
types = []
def __init__(self, baseDirectory, relative):
try:
lines = open(baseDirectory + '/' + relative).readlines()
except (FileNotFoundError, UnicodeDecodeError):
return
self.path = baseDirectory + '/' + relative
self.identifier = relative.replace('/', '-')
while self.identifier.startswith('-'):
self.identifier = self.identifier[1:]
group = ''
for line in lines:
if line == '' or line[0] == '#' or isblank(line[0]):
continue
line = line.strip()
if line.startswith('['):
group = line
if group != '[Desktop Entry]':
continue
if line.startswith('Name='):
self.name = line.split('=', maxsplit=1)[1]
elif line.startswith('Icon='):
self.icon = line.split('=', maxsplit=1)[1]
elif line.startswith('Exec='):
self.executable = line.split('=', maxsplit=1)[1]
elif line.startswith('MimeType='):
self.types = line.split('=', maxsplit=1)[1].split(';')
self.types = list(filter(lambda x: x, self.types))
def __repr__(self):
return "DE({} <{}> <{}>)".format(self.name, self.identifier, self.path)
class MimeAppsSpec:
directoryPatterns = [
'$XDG_DATA_DIRS/applications/',
'$XDG_DATA_HOME/applications/',
'$XDG_CONFIG_DIRS/',
'$XDG_CONFIG_HOME/',
]
defaultVariableValues = {
'XDG_DATA_HOME': '$HOME/.local/share',
'XDG_CONFIG_HOME': '$HOME/.config',
'XDG_DATA_DIRS': '/usr/local/share/:/usr/share/',
'XDG_CONFIG_DIRS': '/etc/xdg'
}
applicationsCache = {}
knownApplications = {}
def __init__(self):
self.findDirectories()
self.createBase()
@staticmethod
def resolveVariable(path):
try:
var = re.match('.*?\\$([A-Z_]+)', path).group(1)
except AttributeError:
return [path]
if var in os.environ and len(os.environ[var]):
value = os.environ[var]
elif var in MimeAppsSpec.defaultVariableValues:
value = MimeAppsSpec.defaultVariableValues[var]
else:
return []
directories = list(filter(lambda x: len(x), value.split(':')))
return [path.replace('$'+var, i) for i in directories]
def findDirectories(self):
self.directories = self.directoryPatterns
while list(filter(lambda x: re.match('.*?\\$([A-Z_]+)', x), self.directories)):
directories_ = []
for i in map(self.resolveVariable, self.directories):
for j in i:
directories_.append(j)
self.directories = directories_
def removeFromType(self, type, appId):
if type in self.applicationsCache:
def f(x):
return x.identifier != appId
self.applicationsCache[type] = list(filter(f, self.applicationsCache[type]))
def addToType(self, type, entry):
if type not in self.applicationsCache:
self.applicationsCache[type] = []
else:
self.removeFromType(type, entry.identifier)
self.applicationsCache[type] = [entry] + self.applicationsCache[type]
def addApplication(self, entry):
for type in self.applicationsCache:
self.removeFromType(type, entry.identifier)
self.knownApplications[entry.identifier] = entry
for type in entry.types:
self.addToType(type, entry)
def processDesktopFile(self, baseDirectory, relative):
entry = DesktopEntry(baseDirectory, relative)
self.addApplication(entry)
def processDesktopInDirectory(self, baseDirectory, relative):
try:
filenames = os.listdir(baseDirectory + '/' + relative)
except FileNotFoundError:
return
for filename in filenames:
if filename.endswith('.desktop'):
self.processDesktopFile(baseDirectory, relative + '/' + filename)
def processMimeapps(self, path):
try:
lines = open(path).readlines()
except FileNotFoundError:
return
added = False
removed = False
for line in lines:
if line == '' or line[0] == '#' or isblank(line[0]):
continue
line = line.strip()
if line == '[Added Associations]':
added = True
removed = False
elif line == '[Removed Associations]':
added = False
removed = True
elif line.startswith('['):
added = False
removed = False
elif (line.count('=') > 0):
type, appIds = line.split('=', maxsplit=1)
appIds = appIds.split(';')
appIds = list(filter(lambda x: x, appIds))
appIds.reverse()
if added:
for appId in appIds:
if appId in self.knownApplications:
self.addToType(type, self.knownApplications[appId])
elif removed:
for appId in appIds:
self.removeFromType(type, appId)
def processDirectory(self, baseDirectory, relative):
directory = baseDirectory + '/' + relative
try:
subdirectories = os.listdir(directory)
except NotADirectoryError:
return
except FileNotFoundError:
return
for subdirectory in subdirectories:
self.processDirectory(baseDirectory, relative + '/' + subdirectory)
if directory[-1] != '/':
directory += '/'
self.processDesktopInDirectory(baseDirectory, relative)
self.processMimeapps(directory + 'mimeapps.list')
def createBase(self):
for directory in self.directories:
self.processDirectory(directory, '')
def appsForMime(self, type):
return self.applicationsCache[type]
if __name__ == '__main__':
base = MimeAppsSpec()
for i in base.appsForMime('application/pdf'):
print(i)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment