Skip to content

Commit 3e55b53

Browse files
Jaewe Heoimportre
authored andcommitted
🎉 Initial commit
0 parents  commit 3e55b53

File tree

7 files changed

+314
-0
lines changed

7 files changed

+314
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
*.alfredworkflow

Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
OUTPUT = Screenshot.alfredworkflow
2+
3+
all: clean build
4+
5+
clean:
6+
@rm -rf $(OUTPUT)
7+
8+
bump:
9+
@plutil -replace version -string $(VERSION) info.plist
10+
@git add info.plist
11+
@git commit -m "🔖 $(VERSION)" &> /dev/null || true
12+
13+
build: clean
14+
@zip $(OUTPUT) \
15+
icon.png \
16+
info.plist \
17+
license \
18+
readme.md \
19+
screenshot.js &> /dev/null
20+
21+
release: build
22+
@gh release create $(VERSION) \
23+
--title $(VERSION) \
24+
--generate-notes \
25+
$(OUTPUT)

icon.png

51.7 KB
Loading

info.plist

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>bundleid</key>
6+
<string>com.importre.screenshot</string>
7+
<key>connections</key>
8+
<dict>
9+
<key>0D8E6B1F-9688-4B23-8A3E-52772496176F</key>
10+
<array>
11+
<dict>
12+
<key>destinationuid</key>
13+
<string>6791E0B2-EF7E-4B4E-8750-155F7ACD0B13</string>
14+
<key>modifiers</key>
15+
<integer>0</integer>
16+
<key>modifiersubtext</key>
17+
<string></string>
18+
<key>vitoclose</key>
19+
<false/>
20+
</dict>
21+
</array>
22+
<key>6791E0B2-EF7E-4B4E-8750-155F7ACD0B13</key>
23+
<array/>
24+
</dict>
25+
<key>createdby</key>
26+
<string>importre</string>
27+
<key>description</key>
28+
<string>Take a screenshot with your beautiful wallpaper.</string>
29+
<key>disabled</key>
30+
<false/>
31+
<key>name</key>
32+
<string>Screenshot</string>
33+
<key>objects</key>
34+
<array>
35+
<dict>
36+
<key>config</key>
37+
<dict>
38+
<key>concurrently</key>
39+
<false/>
40+
<key>escaping</key>
41+
<integer>102</integer>
42+
<key>script</key>
43+
<string>resolution=(${(s/ /)1})
44+
./screenshot.js $resolution[1] $resolution[2]</string>
45+
<key>scriptargtype</key>
46+
<integer>1</integer>
47+
<key>scriptfile</key>
48+
<string></string>
49+
<key>type</key>
50+
<integer>5</integer>
51+
</dict>
52+
<key>type</key>
53+
<string>alfred.workflow.action.script</string>
54+
<key>uid</key>
55+
<string>6791E0B2-EF7E-4B4E-8750-155F7ACD0B13</string>
56+
<key>version</key>
57+
<integer>2</integer>
58+
</dict>
59+
<dict>
60+
<key>config</key>
61+
<dict>
62+
<key>argumenttrimmode</key>
63+
<integer>0</integer>
64+
<key>argumenttype</key>
65+
<integer>1</integer>
66+
<key>fixedorder</key>
67+
<false/>
68+
<key>items</key>
69+
<string>[{"title":"640 x 480","arg":"640 480","subtitle":"4:3"},{"title":"800 x 600","arg":"800 600","subtitle":"4:3"},{"title":"960 × 720","arg":"960 720","subtitle":"4:3"},{"title":"1024 x 768","arg":"1024 768","subtitle":"4:3"},{"title":"1280 x 960","arg":"1280 960","subtitle":"4:3"},{"title":"640 x 360","arg":"640 360","subtitle":"16:9"},{"title":"800 x 450","arg":"800 450","subtitle":"16:9"},{"title":"960 x 540","arg":"960 540","subtitle":"16:9"},{"title":"1024 x 576","arg":"1024 576","subtitle":"16:9"},{"title":"1280 x 720","arg":"1280 720","subtitle":"16:9"}]</string>
70+
<key>keyword</key>
71+
<string>ss</string>
72+
<key>matchmode</key>
73+
<integer>0</integer>
74+
<key>runningsubtext</key>
75+
<string></string>
76+
<key>subtext</key>
77+
<string></string>
78+
<key>title</key>
79+
<string></string>
80+
<key>withspace</key>
81+
<true/>
82+
</dict>
83+
<key>type</key>
84+
<string>alfred.workflow.input.listfilter</string>
85+
<key>uid</key>
86+
<string>0D8E6B1F-9688-4B23-8A3E-52772496176F</string>
87+
<key>version</key>
88+
<integer>1</integer>
89+
</dict>
90+
</array>
91+
<key>readme</key>
92+
<string>See https://github.com/importre/alfred-screenshot</string>
93+
<key>uidata</key>
94+
<dict>
95+
<key>0D8E6B1F-9688-4B23-8A3E-52772496176F</key>
96+
<dict>
97+
<key>xpos</key>
98+
<real>50</real>
99+
<key>ypos</key>
100+
<real>75</real>
101+
</dict>
102+
<key>6791E0B2-EF7E-4B4E-8750-155F7ACD0B13</key>
103+
<dict>
104+
<key>xpos</key>
105+
<real>210</real>
106+
<key>ypos</key>
107+
<real>75</real>
108+
</dict>
109+
</dict>
110+
<key>userconfigurationconfig</key>
111+
<array/>
112+
<key>version</key>
113+
<string>0.0.0</string>
114+
<key>webaddress</key>
115+
<string>https://github.com/importre/alfred-screenshot</string>
116+
</dict>
117+
</plist>

