├── .github
├── CONTRIBUTING.md
└── ISSUE_TEMPLATE.md
├── .gitignore
├── README.md
├── Youdao.alfredworkflow
├── icon.png
├── info.plist
└── workflows.php
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # CONTRIBUTING
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **PHP Version**
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Youdao.alfredworkflow
2 | ======================
3 |
4 | 有道翻译 workflow for Alfred v2
5 |
6 | 默认快捷键 "f",多个翻译结果,回车或直接点击将结果复制到剪切板。
7 |
8 | 通过输入"ff" 即可以在有道词典的页面中查询输入的单词。方便用户查看更详细的信息以及将单词加入生词本操作。
9 |
10 | ## [下载](https://github.com/samqiu/Youdao.alfredworkflow/releases)
11 |
12 | ## Demo
13 |
14 |
15 | ### 多个翻译结果,回车或直接点击将结果复制到剪切板。
16 |
17 | 
18 |
19 |
20 | ### 在有道词典的页面中查询输入的单词
21 |
22 | 
23 |
--------------------------------------------------------------------------------
/Youdao.alfredworkflow:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samqiu/Youdao.alfredworkflow/5e2bf2f515ac1dc5c5cfbb70e02a7d21ee4f5046/Youdao.alfredworkflow
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samqiu/Youdao.alfredworkflow/5e2bf2f515ac1dc5c5cfbb70e02a7d21ee4f5046/icon.png
--------------------------------------------------------------------------------
/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | com.samqiu.workflows.youdao
7 | connections
8 |
9 | 160E3B74-C1C8-4F4F-8E6E-A64B1CDC48FE
10 |
11 |
12 | destinationuid
13 | 96159F02-1880-4FCF-9B30-02652898058D
14 | modifiers
15 | 0
16 | modifiersubtext
17 |
18 |
19 |
20 | destinationuid
21 | B831172E-379D-444D-AECE-4BA8D2A662DB
22 | modifiers
23 | 0
24 | modifiersubtext
25 |
26 |
27 |
28 |
29 | createdby
30 | samqiu
31 | description
32 | 有道翻译
33 | disabled
34 |
35 | name
36 | Youdao
37 | objects
38 |
39 |
40 | config
41 |
42 | autopaste
43 |
44 | clipboardtext
45 | {query}
46 |
47 | type
48 | alfred.workflow.output.clipboard
49 | uid
50 | 96159F02-1880-4FCF-9B30-02652898058D
51 | version
52 | 0
53 |
54 |
55 | config
56 |
57 | argumenttype
58 | 0
59 | escaping
60 | 62
61 | keyword
62 | f
63 | runningsubtext
64 | 翻译中……
65 | script
66 | require_once('workflows.php');
67 |
68 | $w = new Workflows();
69 | $query = urlencode("{query}");
70 |
71 | $url = 'http://fanyi.youdao.com/openapi.do?keyfrom=Youdao-workflow&key=1738796775&type=data&doctype=json&version=1.1&q=' . $query;
72 | $results = json_decode($w->request($url));
73 |
74 | foreach ($results->translation as $result) {
75 | $w->result($result, $result, $result, $result, 'icon.png', '');
76 | }
77 |
78 | if (count($results->web) > 0) {
79 | foreach ($results->web as $web) {
80 | $w->result('', implode(', ', $web->value), implode(', ', $web->value), $web->key, 'icon.png');
81 | }
82 | }
83 |
84 | if (count($w->results()) == 0) {
85 | $w->result('', '', '没有结果', '', 'icon.png', 'no');
86 | }
87 |
88 | echo $w->toxml();
89 | subtext
90 | 请输入需要翻译的中英文
91 | title
92 | 有道翻译
93 | type
94 | 1
95 | withspace
96 |
97 |
98 | type
99 | alfred.workflow.input.scriptfilter
100 | uid
101 | 160E3B74-C1C8-4F4F-8E6E-A64B1CDC48FE
102 | version
103 | 0
104 |
105 |
106 | config
107 |
108 | lastpathcomponent
109 |
110 | onlyshowifquerypopulated
111 |
112 | output
113 | 0
114 | removeextension
115 |
116 | sticky
117 |
118 | text
119 | {query}
120 | title
121 | Translation result copied
122 |
123 | type
124 | alfred.workflow.output.notification
125 | uid
126 | B831172E-379D-444D-AECE-4BA8D2A662DB
127 | version
128 | 0
129 |
130 |
131 | readme
132 |
133 | uidata
134 |
135 | 160E3B74-C1C8-4F4F-8E6E-A64B1CDC48FE
136 |
137 | ypos
138 | 110
139 |
140 | 96159F02-1880-4FCF-9B30-02652898058D
141 |
142 | ypos
143 | 40
144 |
145 | B831172E-379D-444D-AECE-4BA8D2A662DB
146 |
147 | ypos
148 | 160
149 |
150 |
151 | webaddress
152 | http://samqiu.com/posts/52-youdao-workflow-for-alfred-v2
153 |
154 |
155 |
--------------------------------------------------------------------------------
/workflows.php:
--------------------------------------------------------------------------------
1 | path = exec('pwd');
31 | $this->home = exec('printf $HOME');
32 |
33 | if ( file_exists( 'info.plist' ) ):
34 | $this->bundle = $this->get( 'bundleid', 'info.plist' );
35 | endif;
36 |
37 | if ( !is_null( $bundleid ) ):
38 | $this->bundle = $bundleid;
39 | endif;
40 |
41 | $this->cache = $this->home. "/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/".$this->bundle;
42 | $this->data = $this->home. "/Library/Application Support/Alfred 2/Workflow Data/".$this->bundle;
43 |
44 | if ( !file_exists( $this->cache ) ):
45 | exec("mkdir '".$this->cache."'");
46 | endif;
47 |
48 | if ( !file_exists( $this->data ) ):
49 | exec("mkdir '".$this->data."'");
50 | endif;
51 |
52 | $this->results = array();
53 | }
54 |
55 | /**
56 | * Description:
57 | * Accepts no parameter and returns the value of the bundle id for the current workflow.
58 | * If no value is available, then false is returned.
59 | *
60 | * @param none
61 | * @return false if not available, bundle id value if available.
62 | */
63 | public function bundle()
64 | {
65 | if ( is_null( $this->bundle ) ):
66 | return false;
67 | else:
68 | return $this->bundle;
69 | endif;
70 | }
71 |
72 | /**
73 | * Description:
74 | * Accepts no parameter and returns the value of the path to the cache directory for your
75 | * workflow if it is available. Returns false if the value isn't available.
76 | *
77 | * @param none
78 | * @return false if not available, path to the cache directory for your workflow if available.
79 | */
80 | public function cache()
81 | {
82 | if ( is_null( $this->bundle ) ):
83 | return false;
84 | else:
85 | if ( is_null( $this->cache ) ):
86 | return false;
87 | else:
88 | return $this->cache;
89 | endif;
90 | endif;
91 | }
92 |
93 | /**
94 | * Description:
95 | * Accepts no parameter and returns the value of the path to the storage directory for your
96 | * workflow if it is available. Returns false if the value isn't available.
97 | *
98 | * @param none
99 | * @return false if not available, path to the storage directory for your workflow if available.
100 | */
101 | public function data()
102 | {
103 | if ( is_null( $this->bundle ) ):
104 | return false;
105 | else:
106 | if ( is_null( $this->data ) ):
107 | return false;
108 | else:
109 | return $this->data;
110 | endif;
111 | endif;
112 | }
113 |
114 | /**
115 | * Description:
116 | * Accepts no parameter and returns the value of the path to the current directory for your
117 | * workflow if it is available. Returns false if the value isn't available.
118 | *
119 | * @param none
120 | * @return false if not available, path to the current directory for your workflow if available.
121 | */
122 | public function path()
123 | {
124 | if ( is_null( $this->path ) ):
125 | return false;
126 | else:
127 | return $this->path;
128 | endif;
129 | }
130 |
131 | /**
132 | * Description:
133 | * Accepts no parameter and returns the value of the home path for the current user
134 | * Returns false if the value isn't available.
135 | *
136 | * @param none
137 | * @return false if not available, home path for the current user if available.
138 | */
139 | public function home()
140 | {
141 | if ( is_null( $this->home ) ):
142 | return false;
143 | else:
144 | return $this->home;
145 | endif;
146 | }
147 |
148 | /**
149 | * Description:
150 | * Returns an array of available result items
151 | *
152 | * @param none
153 | * @return array - list of result items
154 | */
155 | public function results()
156 | {
157 | return $this->results;
158 | }
159 |
160 | /**
161 | * Description:
162 | * Convert an associative array into XML format
163 | *
164 | * @param $a - An associative array to convert
165 | * @param $format - format of data being passed (json or array), defaults to array
166 | * @return - XML string representation of the array
167 | */
168 | public function toxml( $a=null, $format='array' ) {
169 |
170 | if ( $format == 'json' ):
171 | $a = json_decode( $a, TRUE );
172 | endif;
173 |
174 | if ( is_null( $a ) && !empty( $this->results ) ):
175 | $a = $this->results;
176 | elseif ( is_null( $a ) && empty( $this->results ) ):
177 | return false;
178 | endif;
179 |
180 | $items = new SimpleXMLElement(""); // Create new XML element
181 |
182 | foreach( $a as $b ): // Lop through each object in the array
183 | $c = $items->addChild( 'item' ); // Add a new 'item' element for each object
184 | $c_keys = array_keys( $b ); // Grab all the keys for that item
185 | foreach( $c_keys as $key ): // For each of those keys
186 | if ( $key == 'uid' ):
187 | $c->addAttribute( 'uid', $b[$key] );
188 | elseif ( $key == 'arg' ):
189 | $c->addAttribute( 'arg', $b[$key] );
190 | elseif ( $key == 'type' ):
191 | $c->addAttribute( 'type', $b[$key] );
192 | elseif ( $key == 'valid' ):
193 | if ( $b[$key] == 'yes' || $b[$key] == 'no' ):
194 | $c->addAttribute( 'valid', $b[$key] );
195 | endif;
196 | elseif ( $key == 'autocomplete' ):
197 | $c->addAttribute( 'autocomplete', $b[$key] );
198 | elseif ( $key == 'icon' ):
199 | if ( substr( $b[$key], 0, 9 ) == 'fileicon:' ):
200 | $val = substr( $b[$key], 9 );
201 | $c->$key = $val;
202 | $c->$key->addAttribute( 'type', 'fileicon' );
203 | elseif ( substr( $b[$key], 0, 9 ) == 'filetype:' ):
204 | $val = substr( $b[$key], 9 );
205 | $c->$key = $val;
206 | $c->$key->addAttribute( 'type', 'filetype' );
207 | else:
208 | $c->$key = $b[$key];
209 | endif;
210 | else:
211 | $c->$key = $b[$key];
212 | endif;
213 | endforeach;
214 | endforeach;
215 |
216 | return $items->asXML(); // Return XML string representation of the array
217 |
218 | }
219 |
220 | /**
221 | * Description:
222 | * Remove all items from an associative array that do not have a value
223 | *
224 | * @param $a - Associative array
225 | * @return bool
226 | */
227 | private function empty_filter( $a ) {
228 | if ( $a == '' || $a == null ): // if $a is empty or null
229 | return false; // return false, else, return true
230 | else:
231 | return true;
232 | endif;
233 | }
234 |
235 | /**
236 | * Description:
237 | * Save values to a specified plist. If the first parameter is an associative
238 | * array, then the second parameter becomes the plist file to save to. If the
239 | * first parameter is string, then it is assumed that the first parameter is
240 | * the label, the second parameter is the value, and the third parameter is
241 | * the plist file to save the data to.
242 | *
243 | * @param $a - associative array of values to save
244 | * @param $b - the value of the setting
245 | * @param $c - the plist to save the values into
246 | * @return string - execution output
247 | */
248 | public function set( $a=null, $b=null, $c=null )
249 | {
250 | if ( is_array( $a ) ):
251 | if ( file_exists( $b ) ):
252 | if ( file_exists( $this->path.'/'.$b ) ):
253 | $b = $this->path.'/'.$b;
254 | endif;
255 | elseif ( file_exists( $this->data."/".$b ) ):
256 | $b = $this->data."/".$b;
257 | elseif ( file_exists( $this->cache."/".$b ) ):
258 | $b = $this->cache."/".$b;
259 | else:
260 | $b = $this->data."/".$b;
261 | endif;
262 | else:
263 | if ( file_exists( $c ) ):
264 | if ( file_exists( $this->path.'/'.$c ) ):
265 | $c = $this->path.'/'.$c;
266 | endif;
267 | elseif ( file_exists( $this->data."/".$c ) ):
268 | $c = $this->data."/".$c;
269 | elseif ( file_exists( $this->cache."/".$c ) ):
270 | $c = $this->cache."/".$c;
271 | else:
272 | $c = $this->data."/".$c;
273 | endif;
274 | endif;
275 |
276 | if ( is_array( $a ) ):
277 | foreach( $a as $k => $v ):
278 | exec( 'defaults write "'. $b .'" '. $k .' "'. $v .'"');
279 | endforeach;
280 | else:
281 | exec( 'defaults write "'. $c .'" '. $a .' "'. $b .'"');
282 | endif;
283 | }
284 |
285 | /**
286 | * Description:
287 | * Read a value from the specified plist
288 | *
289 | * @param $a - the value to read
290 | * @param $b - plist to read the values from
291 | * @return bool false if not found, string if found
292 | */
293 | public function get( $a, $b ) {
294 |
295 | if ( file_exists( $b ) ):
296 | if ( file_exists( $this->path.'/'.$b ) ):
297 | $b = $this->path.'/'.$b;
298 | endif;
299 | elseif ( file_exists( $this->data."/".$b ) ):
300 | $b = $this->data."/".$b;
301 | elseif ( file_exists( $this->cache."/".$b ) ):
302 | $b = $this->cache."/".$b;
303 | else:
304 | return false;
305 | endif;
306 |
307 | exec( 'defaults read "'. $b .'" '.$a, $out ); // Execute system call to read plist value
308 |
309 | if ( $out == "" ):
310 | return false;
311 | endif;
312 |
313 | $out = $out[0];
314 | return $out; // Return item value
315 | }
316 |
317 | /**
318 | * Description:
319 | * Read data from a remote file/url, essentially a shortcut for curl
320 | *
321 | * @param $url - URL to request
322 | * @param $options - Array of curl options
323 | * @return result from curl_exec
324 | */
325 | public function request( $url=null, $options=null )
326 | {
327 | if ( is_null( $url ) ):
328 | return false;
329 | endif;
330 |
331 | $defaults = array( // Create a list of default curl options
332 | CURLOPT_RETURNTRANSFER => true, // Returns the result as a string
333 | CURLOPT_URL => $url, // Sets the url to request
334 | CURLOPT_FRESH_CONNECT => true
335 | );
336 |
337 | if ( $options ):
338 | foreach( $options as $k => $v ):
339 | $defaults[$k] = $v;
340 | endforeach;
341 | endif;
342 |
343 | array_filter( $defaults, // Filter out empty options from the array
344 | array( $this, 'empty_filter' ) );
345 |
346 | $ch = curl_init(); // Init new curl object
347 | curl_setopt_array( $ch, $defaults ); // Set curl options
348 | $out = curl_exec( $ch ); // Request remote data
349 | $err = curl_error( $ch );
350 | curl_close( $ch ); // End curl request
351 |
352 | if ( $err ):
353 | return $err;
354 | else:
355 | return $out;
356 | endif;
357 | }
358 |
359 | /**
360 | * Description:
361 | * Allows searching the local hard drive using mdfind
362 | *
363 | * @param $query - search string
364 | * @return array - array of search results
365 | */
366 | public function mdfind( $query )
367 | {
368 | exec('mdfind "'.$query.'"', $results);
369 | return $results;
370 | }
371 |
372 | /**
373 | * Description:
374 | * Accepts data and a string file name to store data to local file as cache
375 | *
376 | * @param array - data to save to file
377 | * @param file - filename to write the cache data to
378 | * @return none
379 | */
380 | public function write( $a, $b )
381 | {
382 | if ( file_exists( $b ) ):
383 | if ( file_exists( $this->path.'/'.$b ) ):
384 | $b = $this->path.'/'.$b;
385 | endif;
386 | elseif ( file_exists( $this->data."/".$b ) ):
387 | $b = $this->data."/".$b;
388 | elseif ( file_exists( $this->cache."/".$b ) ):
389 | $b = $this->cache."/".$b;
390 | else:
391 | $b = $this->data."/".$b;
392 | endif;
393 |
394 | if ( is_array( $a ) ):
395 | $a = json_encode( $a );
396 | file_put_contents( $b, $a );
397 | return true;
398 | elseif ( is_string( $a ) ):
399 | file_put_contents( $b, $a );
400 | return true;
401 | else:
402 | return false;
403 | endif;
404 | }
405 |
406 | /**
407 | * Description:
408 | * Returns data from a local cache file
409 | *
410 | * @param file - filename to read the cache data from
411 | * @return false if the file cannot be found, the file data if found. If the file
412 | * format is json encoded, then a json object is returned.
413 | */
414 | public function read( $a )
415 | {
416 | if ( file_exists( $a ) ):
417 | if ( file_exists( $this->path.'/'.$a ) ):
418 | $a = $this->path.'/'.$a;
419 | endif;
420 | elseif ( file_exists( $this->data."/".$a ) ):
421 | $a = $this->data."/".$a;
422 | elseif ( file_exists( $this->cache."/".$a ) ):
423 | $a = $this->cache."/".$a;
424 | else:
425 | return false;
426 | endif;
427 |
428 | $out = file_get_contents( $a );
429 | if ( !is_null( json_decode( $out ) ) ):
430 | $out = json_decode( $out );
431 | endif;
432 |
433 | return $out;
434 | }
435 |
436 | /**
437 | * Description:
438 | * Helper function that just makes it easier to pass values into a function
439 | * and create an array result to be passed back to Alfred
440 | *
441 | * @param $uid - the uid of the result, should be unique
442 | * @param $arg - the argument that will be passed on
443 | * @param $title - The title of the result item
444 | * @param $sub - The subtitle text for the result item
445 | * @param $icon - the icon to use for the result item
446 | * @param $valid - sets whether the result item can be actioned
447 | * @param $auto - the autocomplete value for the result item
448 | * @return array - array item to be passed back to Alfred
449 | */
450 | public function result( $uid, $arg, $title, $sub, $icon, $valid='yes', $auto=null, $type=null )
451 | {
452 | $temp = array(
453 | 'uid' => $uid,
454 | 'arg' => $arg,
455 | 'title' => $title,
456 | 'subtitle' => $sub,
457 | 'icon' => $icon,
458 | 'valid' => $valid,
459 | 'autocomplete' => $auto,
460 | 'type' => $type
461 | );
462 |
463 | if ( is_null( $type ) ):
464 | unset( $temp['type'] );
465 | endif;
466 |
467 | array_push( $this->results, $temp );
468 |
469 | return $temp;
470 | }
471 |
472 | }
--------------------------------------------------------------------------------