Skip to content

Commit b0487fa

Browse files
thameem-abbasclaude
andcommitted
Add Linux support via OpenDeck
The Elgato Stream Deck app doesn't support Linux, but OpenDeck (an open-source alternative) does and is compatible with Elgato SDK plugins. This adds Linux as a build target and produces a separate Linux-inclusive .streamDeckPlugin package for OpenDeck users. Changes: - Add CodePathLin and Platform linux to plugin manifest (OpenDeck extensions) - Add Linux to CI build matrix (ubuntu-latest, PyInstaller) - Strip Linux-specific manifest entries before Elgato CLI validation, then restore and zip into a separate Linux-inclusive artifact - Make macholib/altgraph macOS-only via PEP 508 environment markers - Add Linux install, dev setup, and build instructions to README - Update release workflow to attach Linux-inclusive artifact Tested end-to-end on Fedora with OpenDeck: plugin registers, launches the binary, and communicates with the browser extension over WebSocket. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3dfec9c commit b0487fa

6 files changed

Lines changed: 120 additions & 23 deletions

File tree

.github/workflows/release.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ jobs:
8181
github-token: ${{ secrets.GITHUB_TOKEN }}
8282
path: ./artifacts
8383

84+
- name: Download Linux-inclusive Stream Deck Plugin
85+
uses: actions/download-artifact@v4
86+
with:
87+
name: com.chrisregado.googlemeet-linux.streamDeckPlugin
88+
run-id: ${{ steps.get-workflow-id.outputs.plugin_run_id }}
89+
github-token: ${{ secrets.GITHUB_TOKEN }}
90+
path: ./artifacts
91+
8492
- name: Attach artifacts to release
8593
uses: softprops/action-gh-release@v2
8694
with:
@@ -89,3 +97,4 @@ jobs:
8997
./artifacts/chrome-extension-${{ github.event.release.tag_name }}.zip
9098
./artifacts/firefox-extension-${{ github.event.release.tag_name }}.xpi
9199
./artifacts/com.chrisregado.googlemeet.streamDeckPlugin
100+
./artifacts/com.chrisregado.googlemeet-linux.streamDeckPlugin

.github/workflows/streamdeck-plugin-build.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727
runs_on: macos-latest
2828
- os: windows
2929
runs_on: windows-latest
30+
- os: linux
31+
runs_on: ubuntu-latest
3032
name: Build ${{ matrix.os }} Stream Deck Plugin
3133
# Since we run on both branch pushes and PRs, don't do a duplicated run if the PR is for a branch in the local repo:
3234
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
@@ -93,6 +95,20 @@ jobs:
9395
name: windows-plugin-intermediate-build
9496
path: com.chrisregado.googlemeet.sdPlugin/dist/windows
9597

98+
- name: Strip Linux-specific manifest entries for Elgato validation
99+
run: |
100+
cd com.chrisregado.googlemeet.sdPlugin
101+
cp manifest.json manifest-full.json
102+
python3 -c "
103+
import json
104+
with open('manifest.json', 'r') as f:
105+
m = json.load(f)
106+
m.pop('CodePathLin', None)
107+
m['OS'] = [o for o in m.get('OS', []) if o.get('Platform') != 'linux']
108+
with open('manifest.json', 'w') as f:
109+
json.dump(m, f, indent='\t')
110+
"
111+
96112
- name: Run Elgato linter
97113
run: streamdeck validate --no-update-check com.chrisregado.googlemeet.sdPlugin
98114