license

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Jaewe Heo
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

readme.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# alfred-screenshot
2+
3+
📸 Take a screenshot with your beautiful wallpaper.
4+
5+
![usage](https://user-images.githubusercontent.com/1744446/208124121-11b3e6e6-c70a-4a58-85c5-a7a40c36dbba.gif)
6+
7+
## Installation
8+
9+
1. Install dependencies.
10+
```sh
11+
brew install importre/core/displays
12+
brew install --cask rectangle
13+
```
14+
1. Go to [releases/latest].
15+
1. Download `Screenshot.alfredworkflow` and then open it!
16+
17+
## Check permissions
18+
19+
* Automation -> Alfred 5 -> System Event
20+
![Automation - System Event](https://user-images.githubusercontent.com/1744446/208055672-b455aeca-3239-4242-831d-2b7e744f9c3a.png)
21+
* Screen Recording
22+
![Screen Recording](https://user-images.githubusercontent.com/1744446/208055688-2a46e2e1-bea6-4b56-9cf0-9bffaed7f40d.png)
23+
24+
## Usage
25+
26+
1. Select the window you want.
27+
1. In Alfred, Type `ss`, select a resolution, and then press <kbd>Enter</kbd>.
28+
1. It will be stored in your **Desktop**. 😎
29+
30+
## Output Example
31+
32+
![Output Example](https://user-images.githubusercontent.com/1744446/208124097-ffefd6f6-32d3-4405-959e-cb3612210807.png)
33+
34+
[releases/latest]: https://github.com/importre/alfred-screenshot/releases/latest

screenshot.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/env osascript -l JavaScript
2+
3+
function run(argv) {
4+
const rectangleId = "com.knollsoft.Rectangle";
5+
const defaultSize = getDefaultSize(rectangleId);
6+
const { dock, menuBar } = currentDockAndMenuBar();
7+
const targetSize = {
8+
width: parseInt(argv[0]) || defaultSize.width,
9+
height: parseInt(argv[1]) || defaultSize.height,
10+
};
11+
12+
try {
13+
hidedockAndMenuBar();
14+
hideOthers();
15+
moveToCenter(defaultSize, targetSize, rectangleId);
16+
screenshot(getRect(targetSize));
17+
} finally {
18+
setDockAndMenuBar(dock, menuBar);
19+
}
20+
}
21+
22+
function currentDockAndMenuBar() {
23+
const dockPreferences = new Application("System Events").dockPreferences();
24+
return {
25+
dock: dockPreferences.autohide(),
26+
menuBar: dockPreferences.autohideMenuBar(),
27+
};
28+
}
29+
30+
function setDockAndMenuBar(hideDock, hideMenuBar) {
31+
const dockPreferences = new Application("System Events").dockPreferences();
32+
dockPreferences.autohide = hideDock;
33+
dockPreferences.autohideMenuBar = hideMenuBar;
34+
}
35+
36+
function hidedockAndMenuBar() {
37+
setDockAndMenuBar(true, true);
38+
}
39+
40+
function hideOthers() {
41+
new Application("System Events")
42+
.processes()
43+
.filter((process) => process.visible() && !process.frontmost())
44+
.forEach((process) => (process.visible = false));
45+
}
46+
47+
function moveToCenter(defaultSize, targetSize, rectangleId) {
48+
const rectangle = new Application("Rectangle");
49+
if (JSON.stringify(defaultSize) !== JSON.stringify(targetSize)) {
50+
const { width, height } = targetSize;
51+
const write = `defaults write ${rectangleId}`;
52+
rectangle.quit();
53+
runCommand(`${write} specifiedWidth -float ${width}`);
54+
runCommand(`${write} specifiedHeight -float ${height}`);
55+
}
56+
if (!rectangle.running()) {
57+
runCommand(`open -b ${rectangleId}`);
58+
}
59+
runCommand('open -g "rectangle://execute-action?name=specified"');
60+
}
61+
62+
function screenshot(rect) {
63+
runCommand(
64+
[
65+
"screencapture",
66+
"-m",
67+
"-T 1",
68+
`-R ${rect.x},${rect.y},${rect.width},${rect.height}`,
69+
"${HOME}/Desktop/$(date +%Y%m%d-%H%M%S).png",
70+
].join(" ")
71+
);
72+
}
73+
74+
function runCommand(command) {
75+
try {
76+
const app = Application.currentApplication();
77+
app.includeStandardAdditions = true;
78+
return app.doShellScript(command);
79+
} catch {
80+
return "";
81+
}
82+
}
83+
84+
function getScreenSize() {
85+
const json = runCommand("displays");
86+
const displays = JSON.parse(json);
87+
const display = displays.find((display) => display.isMain);
88+
if (display === undefined) {
89+
return;
90+
}
91+
return {
92+
width: display.resolution.width,
93+
height: display.resolution.height,
94+
topInset: display.safeAreaInsets.top,
95+
};
96+
}
97+
98+
function getRect(targetSize) {
99+
const padding = 160;
100+
const size = getScreenSize();
101+
return {
102+
x: (size.width - targetSize.width - padding) / 2,
103+
y: (size.height - targetSize.height + size.topInset - padding) / 2,
104+
width: targetSize.width + padding,
105+
height: targetSize.height + padding,
106+
};
107+
}
108+
109+
function getDefaultSize(rectangleId) {
110+
const read = `defaults read ${rectangleId}`;
111+
return {
112+
width: parseInt(runCommand(`${read} specifiedWidth`)) || 800,
113+
height: parseInt(runCommand(`${read} specifiedHeight`)) || 600,
114+
};
115+
}

0 commit comments

Comments
 (0)