Last active
December 1, 2017 05:49
-
-
Save happyjake/b29e6be289c72ecf7a9965b98a3baa3a to your computer and use it in GitHub Desktop.
use hammerspoon to quick add current page link to evernote
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
local apps = {} | |
-- App-specific code, runs when you launch or switch to another app | |
local App = {} | |
App.new = function(name) | |
log.d('new App for ',name) | |
local self = {} | |
self.name = name | |
self.bindings = {} | |
self.onActivateFn = nil | |
self.onDeactivateFn = nil | |
self.onLaunchedFn = nil | |
self.onTerminatedFn = nil | |
self.bind = function(hotkey, predicate) | |
table.insert(self.bindings, {key = hotkey, | |
predicate = predicate}) | |
return self | |
end | |
self.onActivate = function(fn) | |
self.onActivateFn = fn | |
return self | |
end | |
self.onDeactivate = function(fn) | |
self.onDeactivateFn = fn | |
return self | |
end | |
self.onLaunched = function(fn) | |
self.onLaunchedFn = fn | |
local app = hs.application.find(self.name) | |
if app then | |
self.launch(app) | |
if app:isFrontmost() then | |
self.activate(app) | |
end | |
end | |
return self | |
end | |
self.onTerminated = function(fn) | |
self.onTerminatedFn = fn | |
return self | |
end | |
self.activate = function(appObject) | |
--log.d('activate',appObject) | |
if type(self.onActivateFn) == 'function' then | |
self:onActivateFn(appObject) | |
end | |
self:enableBinds() | |
end | |
self.deactivate = function(appObject) | |
if type(self.onDeactivateFn) == 'function' then | |
self:onDeactivateFn(appObject) | |
end | |
self:disableBinds() | |
end | |
self.launch = function(appObject) | |
if type(self.onLaunchedFn) == 'function' then | |
self:onLaunchedFn(appObject) | |
end | |
end | |
self.terminate = function(appObject) | |
if type(self.onTerminatedFn) == 'function' then | |
self:onTerminatedFn(appObject) | |
end | |
self:disableBinds() | |
end | |
self.enableBinds = function(self) | |
--log.d('enableBinds',hs.inspect(self.bindings)) | |
hs.fnutils.each(self.bindings, function(b) | |
if b.predicate and not b.predicate() then | |
b.key:disable() | |
else | |
b.key:enable() | |
end | |
end) | |
end | |
self.disableBinds = function(self) | |
hs.fnutils.each(self.bindings, function(b) | |
if b and b.key then | |
b.key:disable() | |
end | |
end) | |
end | |
self.clearBinds = function(self) | |
log.d('clearBinds for ',hs.inspect(self)) | |
self:disableBinds() | |
self.bindings = {} | |
end | |
apps[name] = self | |
return self | |
end | |
function invoke(keys, predicate) | |
return function () | |
if predicate and not predicate() then | |
return | |
end | |
if type(keys) == 'table' then | |
hs.fnutils.each(keys, function (key) | |
if type(key) ~= 'table' then | |
key = {{}, key} | |
end | |
hs.eventtap.keyStroke(key[1], key[2]) | |
end) | |
elseif type(keys) == 'string' then | |
os.execute(keys) | |
elseif type(keys) == 'function' then | |
return keys() | |
end | |
end | |
end | |
-- | |
function appGlobalWatcher(appName, eventType, appObject) | |
--log.d('appGlobalWatcher',appName,eventType,appObject) | |
if apps[appName] then | |
if (eventType == hs.application.watcher.activated) then | |
apps[appName].activate(appObject) | |
elseif (eventType == hs.application.watcher.deactivated) then | |
apps[appName].deactivate(appObject) | |
elseif (eventType == hs.application.watcher.launched) then | |
apps[appName].launch(appObject) | |
elseif (eventType == hs.application.watcher.terminated) then | |
apps[appName].terminate(appObject) | |
end | |
end | |
end | |
App.appWatcher = hs.application.watcher.new(appGlobalWatcher):start() | |
log.d('App.appWatcher assign') | |
return App |
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
-- for evernote | |
-- | |
local module = {} | |
local appName = 'Evernote' | |
local App = require('App') | |
local app = App.new(appName) | |
local util = require('util') | |
local network = require('network') | |
local executeAppleScript = util.executeAppleScript | |
module.lastActivated = 0 | |
module.activateInterval = 10 | |
app.onActivate(function(appObject) | |
log.d('sync evernote') | |
-- sync if connected to internet | |
if network.isInternetReachable() then | |
hs.eventtap.keyStroke({'cmd','ctrl'}, 's') | |
end | |
-- focus on search if not active for a while | |
-- if os.time() - module.lastActivated > module.activateInterval then | |
-- module.lastActivated = os.time() | |
-- hs.eventtap.keyStroke({'cmd','alt'}, 'f') | |
-- end | |
end) | |
module.copyLink = function(notebookName,noteTitle,isPrepend) | |
local isOK, output, message = hs.osascript.javascript([[ | |
ObjC.import('AppKit'); | |
function run(argv) { | |
var res = {}; | |
getWebLink(res); | |
if (res.hasOwnProperty('title') && res.hasOwnProperty('url')) { | |
copyToClipboard(res); | |
//return res.title + ' - ' + res.url; | |
//return res.title; | |
return JSON.stringify(res); | |
} | |
return 'Failed!'; | |
} | |
function getWebLink(res) { | |
const frontmost_app_name = Application('System Events').applicationProcesses.where({ frontmost: true }).name()[0] | |
const frontmost_app = Application(frontmost_app_name) | |
if (['Google Chrome','Google Chrome Canary','Chromium','Vivaldi'].indexOf(frontmost_app_name) > -1) { | |
res.title = frontmost_app.windows[0].activeTab.name() | |
res.url = frontmost_app.windows[0].activeTab.url() | |
} else if (['Safari','Safari Technology Preview','Webkit'].indexOf(frontmost_app_name) > -1) { | |
res.title = frontmost_app.documents[0].name() | |
res.url = frontmost_app.documents[0].url() | |
} else { | |
throw new Error('You need a supported browser as your frontmost app') | |
} | |
} | |
function copyToClipboard(res) { | |
var pb = $.NSPasteboard.generalPasteboard; | |
var str1 = $.NSString.alloc.initWithUTF8String('<a href="' + res.url + '">' + res.title +'</a>'); | |
var str2 = $.NSString.alloc.initWithUTF8String('[' + res.title + '](' + res.url + ')'); | |
var str3 = $.NSString.alloc.initWithUTF8String('{\\rtf1\\ansi\deff0{\\field{\\*\\fldinst{HYPERLINK "' + res.url + '"}}{\\fldrslt ' + res.title + '}}}'); | |
pb.clearContents; | |
pb.setStringForType(str1, $.NSPasteboardTypeHTML); | |
pb.setStringForType(str2, $.NSPasteboardTypeString); | |
pb.setStringForType(str3, $.NSPasteboardTypeRTF); | |
} | |
]]) | |
if isOK then | |
local res = hs.json.decode(output) | |
-- hs.application(appName):activate() | |
local html = string.format([[set html1 to "<li><a href=\"%s\">%s</a> - "]] ,res.url ,util.html_escape(res.title)) .. [[& (do shell script "LANG=zh_CN.UTF-8 date") & "</li>" | |
]] | |
local as = html .. [[ | |
tell application "Evernote" | |
synchronize | |
set isPrepend to ]].. tostring(isPrepend) .. [[ | |
set notebookName to "]].. notebookName .. [[" | |
if (not (notebook named notebookName exists)) then | |
set notebook1 to create notebook notebookName | |
end if | |
set notebook1 to notebook notebookName | |
set noteTitle to "]].. noteTitle ..[[ " | |
set theNotes to find notes "notebook:\"" & notebookName & "\" intitle:\"" & noteTitle & "\"" | |
if length of theNotes is 0 then | |
create note with html html1 title noteTitle notebook notebook1 | |
else | |
set theNote to first item of theNotes | |
-- tell theNote to append html html1 | |
tell theNote | |
if isPrepend then | |
set noteHTML to html1 & (HTML content of item 1 of theNote) | |
set (HTML content of item 1 of theNote) to noteHTML | |
else | |
set noteHTML to (HTML content of item 1 of theNote) & html1 | |
set (HTML content of item 1 of theNote) to noteHTML | |
end if | |
end tell | |
end if | |
end | |
]] | |
executeAppleScript(as, "prepend to evernote") | |
hs.alert.show("\"".. res.title .."\" copied to ".. noteTitle) | |
else | |
hs.alert.show(message['NSLocalizedDescription']) | |
log.d(hs.inspect.inspect(message)) | |
end | |
end | |
-- cmd + f to search for notes | |
app.bind(hs.hotkey.new({'cmd'}, 'f', function() | |
hs.application(appName):selectMenuItem("Search Notes...") | |
end)) | |
-- cmd + shift + f to search in current note | |
app.bind(hs.hotkey.new({'cmd', 'shift'}, 'f', function() | |
hs.application(appName):selectMenuItem("Find Within Note...") | |
end)) | |
-- esc to not focus on search | |
app.bind(hs.hotkey.new({}, 'escape', 'esc', function() | |
if util.menuEnabled(hs.application(appName),'Paste') then | |
hs.application(appName):selectMenuItem("Select Note List") | |
end | |
end)) | |
-- lost focus for search on deactive | |
app.onDeactivate(function() | |
if util.menuEnabled(hs.application(appName),'Paste') then | |
hs.application(appName):selectMenuItem("Select Note List") | |
end | |
end) | |
return module |
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
local util = require("util") | |
local network = {} | |
network.internetReachWatcher = hs.network.reachability.internet() | |
network.onInternetConnected = function (event) end | |
network.onInternetDisconnected = function (event) end | |
network.internetReachWatcher:setCallback(function(watcher, flags) | |
-- log.d("internet reachability changed: ", flags, watcher.statusString()) | |
if (flags & hs.network.reachability.flags.reachable) > 0 then | |
-- a default route exists, so an active internet connection is present | |
hs.alert.show("internet connected") | |
network.onInternetConnected(flags) | |
else | |
-- no default route exists, so no active internet connection is present | |
hs.alert.show("internet Disconnected") | |
network.onInternetDisconnected(flags) | |
end | |
end):start() | |
network.isInternetReachable = function() | |
return (network.internetReachWatcher:status() & hs.network.reachability.flags.reachable) > 0 | |
end | |
return network |
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
local module = {} | |
-- strings | |
module.startsWith = function(String,Start) | |
return string.sub(String,1,string.len(Start))==Start end | |
module.endsWith = function(String,End) | |
return End=='' or string.sub(String,-string.len(End))==End | |
end | |
-- table fn | |
module.reduce = function(t,init,fn) | |
return hs.fnutils.reduce(hs.fnutils.concat({init},t),function(a,b) return fn(a,b) end) | |
end | |
module.count = function(t) | |
local count = 0 | |
hs.fnutils.each(t,function() count = count + 1 end) | |
return count | |
end | |
module.urlencode = function(str) | |
if (str) then | |
str = string.gsub (str, "\n", "\r\n") | |
str = string.gsub (str, "([^%w ])", | |
function (c) return string.format ("%%%02X", string.byte(c)) end) | |
str = string.gsub (str, " ", "+") | |
end | |
return str | |
end | |
module.html_escape = function (s) | |
assert("Expected string in argument #1.") | |
return (string.gsub(s, "[}{\">/<'&]", { | |
["&"] = "&", | |
["<"] = "<", | |
[">"] = ">", | |
['"'] = """, | |
["'"] = "'", | |
["/"] = "/" | |
})) | |
end | |
-- | |
module.selectWifi = function(ssid) | |
local cmd = [[ | |
tell application "System Events" | |
tell process "SystemUIServer" | |
click (menu bar item 1 of menu bar 1 whose description contains "Wi-Fi") | |
click menu item "%s" of menu 1 of result | |
end tell | |
end tell]] | |
return hs.osascript.applescript(string.format(cmd,ssid)) | |
end | |
-- | |
module.moveFile = function(from,to) | |
return os.rename(from,to) | |
end | |
module.parentDir = function(str,sep) | |
sep=sep or'/' | |
return str:match("(.*"..sep..")") | |
end | |
module.filename = function(str) | |
return str:match("^.+/(.+)$") | |
end | |
module.fileext = function(str) | |
return str:match("^.+(%..+)$") | |
end | |
module.killApp = function(appName) | |
local app = hs.application.find(appName) | |
if not app then | |
return | |
end | |
app:kill() | |
end | |
module.launchApp = function(appName) | |
hs.application.open(appName) | |
end | |
module.launchAppIfNotRunning = function(appName) | |
local app = hs.application.find(appName) | |
if app and app:isRunning() then | |
return | |
end | |
hs.application.open(appName) | |
end | |
module.menuEnabled = function(app,menuName) | |
local item = app:findMenuItem(menuName) | |
return item and item.enabled | |
end | |
module.showApps = function() | |
hs.fnutils.each(hs.application.runningApplications(), function(app) print(app:bundleID(), app:title()) end) | |
end | |
-- osascript to tell an application to do something | |
module.applescriptTell = function(app, appCmd) | |
local cmd = 'tell application "'..app..'" to '..appCmd | |
local ok, result = hs.applescript(cmd) | |
if ok and result == nil then result = true end | |
if not ok then result = nil end | |
return result | |
end | |
-- Execute the given apple script and logs any errors. The context will be added | |
-- to the log. | |
-- Returns: The output of the apple script if successful, nil otherwise | |
module.executeAppleScript = function(script, context) | |
successful, output, errDesc = hs.osascript.applescript(script) | |
if not successful then | |
msg = string.format("Failed to execute AppleScript (%s)", context) | |
hs.alert(msg) | |
log:e(msg) | |
log:e(string.format("Script:\n%s", script)) | |
log:e(string.format("Error:\n%s", hs.inspect(errDesc))) | |
return nil | |
end | |
return output | |
end | |
-- get the current URL of the focused browser window | |
module.getFocusedBrowserURL = function() | |
-- values for this table are either applescript strings to pass to | |
-- lib.tell(), or functions to be called. In either case, the return | |
-- value should be the URL of the frontmost window/tab. | |
local browsers = { | |
['Google Chrome'] = 'URL of active tab of front window', | |
Safari = 'URL of front document', | |
} | |
local url = nil | |
local app = hs.application.frontmostApplication() | |
local title = app:title() | |
if browsers[title] ~= nil then | |
if type(browsers[title]) == 'string' then | |
url = module.applescriptTell(title, browsers[title]) | |
elseif type(browsers[title] == 'function') then | |
url = browsers[title]() | |
end | |
end | |
return url | |
end | |
module.openUrl = function(url) | |
return hs.urlevent.openURLWithBundle(url, '') | |
end | |
module.waitUntil = function(predicateFn, actionFn, failFn,checkInterval, maxTryCount) | |
local tryCount = 0 | |
local timer = hs.timer.waitUntil(function() | |
tryCount = tryCount + 1 | |
if tryCount > maxTryCount then | |
return true | |
end | |
return predicateFn() | |
end, function(tm) | |
if tryCount > maxTryCount then | |
if failFn then | |
return failFn(tm) | |
else | |
return | |
end | |
end | |
return actionFn(tm) | |
end, checkInterval) | |
return timer | |
end | |
-- Focus the last used window. | |
module.focusLastFocused = function() | |
local wf = hs.window.filter | |
local lastFocused = wf.defaultCurrentSpace:getWindows(wf.sortByFocusedLast) | |
if #lastFocused > 0 then lastFocused[1]:focus() end | |
end | |
return module | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment