| ... | ... |
@@ -2,11 +2,51 @@ |
| 2 | 2 |
|
| 3 | 3 |
An [Ansible][] [role][] for installing [Firefox][] [extension][]s. |
| 4 | 4 |
|
| 5 |
+Takes a list of extension [slug][]s (the part after |
|
| 6 |
+`https://addons.mozilla.org/en-US/firefox/addon/`) and downloads and places the |
|
| 7 |
+extensions in the `extensions` directory in the default profile (a subdirectory |
|
| 8 |
+of `$HOME/.mozilla/firefox/`). |
|
| 9 |
+ |
|
| 10 |
+Note that, unless `extensions.autoDisableScopes` is set to an appropriate value |
|
| 11 |
+in `user.js`, extensions have to be enabled manually (e.g. from "Extensions" in |
|
| 12 |
+`about:addons`). |
|
| 13 |
+ |
|
| 5 | 14 |
[`ansible-role-firefox-extensions`]: https://git.rcrnstn.net/rcrnstn/ansible-role-firefox-extensions |
| 6 | 15 |
[Ansible]: https://docs.ansible.com/ansible |
| 7 | 16 |
[role]: https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html |
| 8 | 17 |
[Firefox]: https://en.wikipedia.org/wiki/Firefox |
| 9 | 18 |
[extension]: https://en.wikipedia.org/wiki/Firefox#Browser_extensions |
| 19 |
+[slug]: https://en.wikipedia.org/wiki/Clean_URL#Slug |
|
| 20 |
+ |
|
| 21 |
+## Usage |
|
| 22 |
+ |
|
| 23 |
+Example [`requirements.yml`][]: |
|
| 24 |
+ |
|
| 25 |
+```yaml |
|
| 26 |
+--- |
|
| 27 |
+ |
|
| 28 |
+roles: |
|
| 29 |
+ - name: 'firefox-extensions' |
|
| 30 |
+ src: 'https://git.rcrnstn.net/rcrnstn/ansible-firefox-extensions' |
|
| 31 |
+ scm: 'git' |
|
| 32 |
+``` |
|
| 33 |
+ |
|
| 34 |
+Example [playbook][]: |
|
| 35 |
+ |
|
| 36 |
+```yaml |
|
| 37 |
+--- |
|
| 38 |
+ |
|
| 39 |
+- hosts: 'all' |
|
| 40 |
+ roles: |
|
| 41 |
+ - role: 'firefox-extensions' |
|
| 42 |
+ firefox_extensions: |
|
| 43 |
+ - 'ublock-origin' |
|
| 44 |
+ - 'old-reddit-redirect' |
|
| 45 |
+ - 'tridactyl-vim' |
|
| 46 |
+``` |
|
| 47 |
+ |
|
| 48 |
+[`requirements.yml`]: https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-multiple-roles-from-a-file |
|
| 49 |
+[playbook]: https://docs.ansible.com/ansible/latest/user_guide/playbooks.html |
|
| 10 | 50 |
|
| 11 | 51 |
## License |
| 12 | 52 |
|
| 13 | 53 |
new file mode 100755 |
| ... | ... |
@@ -0,0 +1,39 @@ |
| 1 |
+#!/usr/bin/env python3 |
|
| 2 |
+ |
|
| 3 |
+ |
|
| 4 |
+import os |
|
| 5 |
+import sys |
|
| 6 |
+import configparser |
|
| 7 |
+import urllib.request |
|
| 8 |
+import json |
|
| 9 |
+ |
|
| 10 |
+ |
|
| 11 |
+FIREFOX_PATH = os.path.expanduser('~/.mozilla/firefox')
|
|
| 12 |
+PROFILES_PATH = os.path.join(FIREFOX_PATH, 'profiles.ini') |
|
| 13 |
+API_BASE_URL = 'https://services.addons.mozilla.org/api/v4/addons/addon' |
|
| 14 |
+ |
|
| 15 |
+ |
|
| 16 |
+extension = sys.argv[1] |
|
| 17 |
+ |
|
| 18 |
+ |
|
| 19 |
+profiles = configparser.ConfigParser() |
|
| 20 |
+profiles.optionxform = str |
|
| 21 |
+profiles.read(PROFILES_PATH) |
|
| 22 |
+for section in profiles.sections(): |
|
| 23 |
+ if section.startswith('Profile'):
|
|
| 24 |
+ profile = dict(profiles.items(section)) |
|
| 25 |
+ if int(profile['Default']): |
|
| 26 |
+ profile_path = profile['Path'] |
|
| 27 |
+ if int(profile.get('IsRelative', '0')):
|
|
| 28 |
+ profile_path = os.path.join(FIREFOX_PATH, profile_path) |
|
| 29 |
+ |
|
| 30 |
+ |
|
| 31 |
+with urllib.request.urlopen(f'{API_BASE_URL}/{extension}') as response:
|
|
| 32 |
+ info = json.loads(response.read()) |
|
| 33 |
+guid = info['guid'] |
|
| 34 |
+url = info['current_version']['files'][0]['url'] |
|
| 35 |
+path = os.path.join(profile_path, 'extensions', f'{guid}.xpi')
|
|
| 36 |
+os.makedirs(os.path.dirname(path), exist_ok=True) |
|
| 37 |
+if not os.path.exists(path): |
|
| 38 |
+ urllib.request.urlretrieve(url, path) |
|
| 39 |
+ print(extension) |