@@ -110,8 +126,42 @@ jobs:
110126
VERSION_NUMBER="${GIT_TAG#v}"
111127
streamdeck pack --output ./build/ --no-update-check --force --version "${VERSION_NUMBER}" com.chrisregado.googlemeet.sdPlugin
112128
129+
- name: Download Linux plugin artifact
130+
uses: actions/download-artifact@v4
131+
with:
132+
name: linux-plugin-intermediate-build
133+
path: com.chrisregado.googlemeet.sdPlugin/dist/linux
134+
135+
- name: Set executable permissions on Linux binary
136+
run: chmod +x com.chrisregado.googlemeet.sdPlugin/dist/linux/main/main
137+
138+
- name: Build Linux-inclusive package for OpenDeck
139+
run: |
140+
cd com.chrisregado.googlemeet.sdPlugin
141+
cp manifest-full.json manifest.json
142+
rm manifest-full.json
143+
if [[ "${{ github.ref_type }}" == "tag" ]]; then
144+
GIT_TAG="${{ github.ref_name }}"
145+
VERSION_NUMBER="${GIT_TAG#v}"
146+
python3 -c "
147+
import json
148+
with open('manifest.json', 'r') as f:
149+
m = json.load(f)
150+
m['Version'] = '${VERSION_NUMBER}'
151+
with open('manifest.json', 'w') as f:
152+
json.dump(m, f, indent='\t')
153+
"
154+
fi
155+
zip -r ../build/com.chrisregado.googlemeet-linux.streamDeckPlugin . -x ".*"
156+
113157
- name: Upload final plugin binary
114158
uses: actions/upload-artifact@v4
115159
with:
116160
name: com.chrisregado.googlemeet.streamDeckPlugin
117161
path: ./build/com.chrisregado.googlemeet.streamDeckPlugin
162+
163+
- name: Upload Linux-inclusive plugin package
164+
uses: actions/upload-artifact@v4
165+
with:
166+
name: com.chrisregado.googlemeet-linux.streamDeckPlugin
167+
path: ./build/com.chrisregado.googlemeet-linux.streamDeckPlugin

