Skip to content

Instantly share code, notes, and snippets.

@davidfraser
Created August 16, 2024 13:36
Show Gist options
  • Save davidfraser/161a8366cde68d8713109215427e8661 to your computer and use it in GitHub Desktop.
Save davidfraser/161a8366cde68d8713109215427e8661 to your computer and use it in GitHub Desktop.
Patch ActivityWatch Web Watcher extensions to include profile names in the bucket they submit events to
#!/usr/bin/env python
"""Searches all Chrome profiles for a Windows user for the ActivityWatch Web Watcher extension
and then patches them to include their profile name in the bucket they submit events to
See https://github.com/ActivityWatch/aw-watcher-web/issues/82
"""
import os
from os.path import abspath, exists, expanduser, isdir, join
import json
import logging
def get_chrome_data_dir():
windows_chrome_data_dir = expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data")
if not exists(windows_chrome_data_dir):
raise ValueError("Could not find Chrome user data directory")
return windows_chrome_data_dir
def find_profiles():
chrome_data_dir = get_chrome_data_dir()
with open(join(chrome_data_dir, 'Local State')) as f:
local_state = json.load(f)
profiles_info = local_state.get('profile', {})
profile_keys = profiles_info.get('profiles_order', [])
for profile_key in profile_keys:
profile_info = profiles_info.get('info_cache', {}).get(profile_key, {})
profile_name = profile_info.get('name')
profile_user_name = profile_info.get('user_name')
yield {'dir': join(chrome_data_dir, profile_key), 'name': profile_name, 'user_name': profile_user_name}
if not profile_keys:
for filename in os.listdir(chrome_data_dir):
if filename == "Default" or filename.startswith("Profile "):
yield {'dir': join(chrome_data_dir, filename), 'name': filename, 'user_name': None}
def patch_profile_aw_web_watcher(profile_info):
extensions_dir = join(profile_info['dir'], 'Extensions')
profile_name = profile_info.get('name')
watcher_suffix = profile_info.get('name').replace(' ', '-').lower()
search_js = '"aw-watcher-web-" + browserName.toLowerCase()'
logging.info(f"Searching for ActivityWatch Web Watcher extensions under Chrome profile {profile_name}...")
for extension_key in os.listdir(extensions_dir):
extension_dir = join(extensions_dir, extension_key)
if not isdir(extension_dir):
continue
for version in os.listdir(extension_dir):
manifest_file = join(extension_dir, version, 'manifest.json')
if not exists(manifest_file):
continue
manifest = json.load(open(manifest_file))
extension_name = manifest.get('name')
if extension_name == 'ActivityWatch Web Watcher':
app_js_file = join(extension_dir, version, 'out', 'app.js')
if exists(app_js_file):
add_js = f' + "{watcher_suffix}"'
app_js_src = open(app_js_file).read()
if add_js in app_js_src:
logging.info(f"Found {extension_name} for {profile_name}; already patched, so leaving")
elif (search_js + ';') in app_js_src:
logging.info(f"Found {extension_name} for {profile_name}; patching")
app_js_src = app_js_src.replace(search_js, search_js + add_js)
with open(app_js_file, 'w') as f:
f.write(app_js_src)
return
if __name__ == '__main__':
logging.getLogger().setLevel(logging.INFO)
for profile_info in find_profiles():
patch_profile_aw_web_watcher(profile_info)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment