├── .gitignore
├── List Filter Images
├── icon-applepodcasts.png
├── icon-breaker.png
├── icon-castbox.png
├── icon-castro.png
├── icon-googlepodcasts.png
├── icon-iheartradio.png
├── icon-overcast.png
├── icon-playerfm.png
├── icon-pocketcasts.png
├── icon-podcastaddict.png
├── icon-radiopublic.png
├── icon-rss.png
├── icon-spotify.png
└── icon-stitcher.png
├── _config.yml
├── demo.gif
├── icon.png
├── index.js
├── info.plist
├── license
├── package.json
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | media
--------------------------------------------------------------------------------
/List Filter Images/icon-applepodcasts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-applepodcasts.png
--------------------------------------------------------------------------------
/List Filter Images/icon-breaker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-breaker.png
--------------------------------------------------------------------------------
/List Filter Images/icon-castbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-castbox.png
--------------------------------------------------------------------------------
/List Filter Images/icon-castro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-castro.png
--------------------------------------------------------------------------------
/List Filter Images/icon-googlepodcasts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-googlepodcasts.png
--------------------------------------------------------------------------------
/List Filter Images/icon-iheartradio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-iheartradio.png
--------------------------------------------------------------------------------
/List Filter Images/icon-overcast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-overcast.png
--------------------------------------------------------------------------------
/List Filter Images/icon-playerfm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-playerfm.png
--------------------------------------------------------------------------------
/List Filter Images/icon-pocketcasts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-pocketcasts.png
--------------------------------------------------------------------------------
/List Filter Images/icon-podcastaddict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-podcastaddict.png
--------------------------------------------------------------------------------
/List Filter Images/icon-radiopublic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-radiopublic.png
--------------------------------------------------------------------------------
/List Filter Images/icon-rss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-rss.png
--------------------------------------------------------------------------------
/List Filter Images/icon-spotify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-spotify.png
--------------------------------------------------------------------------------
/List Filter Images/icon-stitcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/List Filter Images/icon-stitcher.png
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | name: Podcast Search for Alfred
2 | title: null
3 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/demo.gif
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ResonantConcepts/podlink-alfred/9258bcb7218e0e97a4e048d04f2fe40cbe15dbd7/icon.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const path = require('path');
3 | const fs = require('fs');
4 | const https = require('https');
5 | const alfy = require('alfy');
6 |
7 | let media = path.join(__dirname, 'media');
8 | let cachelength = 60 * 60 * 1000; // 1 hour cache
9 |
10 | function ensureDirectoryExistence(filePath) {
11 | var dirname = path.dirname(filePath);
12 | if (fs.existsSync(dirname)) {
13 | return true;
14 | }
15 | ensureDirectoryExistence(dirname);
16 | fs.mkdirSync(dirname);
17 | }
18 |
19 |
20 | function download(filename, url, callback) {
21 | ensureDirectoryExistence(filename)
22 | let file = fs.createWriteStream(filename);
23 |
24 | https.get(url, function (response) {
25 | if (callback !== undefined) {
26 | response.pipe(file).on('finish', () => {
27 | callback(file);
28 | });
29 | }
30 | });
31 | }
32 |
33 | (async () => {
34 | const data = await alfy.fetch(`https://itunes.apple.com/search?term=${encodeURIComponent(alfy.input)}&limit=9&media=podcast`, {maxAge: cachelength});
35 |
36 | const results = data.results.map(result => {
37 | const trackCount = (result.trackCount === 300) ? '300+' : result.trackCount;
38 | const iconPath = path.join(media, `${result.collectionId}.jpg`);
39 |
40 | return {
41 | uid: result.collectionId,
42 | title: result.collectionName,
43 | subtitle: `${result.artistName} · Genre: ${result.primaryGenreName} · Episodes: ${trackCount}`,
44 | arg: `https://pod.link/${result.collectionId}`,
45 | icon: {
46 | path: iconPath
47 | }
48 | };
49 | });
50 |
51 | data.results.forEach(result => {
52 | const iconPath = path.join(media, `${result.collectionId}.jpg`);
53 |
54 | fs.exists(iconPath, exists => {
55 | if (!exists) {
56 | download(iconPath, result.artworkUrl100, () => {
57 | return true;
58 | });
59 | }
60 | });
61 | });
62 |
63 | alfy.output(results);
64 | })();
65 |
--------------------------------------------------------------------------------
/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | link.pod.search
7 | category
8 | Productivity
9 | connections
10 |
11 | 0F635C4D-EF27-4E06-BDF4-1898EE3039AB
12 |
13 |
14 | destinationuid
15 | 28180B02-C512-4E2F-BA05-E28A7C05E1A7
16 | modifiers
17 | 0
18 | modifiersubtext
19 |
20 | vitoclose
21 |
22 |
23 |
24 | destinationuid
25 | F1304401-205F-426B-914D-E8AA5A2BFB82
26 | modifiers
27 | 0
28 | modifiersubtext
29 |
30 | vitoclose
31 |
32 |
33 |
34 | 1BB1CD87-F91F-4887-9F8A-A99F2E730262
35 |
36 |
37 | destinationuid
38 | E8058394-1462-41B7-A91D-909B07A34AF2
39 | modifiers
40 | 0
41 | modifiersubtext
42 |
43 | vitoclose
44 |
45 |
46 |
47 | 28180B02-C512-4E2F-BA05-E28A7C05E1A7
48 |
49 |
50 | destinationuid
51 | 1BB1CD87-F91F-4887-9F8A-A99F2E730262
52 | modifiers
53 | 0
54 | modifiersubtext
55 |
56 | vitoclose
57 |
58 |
59 |
60 |
61 | createdby
62 | Nathan Gathright
63 | description
64 | Search for podcasts (powered by pod.link)
65 | disabled
66 |
67 | name
68 | Podcast Search
69 | objects
70 |
71 |
72 | config
73 |
74 | browser
75 |
76 | spaces
77 |
78 | url
79 | {query}
80 | utf8
81 |
82 |
83 | type
84 | alfred.workflow.action.openurl
85 | uid
86 | E8058394-1462-41B7-A91D-909B07A34AF2
87 | version
88 | 1
89 |
90 |
91 | config
92 |
93 | alfredfiltersresults
94 |
95 | alfredfiltersresultsmatchmode
96 | 0
97 | argumenttreatemptyqueryasnil
98 |
99 | argumenttrimmode
100 | 0
101 | argumenttype
102 | 0
103 | escaping
104 | 102
105 | keyword
106 | pod
107 | queuedelaycustom
108 | 3
109 | queuedelayimmediatelyinitially
110 |
111 | queuedelaymode
112 | 0
113 | queuemode
114 | 2
115 | runningsubtext
116 | Searching…
117 | script
118 | ./node_modules/.bin/run-node index.js "$1"
119 | scriptargtype
120 | 1
121 | scriptfile
122 | index.js
123 | subtext
124 |
125 | title
126 | Search pod.link for '{query}'
127 | type
128 | 0
129 | withspace
130 |
131 |
132 | type
133 | alfred.workflow.input.scriptfilter
134 | uid
135 | 0F635C4D-EF27-4E06-BDF4-1898EE3039AB
136 | version
137 | 3
138 |
139 |
140 | config
141 |
142 | argumenttrimmode
143 | 0
144 | argumenttype
145 | 2
146 | fixedorder
147 |
148 | items
149 | [{"title":"Open in pod.link","arg":"{var:podlink}","subtitle":""},{"imagefile":"icon-applepodcasts.png","title":"Open in Apple Podcasts","arg":"{var:podlink}.apple","subtitle":""},{"imagefile":"icon-breaker.png","title":"Open in Breaker","arg":"{var:podlink}.breaker","subtitle":""},{"imagefile":"icon-castbox.png","title":"Open in Castbox","arg":"{var:podlink}.castbox","subtitle":""},{"imagefile":"icon-castro.png","title":"Open in Castro","arg":"{var:podlink}.castro","subtitle":""},{"imagefile":"icon-googlepodcasts.png","title":"Open in Google Podcasts","arg":"{var:podlink}.google","subtitle":""},{"imagefile":"icon-overcast.png","title":"Open in Overcast","arg":"{var:podlink}.overcast","subtitle":""},{"imagefile":"icon-playerfm.png","title":"Open in Player FM","arg":"{var:podlink}.playerfm","subtitle":""},{"imagefile":"icon-pocketcasts.png","title":"Open in Pocket Casts","arg":"{var:podlink}.pocketcasts","subtitle":""},{"imagefile":"icon-podcastaddict.png","title":"Open in Podcast Addict","arg":"{var:podlink}.podcastaddict","subtitle":""},{"imagefile":"icon-radiopublic.png","title":"Open in RadioPublic","arg":"{var:podlink}.radiopublic","subtitle":""},{"imagefile":"icon-spotify.png","title":"Open in Spotify","arg":"{var:podlink}.spotify","subtitle":""},{"imagefile":"icon-stitcher.png","title":"Open in Stitcher","arg":"{var:podlink}.stitcher","subtitle":""},{"imagefile":"icon-rss.png","title":"Open in RSS","arg":"{var:podlink}.rss","subtitle":""},{"imagefile":"icon-iheartradio.png","title":"Open in iHeartRadio","arg":"{var:pod.link}.iheartradio"}]
150 | runningsubtext
151 |
152 | subtext
153 |
154 | title
155 |
156 | withspace
157 |
158 |
159 | type
160 | alfred.workflow.input.listfilter
161 | uid
162 | 1BB1CD87-F91F-4887-9F8A-A99F2E730262
163 | version
164 | 1
165 |
166 |
167 | config
168 |
169 | argument
170 |
171 | passthroughargument
172 |
173 | variables
174 |
175 | podlink
176 | {query}
177 |
178 |
179 | type
180 | alfred.workflow.utility.argument
181 | uid
182 | 28180B02-C512-4E2F-BA05-E28A7C05E1A7
183 | version
184 | 1
185 |
186 |
187 | config
188 |
189 | concurrently
190 |
191 | escaping
192 | 0
193 | script
194 | # THESE VARIABLES MUST BE SET. SEE THE ONEUPDATER README FOR AN EXPLANATION OF EACH.
195 | readonly remote_info_plist=''
196 | readonly workflow_url='nathangathright/alfred-producthunt-search'
197 | readonly download_type='github_release'
198 | readonly frequency_check='0'
199 |
200 | # FROM HERE ON, CODE SHOULD BE LEFT UNTOUCHED!
201 | function abort {
202 | echo "${1}" >&2
203 | exit 1
204 | }
205 |
206 | function url_exists {
207 | curl --silent --location --output /dev/null --fail --range 0-0 "${1}"
208 | }
209 |
210 | function notification {
211 | local -r notificator="$(find . -type d -name 'Notificator.app')"
212 | if [[ -n "${notificator}" ]]; then
213 | "${notificator}/Contents/Resources/Scripts/notificator" --message "${1}" --title "${alfred_workflow_name}" --subtitle 'A new version is available'
214 | return
215 | fi
216 |
217 | local -r terminal_notifier="$(find . -type f -name 'terminal-notifier')"
218 | if [[ -n "${terminal_notifier}" ]]; then
219 | "${terminal_notifier}" -title "${alfred_workflow_name}" -subtitle 'A new version is available' -message "${1}"
220 | return
221 | fi
222 |
223 | osascript -e "display notification \"${1}\" with title \"${alfred_workflow_name}\" subtitle \"A new version is available\""
224 | }
225 |
226 | # Local sanity checks
227 | readonly local_info_plist='info.plist'
228 | readonly local_version="$(/usr/libexec/PlistBuddy -c 'print version' "${local_info_plist}")"
229 |
230 | [[ -n "${local_version}" ]] || abort 'You need to set a workflow version in the configuration sheet.'
231 | [[ "${download_type}" =~ ^(direct|page|github_release)$ ]] || abort "'download_type' (${download_type}) needs to be one of 'direct', 'page', or 'github_release'."
232 | [[ "${frequency_check}" =~ ^[0-9]+$ ]] || abort "'frequency_check' (${frequency_check}) needs to be a number."
233 |
234 | # Check for updates
235 | if [[ $(find "${local_info_plist}" -mtime +"${frequency_check}"d) ]]; then
236 | if ! url_exists "${remote_info_plist}"; then abort "'remote_info_plist' (${remote_info_plist}) appears to not be reachable."; fi # Remote sanity check
237 |
238 | readonly tmp_file="$(mktemp)"
239 | curl --silent --location --output "${tmp_file}" "${remote_info_plist}"
240 | readonly remote_version="$(/usr/libexec/PlistBuddy -c 'print version' "${tmp_file}")"
241 |
242 | if [[ "${local_version}" == "${remote_version}" ]]; then
243 | touch "${local_info_plist}" # Reset timer by touching local file
244 | exit 0
245 | fi
246 |
247 | if [[ "${download_type}" == 'page' ]]; then
248 | notification 'Opening download page…'
249 | open "${workflow_url}"
250 | exit 0
251 | fi
252 |
253 | download_url="$([[ "${download_type}" == 'github_release' ]] && curl --silent "https://api.github.com/repos/${workflow_url}/releases/latest" | grep 'browser_download_url' | head -1 | sed -E 's/.*browser_download_url": "(.*)"/\1/' || echo "${workflow_url}")"
254 |
255 | if url_exists "${download_url}"; then
256 | notification 'Downloading and installing…'
257 | curl --silent --location --output "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow" "${download_url}"
258 | open "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow"
259 | else
260 | abort "'workflow_url' (${download_url}) appears to not be reachable."
261 | fi
262 | fi
263 | scriptargtype
264 | 1
265 | scriptfile
266 |
267 | type
268 | 0
269 |
270 | type
271 | alfred.workflow.action.script
272 | uid
273 | F1304401-205F-426B-914D-E8AA5A2BFB82
274 | version
275 | 2
276 |
277 |
278 | readme
279 |
280 | uidata
281 |
282 | 0F635C4D-EF27-4E06-BDF4-1898EE3039AB
283 |
284 | xpos
285 | 10
286 | ypos
287 | 10
288 |
289 | 1BB1CD87-F91F-4887-9F8A-A99F2E730262
290 |
291 | xpos
292 | 225
293 | ypos
294 | 10
295 |
296 | 28180B02-C512-4E2F-BA05-E28A7C05E1A7
297 |
298 | xpos
299 | 160
300 | ypos
301 | 40
302 |
303 | E8058394-1462-41B7-A91D-909B07A34AF2
304 |
305 | xpos
306 | 390
307 | ypos
308 | 10
309 |
310 | F1304401-205F-426B-914D-E8AA5A2BFB82
311 |
312 | colorindex
313 | 12
314 | note
315 | OneUpdater
316 | xpos
317 | 230
318 | ypos
319 | 155
320 |
321 |
322 | variablesdontexport
323 |
324 | version
325 | 1.5.0
326 | webaddress
327 | https://github.com/ResonantConcepts/podlink-alfred
328 |
329 |
330 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Nathan Gathright (nathangathright.com)
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "podlink-alfred",
3 | "version": "1.5.0",
4 | "description": "Search for podcasts from Alfred",
5 | "license": "MIT",
6 | "repository": "ResonantConcepts/podlink-alfred",
7 | "author": {
8 | "name": "Nathan Gathright",
9 | "email": "nathan.gathright@gmail.com",
10 | "url": "https://nathangathright.com"
11 | },
12 | "engines": {
13 | "node": ">=4"
14 | },
15 | "scripts": {
16 | "purge": "rm media/*"
17 | },
18 | "keywords": [
19 | "alfred",
20 | "workflow",
21 | "alfy"
22 | ],
23 | "dependencies": {
24 | "alfy": "^0.10.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Podcast Search for Alfred
2 |
3 | Search for podcasts from Alfred (powered by [pod.link](https://pod.link/))
4 |
5 | 
6 |
7 | ## Installation
8 | **Download and install the latest release**
9 |
10 | _You will need the [Alfred Powerpack](https://www.alfredapp.com/powerpack/) to enable this workflow._
11 |
12 | ## Usage
13 | 1. Type the keyword `pod` followed by your query to generate results.
14 | 2. Press ⌘ + C to copy the pod.link URL of the selected show to you clipboard.
15 | 3. Select a podcast to reveal a list of supported platforms.
16 | 4. Select your preferred platform or type its name to filter the list.
17 | * Press Return to open the selected result in your browser.
18 | * Press ⌘ + C to copy the URL of the selected result to your clipboard.
19 |
20 | ## Supported Platforms
21 | Alfred learns and will sort the results based on usage. Here’s the list of platforms currently supported:
22 |
23 | 
24 | 
25 | 
26 | 
27 | 
28 | 
29 | 
30 | 
31 | 
32 | 
33 | 
34 | 
35 | 
36 | 
37 |
38 |
39 | ## Limitations
40 | * If a podcast is not listed in the Apple Podcasts directory, it will not appear in search results.
41 | * All podcasts are not necessarily available on all platforms. If pod.link cannot find a match on an platform, the link will redirect back to the pod.link page for that podcast.
42 |
43 | ## Credits
44 | * Hat tip to [Chris Messina](https://twitter.com/chrismessina) for the nudge to create this
45 | * Built with [alfy](https://github.com/sindresorhus/alfy) via [generator-alfred](https://github.com/SamVerschueren/generator-alfred)
46 |
47 | ## License
48 |
49 | MIT © [Nathan Gathright](https://github.com/nathangathright)
50 |
--------------------------------------------------------------------------------