README.md

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,46 @@ This is a plugin that allows the [Elgato Stream Deck](https://www.elgato.com/en/
66

77
This plugin works in conjuction with our Google Chrome / Mozilla Firefox browser extension, which is required for this plugin to function.
88

9-
Developed and tested primarily on macOS 15.0, Python 3.13.0, Chrome 130, and Stream Deck app v6.6. It should work on Windows or in Firefox as well.
9+
Developed and tested primarily on macOS 15.0, Python 3.13.0, Chrome 130, and Stream Deck app v6.6. It should work on Windows or in Firefox as well. Linux is supported via [OpenDeck](https://github.com/nekename/OpenDeck).
1010

1111
## Installing
1212

13+
### macOS / Windows
14+
1315
1. If you're running on an Apple Silicon Mac (e.g. an M1 chip), you must have Apple's [Rosetta 2](https://support.apple.com/en-us/HT211861) installed. If you don't (or if you're not sure), open Terminal and run this command:
1416

1517
```
1618
softwareupdate --install-rosetta --agree-to-license
1719
```
1820

1921
2. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the `com.chrisregado.googlemeet.streamDeckPlugin` package and open it. The Stream Deck desktop software will prompt you to install the plugin.
20-
3. The browser extension is not in the web store, so we'll install it manually:
2122

22-
**For Google Chrome:**
23-
1. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the `chrome-extension` zip file and extract it somewhere you can keep it. (If you move the folder after installing, Chrome will uninstall the extension from your browser and you'll have to reinstall it.)
24-
2. From Chrome's extension settings page (`chrome://extensions/`), turn on "Developer mode" using the toggle at the top-right corner of the page.
25-
3. Click the "Load unpacked" button at the top-left corner, and select the folder you extracted the zip to earlier.
26-
4. You can turn Developer mode back off now if you want.
23+
### Linux (via OpenDeck)
24+
25+
1. Install [OpenDeck](https://github.com/nekename/OpenDeck), an open-source Stream Deck application that supports Elgato SDK plugins on Linux.
26+
2. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the `com.chrisregado.googlemeet-linux.streamDeckPlugin` package (the Linux-inclusive build) and install it through OpenDeck.
27+
28+
### Browser Extension
29+
30+
The browser extension is not in the web store, so we'll install it manually:
31+
32+
**For Google Chrome:**
33+
1. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the `chrome-extension` zip file and extract it somewhere you can keep it. (If you move the folder after installing, Chrome will uninstall the extension from your browser and you'll have to reinstall it.)
34+
2. From Chrome's extension settings page (`chrome://extensions/`), turn on "Developer mode" using the toggle at the top-right corner of the page.
35+
3. Click the "Load unpacked" button at the top-left corner, and select the folder you extracted the zip to earlier.
36+
4. You can turn Developer mode back off now if you want.
2737

28-
**For Mozilla Firefox:**
29-
1. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the Firefox extension `.xpi` file.
30-
2. From Firefox's extension settings page (`about:addons`), click the Settings cogwheel at the top-right of the page, click "Install Add-on From File...", and select the `.xpi` file that you just downloaded.
31-
3. Click "Add" on the Firefox popup to allow the extension to install.
38+
**For Mozilla Firefox:**
39+
1. From the [Releases page](https://github.com/ChrisRegado/streamdeck-googlemeet/releases), download the Firefox extension `.xpi` file.
40+
2. From Firefox's extension settings page (`about:addons`), click the Settings cogwheel at the top-right of the page, click "Install Add-on From File...", and select the `.xpi` file that you just downloaded.
41+
3. Click "Add" on the Firefox popup to allow the extension to install.
3242

33-
4. If you use an ad blocker (such as uBlock Origin with the EasyPrivacy filter list), you may have to add meet.google.com as a trusted site in your blocker's settings to allow the browser Extension to work. (Some filters block websockets to 127.0.0.1, which this extension needs to communicate with the Stream Deck.)
34-
5. Add some buttons to your Stream Deck, and start a Google Meet call to try them out!
43+
### Final Steps
3544

36-
It's safe to delete the `com.chrisregado.googlemeet.streamDeckPlugin` file once it's installed. However, on Windows, you may need to quit the Stream Deck desktop software (by right clicking its icon in the Windows task tray and clicking Quit) and re-launch it to avoid "action can't be completed because the file is open" errors.
45+
1. If you use an ad blocker (such as uBlock Origin with the EasyPrivacy filter list), you may have to add meet.google.com as a trusted site in your blocker's settings to allow the browser Extension to work. (Some filters block websockets to 127.0.0.1, which this extension needs to communicate with the Stream Deck.)
46+
2. Add some buttons to your Stream Deck, and start a Google Meet call to try them out!
47+
48+
It's safe to delete the `.streamDeckPlugin` file once it's installed. However, on Windows, you may need to quit the Stream Deck desktop software (by right clicking its icon in the Windows task tray and clicking Quit) and re-launch it to avoid "action can't be completed because the file is open" errors.
3749

3850
## Updating
3951

@@ -67,7 +79,7 @@ The Stream Deck plugin code is in the `streamdeck-plugin` directory. The browser
6779

6880
The plugin is written in Python. Create a venv to hold your package's dependencies, and install those dependencies:
6981

70-
**MacOS:**
82+
**macOS / Linux:**
7183

7284
```
7385
cd streamdeck-plugin
@@ -89,7 +101,7 @@ Remember that virtualenvs are not portable. If you move this folder at all, you'
89101

90102
### Running Unit Tests
91103

92-
**MacOS:**
104+
**macOS / Linux:**
93105

94106
```
95107
cd streamdeck-plugin
@@ -113,7 +125,7 @@ Our plugin code is written in Python, but the Elgato CLI tool is distributed as
113125

114126
To build the plugin:
115127

116-
**MacOS:**
128+
**macOS:**
117129

118130
```
119131
cd streamdeck-plugin
@@ -123,6 +135,16 @@ pyinstaller --clean --dist "../com.chrisregado.googlemeet.sdPlugin/dist/macos" s
123135
rm -rf build
124136
```
125137

138+
**Linux:**
139+
140+
```
141+
cd streamdeck-plugin
142+
source venv/bin/activate
143+
rm -rf ../com.chrisregado.googlemeet.sdPlugin/dist/linux
144+
pyinstaller --clean --dist "../com.chrisregado.googlemeet.sdPlugin/dist/linux" src/main.py
145+
rm -rf build
146+
```
147+
126148
**Windows:**
127149

128150
```
@@ -133,22 +155,34 @@ pyinstaller --clean --dist "..\com.chrisregado.googlemeet.sdPlugin\dist\windows"
133155
rmdir /q /s build
134156
```
135157

136-
Note that the resulting executable is only valid for the OS you built it on. MacOS and Windows bundles must be created separately from a machine/VM of that OS, and then combined into the `com.chrisregado.googlemeet.sdPlugin/dist/` folder with `macos` and `windows` subdirectories for release.
158+
Note that the resulting executable is only valid for the OS you built it on. macOS, Linux, and Windows bundles must be created separately from a machine/VM of that OS, and then combined into the `com.chrisregado.googlemeet.sdPlugin/dist/` folder with `macos`, `linux`, and `windows` subdirectories for release.
137159

138160
If you're just testing locally (so you only care about one OS), you can place any file in the other OS's executable location (`CodePath`s from `manifest.json`) to appease the Elgato packaging tool. Example:
139161

140162
```
141163
# If you're running macOS:
142164
mkdir -p com.chrisregado.googlemeet.sdPlugin/dist/windows/main
143165
touch com.chrisregado.googlemeet.sdPlugin/dist/windows/main/main.exe
166+
mkdir -p com.chrisregado.googlemeet.sdPlugin/dist/linux/main
167+
touch com.chrisregado.googlemeet.sdPlugin/dist/linux/main/main
168+
169+
# If you're running Linux:
170+
mkdir -p com.chrisregado.googlemeet.sdPlugin/dist/macos/main
171+
touch com.chrisregado.googlemeet.sdPlugin/dist/macos/main/main
172+
mkdir -p com.chrisregado.googlemeet.sdPlugin/dist/windows/main
173+
touch com.chrisregado.googlemeet.sdPlugin/dist/windows/main/main.exe
144174
145175
# If you're running Windows:
146176
mkdir com.chrisregado.googlemeet.sdPlugin\dist\macos\main
147177
type nul > com.chrisregado.googlemeet.sdPlugin\dist\macos\main\main
178+
mkdir com.chrisregado.googlemeet.sdPlugin\dist\linux\main
179+
type nul > com.chrisregado.googlemeet.sdPlugin\dist\linux\main\main
148180
```
149181

150182
Or, if you don't ever plan on publishing your local builds, delete the other OS's CodePath and `OS` entry in manifest.json so you don't have to worry about multi-OS support.
151183

184+
Note that the Elgato `streamdeck` CLI does not recognize `CodePathLin` (it's an OpenDeck extension). If you need to run `streamdeck validate` or `streamdeck pack` locally, temporarily remove the `CodePathLin` entry from manifest.json first.
185+
152186
Finally, use Elgato's `streamdeck` CLI tool to bundle everything into the Stream Deck plugin distributable that you can install or send to users. From the root of this git repo, run:
153187

154188
```

RELEASE_INSTRUCTIONS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ Follow these steps each time you want to release a new version of the plugin and
3737
1. Tag the commit you wish to release and push it to GitHub. We use semantic versioning with a "v" prefix for our releases. For example: `git checkout master && git tag v1.2.3 && git push origin tag v1.2.3`
3838
* Our CI jobs will update version numbers automatically to match that tag for both the plugin and browser extensions. You don't need to manually change any version numbers in code/config.
3939
2. CI jobs should automatically launch against that tag to build the [Stream Deck plugin](https://github.com/ChrisRegado/streamdeck-googlemeet/actions/workflows/streamdeck-plugin-build.yml) and [browser extensions](https://github.com/ChrisRegado/streamdeck-googlemeet/actions/workflows/browser-extension-build.yml). (The list of workflow runs should show one copy of each of those two jobs with your `v1.2.3` tag.) Wait for them to complete successfully.
40-
3. Click into those two build jobs, and on each job's "Summary" tab, download our build artifacts. The browser extension build job should have `chrome-extension` and `firefox-extension-signed` artifacts, and the plugin build job should have `com.chrisregado.googlemeet.streamDeckPlugin`.
41-
4. Do a final manual validation of those release artifacts. Install the plugin, Firefox extension, and Chrome extension, and verify basic functionality.
40+
3. Click into those two build jobs, and on each job's "Summary" tab, download our build artifacts. The browser extension build job should have `chrome-extension` and `firefox-extension-signed` artifacts, and the plugin build job should have `com.chrisregado.googlemeet.streamDeckPlugin` (macOS/Windows, Elgato-validated) and `com.chrisregado.googlemeet-linux.streamDeckPlugin` (Linux-inclusive, for OpenDeck).
41+
4. Do a final manual validation of those release artifacts. Install the plugin, Firefox extension, and Chrome extension, and verify basic functionality. If you have access to a Linux machine with OpenDeck, test the Linux-inclusive package as well.
4242
5. On the Github page for your repo, click "Releases". (https://github.com/ChrisRegado/streamdeck-googlemeet/releases)
4343
6. Click "Draft a new release".
4444
7. Click the "Tag" button and select the tag you made in the previous step.
4545
8. Use the your tag name as the "Release title", and enter a description summarizing notable changes in this release.
4646
9. Select the "Set as a pre-release" checkbox near the bottom of the page.
4747
10. Click "Publish release".
48-
11. Our [release CI job](https://github.com/ChrisRegado/streamdeck-googlemeet/actions/workflows/release.yaml) should automatically start and attach our tag's artifacts to the GitHub Release. Wait for it to complete. If all goes well, in a minute or two you should see 3 attachments appear on the release: the `com.chrisregado.googlemeet.streamDeckPlugin` plugin, a zip of the Chrome extension, and an `.xpi` file for the Firefox extension.
48+
11. Our [release CI job](https://github.com/ChrisRegado/streamdeck-googlemeet/actions/workflows/release.yaml) should automatically start and attach our tag's artifacts to the GitHub Release. Wait for it to complete. If all goes well, in a minute or two you should see 4 attachments appear on the release: the `com.chrisregado.googlemeet.streamDeckPlugin` plugin (macOS/Windows), the `com.chrisregado.googlemeet-linux.streamDeckPlugin` (Linux-inclusive, for OpenDeck), a zip of the Chrome extension, and an `.xpi` file for the Firefox extension.
4949
12. Edit the release, uncheck the "Set as a pre-release" checkbox at the bottom of the page, select the "Set as the latest release" checkbox, and click "Update release".

com.chrisregado.googlemeet.sdPlugin/manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@
425425
"CodePath": "dist/macos/main/main",
426426
"CodePathMac": "dist/macos/main/main",
427427
"CodePathWin": "dist/windows/main/main.exe",
428+
"CodePathLin": "dist/linux/main/main",
428429
"Description": "A Stream Deck plugin to manage your Google Meet calls.",
429430
"Name": "Google Meet",
430431
"UUID": "com.chrisregado.googlemeet",
@@ -441,6 +442,9 @@
441442
{
442443
"Platform": "windows",
443444
"MinimumVersion": "10"
445+
},
446+
{
447+
"Platform": "linux"
444448
}
445449
],
446450
"Software": {

streamdeck-plugin/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
altgraph==0.17.4
2-
macholib==1.16.3
1+
altgraph==0.17.4; sys_platform == 'darwin'
2+
macholib==1.16.3; sys_platform == 'darwin'
33
packaging==25.0
44
pyinstaller==6.14.2
55
pyinstaller-hooks-contrib==2025.8

0 commit comments

Comments
 (0)