07 Sep 2022
Creating a list of all apps installed on my 2 Macs
Fetching all apps on my systems with Python, and listing them in Grist Grist | The Evolution of Spreadsheets
Plus copy each app's icon in its original format.
####################
# Import Apps to Grist
import grist_PE
from slugify import slugify
import glob
import os
import shutil
list_locations = [
'/Applications/*.app', # fetches all apps in my Applications folder
'/Applications/Setapp/*.app', # fetches all apps in my Setapp subscription
'/Applications/Adobe Acrobat DC/*.app', # fetching Adobe apps within their folder
'/Applications/Adobe Illustrator 2022/*.app', # fetching Adobe apps within their folder
'/Applications/Adobe Photoshop 2022/*.app', # fetching Adobe apps within their folder
'/Volumes/Macintosh HD-1/Applications/*.app', # fetching all apps from the Applications folder on my 2nd Mac on network
]
list_errors = []
count_file = 0
for location in list_locations:
parts = location.split('*')
prefix = len(parts[0])
list_of_files = glob.glob(location)
print()
for file in list_of_files:
count += 1
app = file[prefix:-4]
print(app)
slug = slugify(app)
for root, dirs, files in os.walk(file):
for name in files:
# copying app's logos to a central folder
if name.endswith((".icns")):
count_file += 1
print(f"{root}/{name}")
try:
shutil.copy2(f'{root}/{name}', f"/path/to/folder/{slug}_{name}.icns")
except:
list_errors.append(name)
continue
print()
# adding to Grist
grist_PE.Apps.add_records('Master', [
{
'name': app,
'type': ['L', 'macOS'],
'status': ['L', 'using'],
'slug': slug,
}
])
for error in list_errors:
print(error)
print(f"\nTotal of {len(list_errors)} errors")
Convert apps' logos to usable format
####################
# Convert .icns files to .png
count_deleted = 0
import icnsutil
for root, dirs, files in os.walk("/path/to/folder/with/icns"): # path to folder with .icns files
for name in files:
if name.endswith((".icns")):
count += 1
file_path = f"{root}/{name}"
print(file_path)
slug = name[:-5]
print(slug)
img = icnsutil.IcnsFile(file_path)
output_path = f"/path/to/output/folder/{slug}"
os.makedirs(output_path)
img.export(output_path, allowed_ext='png', convert_png=True)
## Cleaning
### move to apps folder
import shutil
path = "/path/to/folder/png/"
for root, dirs, files in os.walk(path):
prefix = len(path)
for name in files:
if name.endswith((".png")):
count += 1
file_path = f"{root}/{name}"
print(file_path)
file_name = name
print(file_name)
slug = root[prefix:]
print(slug)
shutil.copy2(f'{root}/{name}', f'/path/to/folder/content/images/apps/{slug}_{file_name}')
### remove undesirables
blacklist = [
'@2x',
'_16x',
'_32x',
]
path = "/path/to/folder/content/images/apps/"
for black in blacklist:
for root, dirs, files in os.walk(path):
prefix = len(path)
for name in files:
if name.endswith((".png")):
count += 1
file_path = f"{root}/{name}"
if black in name:
os.remove(file_path)
count_deleted += 1
Import Apps list from Grist to Pelican Markdown files (notes)
22 Sep 2022
####################
# Import Apps list from Grist to Pelican markdown files
from datetime import date
from datetime import timedelta
from operator import attrgetter
from slugify import slugify
## Define Published Date as yesterday so library updates do not show up as Featured article
today = date.today()
yesterday = today - timedelta(days = 1)
publish_date = f"{yesterday.strftime('%Y-%m-%d')}"
# Identify if cover image is available
list_existing_images = []
for root, dirs, files in os.walk("/path/to/folder/content/images/apps"):
for name in files:
list_existing_images.append(name)
### books/library
apps_data = grist_PE.Apps.fetch_table('Master') # list of namedtuples
total = len(apps_data)
print(f"{total} Apps in Grist\n")
today = datetime.now()
date_today = today.strftime('%Y-%m-%d')
apps_sorted_by_title = sorted(apps_data, key=attrgetter('slug'))
# APPS NOTES
import glob
notes_path = '/path/to/folder/content/articles/apps/*.md'
list_of_apps_notes = [x[len(notes_path)-4:-3] for x in glob.glob(notes_path)]
# USING
count_using = 0
output_using = ''
for b in apps_sorted_by_title:
count_row += 1
if b.status != None:
if 'using' in b.status:
count_using += 1
title = b.name
slug = b.slug
summary = b.summary
if b.rating != None:
rating = "⭐️" * b.rating
else:
rating = ''
link = b.link
types = b.type
type = ''
if types != None:
for typ in types:
if typ != 'L':
if type != '':
type = f"{type} <span class=\"tag\">{typ}</span>"
else:
type = f"<span class=\"tag\">{typ}</span>"
else:
type = ''
categories = b.category
category = ''
if categories != None:
for cat in categories:
if cat != 'L':
if category != '':
category = f"{category} <span class=\"tag\">{cat}</span>"
else:
category = f"<span class=\"tag\">{cat}</span>"
tags_raw = b.tags
tags = ''
if tags_raw != None:
for tag in tags_raw:
if tag != 'L':
if tags != '':
tags = f"{tags} <span class=\"tag\">{tag}</span>"
else:
tags = f"<span class=\"tag\">{tag}</span>"
if slug in list_of_apps_notes:
note = f'[[note](../../apps/{slug}/index.html)]'
else:
note = ''
icon = f"<img class=\"app_icon\" src=\"https://ik.imagekit.io/vhucnsp9j1u/images/apps/{slug}_128x128.png\" alt=\"{slug}\"/>"
if link != '':
output_using = f"{output_using}\n {icon} | <a href=\"{link}\" target=\"_blank\">{title}</a> | {note} | {type} | {category} | {tags} | {summary} | {rating} | "
else:
output_using = f"{output_using}\n {icon} | {title} | {note} | {type} | {category} | {tags} | {summary} | {rating} | "
# Adding the header at the end to ensure proper books count
header = f"Title: My Apps Library\nDate: {publish_date}\nTags: apps\nSummary: keeping track of apps I currently use, have used and on my radar\n\n{total} apps total"
header_using = f"\n\n# Using: {count_using} apps \n\napp | name/website | note | type | category | tags | summary | rating |\n---|---|---|---|---|---|---|---|"
# ## USED
count_used = 0
output_used = ''
for b in apps_sorted_by_title:
if b.status != None:
if 'used' in b.status:
count_used += 1
title = b.name
slug = b.slug
summary = b.summary
if b.rating != None:
rating = "⭐️" * b.rating
else:
rating = ''
link = b.link
types = b.type
type = ''
if types != None:
for typ in types:
if typ != 'L':
if type != '':
type = f"{type} <span class=\"tag\">{typ}</span>"
else:
type = f"<span class=\"tag\">{typ}</span>"
else:
type = ''
categories = b.category
category = ''
if categories != None:
for cat in categories:
if cat != 'L':
if category != '':
category = f"{category} <span class=\"tag\">{cat}</span>"
else:
category = f"<span class=\"tag\">{cat}</span>"
tags_raw = b.tags
tags = ''
if tags_raw != None:
for tag in tags_raw:
if tag != 'L':
if tags != '':
tags = f"{tags} <span class=\"tag\">{tag}</span>"
else:
tags = f"<span class=\"tag\">{tag}</span>"
if slug in list_of_apps_notes:
note = f'[[note](../../apps/{slug}/index.html)]'
else:
note = ''
icon = f"<img class=\"app_icon\" src=\"https://ik.imagekit.io/vhucnsp9j1u/images/apps/{slug}_128x128.png\" alt=\"{slug}\"/>"
if link != '':
output_used = f"{output_used}\n {icon} | <a href=\"{link}\" target=\"_blank\">{title}</a> | {note} | {type} | {category} | {tags} | {summary} | {rating} | "
else:
output_used = f"{output_used}\n {icon} | {title} | {note} | {type} | {category} | {tags} | {summary} | {rating} | "
header_used = f"\n\n# Used: {count_used} apps \n\napp | name/website | note | type | category | tags | summary | rating |\n---|---|---|---|---|---|---|---|"
# ## RADAR
count_radar = 0
output_radar = ''
for b in apps_sorted_by_title:
if b.status != None:
if 'radar' in b.status:
count_radar += 1
title = b.name
slug = b.slug
summary = b.summary
link = b.link
types = b.type
type = ''
if types != None:
for typ in types:
if typ != 'L':
if type != '':
type = f"{type} <span class=\"tag\">{typ}</span>"
else:
type = f"<span class=\"tag\">{typ}</span>"
else:
type = ''
categories = b.category
category = ''
if categories != None:
for cat in categories:
if cat != 'L':
if category != '':
category = f"{category} <span class=\"tag\">{cat}</span>"
else:
category = f"<span class=\"tag\">{cat}</span>"
tags_raw = b.tags
tags = ''
if tags_raw != None:
for tag in tags_raw:
if tag != 'L':
if tags != '':
tags = f"{tags} <span class=\"tag\">{tag}</span>"
else:
tags = f"<span class=\"tag\">{tag}</span>"
if slug in list_of_apps_notes:
note = f'[[note](../../apps/{slug}/index.html)]'
else:
note = ''
icon = f"<img class=\"app_icon\" src=\"https://ik.imagekit.io/vhucnsp9j1u/images/apps/{slug}_128x128.png\" alt=\"{slug}\"/>"
if link != '':
output_radar = f"{output_radar}\n <a href=\"{link}\" target=\"_blank\">{title}</a> | {note} | {type} | {category} | {tags} | {summary} | "
else:
output_radar = f"{output_radar}\n {title} | {note} | {type} | {category} | {tags} | {summary} | "
header_radar_table = f"\n\n# Radar: {count_radar} apps \n\nname/website | note | type | category | tags | summary | \n---|---|---|---|---|---|"
output = f"{header}{header_using}{output_using}{header_used}{output_used}{header_radar_table}{output_radar}\n\n"
with open(f"notes/content/articles/apps/library.md", 'w') as file:
file.write(output)
### apps/radar
# Adding the header at the end to ensure proper books count
header_radar = f"Title: Apps on my radar\nDate: {publish_date}\nTags: apps\nSummary: keeping track of apps I might want to look into...\n\n{count_radar} apps on radar"
output_radar = f"{header_radar}{header_radar_table}{output_radar}\n\n"
with open(f"notes/content/articles/apps/radar.md", 'w') as file:
file.write(output_radar)
########################################################################################################
Next
generate note for B2B Sales apps only
as b2b-sales/apps
.