Last active
October 25, 2020 08:45
-
-
Save schoeffm/fe6a7bdf9af159f6877917c5a51b11aa to your computer and use it in GitHub Desktop.
Scriptable approach to have a HuffDuffIt-ShareSheet entry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: orange; icon-glyph: headphones; | |
// share-sheet-inputs: url; | |
// this script is supposed to be used as an action-extension | |
if (! config.runsInActionExtension && ! config.runsInApp) { | |
await warn('No Arguments given', | |
'This script can only be used as an Action-Extension where a URL is passed down to it'); | |
Script.complete(); | |
} | |
// take the url which were passed to the script | |
let url = (args.urls.length > 0) ? args.urls[0] : 'https://changelog.com' | |
// load the page and find all sound-file references in there | |
const info = await extractStreamInfosFrom(url); | |
let selection; | |
if (info.episodes.length > 1) { | |
// in case there are more than one file referenced in the page ... show a selection dialo | |
let listWidget = await createSelectionTable(info); | |
await listWidget.present(false); | |
// once the user selected one entry ... huffduff that entry | |
await huffduffit(selection.title, selection.episode); | |
} else if (info.episodes.length === 1) { | |
// we there was only one episode-reference contained in the page ... directly huffduff it | |
await huffduffit(info.title, info.episodes[0]); | |
} else { | |
// if there was no sound-file at all ... tell the user | |
await warn('No Audio File Found', | |
`Apparently there\'s no suitable audio file contained in the given web-page ${url}`); | |
} | |
Script.complete(); | |
/** | |
* Takes the given url (as a string) and fetches the content of the respective page. | |
* After that, it'll look for all kinds of sound files (mp3, m4a, ogg, oga, opus) and | |
* extracts the URL-references to that files. Along with that sound-file-references | |
* the method is looking for some kind of title (basically a h1-tag) and tries at least | |
* to extract that as well (in order to make a title-suggestion). | |
*/ | |
async function extractStreamInfosFrom(url) { | |
let req = new Request(url); | |
let content = await req.loadString(); | |
let titleExp = new RegExp(/<h1.*>\s*(.*)\s*<.*h1>/g); | |
let titleMatches = titleExp.exec(content); | |
let title = (titleMatches) ? titleMatches[1].trim() : ''; | |
let streams = content.match(/https?:\/\/.*?\.(mp3|opus|oga|ogg|m4a)/g) | |
if(streams) { | |
streams = streams | |
.filter((a, b) => streams.indexOf(a) === b); | |
return { title, episodes: streams } | |
} else { | |
return { title, episodes: [] } | |
} | |
} | |
/** | |
* A quick and simple table-view where the user can pick one of the given items. | |
* Notice: I had some strange behavior with the `onSelect`-handler. I wasn't able to | |
* directly trigger the `huffduffit`-WebView from that callback. Hence, I | |
* now set a global variable which is used after the UITable-View was | |
* dismissed. That works | |
*/ | |
async function createSelectionTable(item) { | |
let table = new UITable(); | |
for (episode of item.episodes) { | |
let row = new UITableRow(); | |
let episodeCell = row.addText((episode.indexOf('/') > 0) | |
? episode.substring(episode.lastIndexOf('/') + 1) | |
: episode); | |
row.height = 60 | |
row.cellSpacing = 10 | |
row.dismissOnSelect = true; | |
row.onSelect = (idx) => selection = { title: item.title, episode }; | |
table.addRow(row); | |
} | |
return table; | |
} | |
/** | |
* The actual call to huffduff a file ... it actually only calls the add-huffduff | |
* popup in order to reuse auth-info stored in the browser | |
*/ | |
async function huffduffit(title, url) { | |
let webView = new WebView(); | |
await webView.loadURL(`https://huffduffer.com/add?popup=true&bookmark[url]=${url}&bookmark[title]=${encodeURI(title)}`); | |
return webView.present(false); | |
} | |
/** | |
* Small helper to show a warning-notification | |
*/ | |
async function warn(title, message) { | |
let nothingFoundAlert = new Alert(); | |
nothingFoundAlert.title = title; | |
nothingFoundAlert.message = message; | |
return nothingFoundAlert.presentAlert(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment