-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from Pandoks/sleep-consistency
Sleep consistency
- Loading branch information
Showing
4 changed files
with
243 additions
and
167 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,173 +1,21 @@ | ||
local schedule = hs.json.read("./hammer-control/schedule.json") | ||
local days = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" } | ||
hs.application.enableSpotlightForNameSearches(true) | ||
local selfcontrol = require("hammer-control/selfcontrol") | ||
local time = require("hammer-control/time") | ||
|
||
-- initiate time | ||
local DAY, TIME | ||
local function getTime() | ||
local url = "http://worldtimeapi.org/api/ip" | ||
local status, body = hs.http.get(url) | ||
|
||
if status == 200 then | ||
local json = hs.json.decode(body) | ||
|
||
DAY = days[json.day_of_week + 1] | ||
local hour, minute = json.datetime:match("T(%d%d):(%d%d):") | ||
TIME = hour .. ":" .. minute | ||
else | ||
DAY = string.lower(os.date("%A")) | ||
TIME = os.date("%H:%M") | ||
end | ||
end | ||
getTime() | ||
|
||
local function incrementTime() | ||
if string.match(TIME, "23:59") then | ||
local day_index | ||
for index, value in ipairs(days) do | ||
if string.match(DAY, value) then | ||
day_index = index | ||
end | ||
end | ||
if day_index == 7 then | ||
DAY = days[1] -- reminder that lua has cancer indexing starting at 1 | ||
else | ||
DAY = days[day_index + 1] | ||
end | ||
TIME = "00:00" | ||
else | ||
local hour, minute = string.match(TIME, "(%d%d):(%d%d)") | ||
hour, minute = tonumber(hour), tonumber(minute) | ||
minute = minute + 1 | ||
if minute == 60 then | ||
minute = 0 | ||
hour = hour + 1 | ||
end | ||
TIME = string.format("%02d:%02d", hour, minute) | ||
-- system event tracker | ||
SYSTEM_WATCHER = hs.caffeinate.watcher.new(function(event_type) | ||
if event_type == hs.caffeinate.watcher.screensDidUnlock then | ||
time.getTime() | ||
selfcontrol.start() | ||
SELFCONTROL_TIMER:start() | ||
end | ||
end | ||
|
||
-- initiate system sleep tracker | ||
local sleep_watcher = hs.caffeinate.watcher.new(function(event_type) | ||
if event_type == hs.caffeinate.watcher.systemDidWake then | ||
getTime() -- reset time after wake | ||
if event_type == hs.caffeinate.watcher.screensDidLock then | ||
SELFCONTROL_TIMER:stop() | ||
end | ||
end) | ||
sleep_watcher:start() | ||
|
||
local function convertToMinute(time_string) | ||
local hour, minute = string.match(time_string, "(%d%d):(%d%d)") | ||
if not hour or not minute then | ||
error("Time format is incorrect. Needs two digits for both hour and minute: 01:00 not 1:00") | ||
end | ||
return tonumber(hour) * 60 + tonumber(minute) | ||
end | ||
|
||
local function compareTime(time1, time2) | ||
-- equivalencies: | ||
-- compareTime(time1, time2) > 0 === time1 > time2 | ||
-- compareTime(time1, time2) <= 0 === time1 <= time2 | ||
-- etc | ||
|
||
local minutes1 = convertToMinute(time1) | ||
local minutes2 = convertToMinute(time2) | ||
|
||
if minutes1 < minutes2 then | ||
return -1 | ||
elseif minutes1 == minutes2 then | ||
return 0 | ||
else | ||
return 1 | ||
end | ||
end | ||
|
||
local function selfControl() | ||
incrementTime() | ||
local output = | ||
hs.execute("/Applications/SelfControl.app/Contents/MacOS/selfcontrol-cli is-running 2>&1") | ||
if string.match(output, "YES") then | ||
return | ||
end | ||
|
||
local block | ||
for _, timeblock in pairs(schedule[DAY]) do | ||
local start_time = timeblock["start"] | ||
local end_time = timeblock["end"] | ||
|
||
if compareTime(TIME, end_time) >= 0 then | ||
goto continue | ||
end | ||
if compareTime(TIME, start_time) >= 0 then | ||
block = timeblock | ||
break | ||
end | ||
|
||
::continue:: | ||
end | ||
if block == nil then | ||
return | ||
end | ||
|
||
local block_time = convertToMinute(block["end"]) - convertToMinute(TIME) | ||
if block_time < 0 then | ||
return | ||
end | ||
local end_time = os.date("!%Y-%m-%dT%H:%M:%SZ", os.time(os.date("*t")) + block_time * 60) | ||
|
||
local selfcontrol_command = "/Applications/SelfControl.app/Contents/MacOS/selfcontrol-cli" | ||
local block_file = hs.fs.pathToAbsolute(block["blocklist"]) | ||
local selfcontrol_arguments = { | ||
"start", | ||
"--enddate", | ||
end_time, | ||
"--blocklist", | ||
block_file, | ||
} | ||
|
||
local startSelfControl | ||
local function selfcontrol_callback(exit_code, _, std_error) | ||
if exit_code == 0 then | ||
print("SelfControl started") | ||
elseif string.match(std_error, "Blocklist is empty, or block does not end in the future") then | ||
local block_file_attributes = hs.fs.attributes(block_file) | ||
if not (block_file_attributes and block_file_attributes["mode"] == "file") then | ||
error("Blocklist file " .. block_file .. " does not exist or has an error") | ||
else | ||
error("End date ends in the past") | ||
end | ||
elseif string.match(std_error, "Block is already running") then | ||
error("SelfControl is already running") | ||
elseif string.match(std_error, "Authorization cancelled") then | ||
print("User tried to cancel. Restarting...") | ||
startSelfControl() | ||
end | ||
end | ||
|
||
startSelfControl = function() | ||
local selfcontrol_task = | ||
hs.task.new(selfcontrol_command, selfcontrol_callback, selfcontrol_arguments) | ||
if not selfcontrol_task:start() then | ||
error("Couldn't start SelfControl task") | ||
return | ||
end | ||
|
||
local prompt_timer | ||
prompt_timer = hs.timer.doEvery(0.1, function() | ||
local security_prompt = hs.application.get("SecurityAgent") | ||
if security_prompt then | ||
local password = | ||
hs.execute("security find-generic-password -a $(whoami) -s hammer-control -w") | ||
security_prompt:activate(true) | ||
hs.eventtap.keyStrokes(password) | ||
hs.eventtap.keyStroke({}, "return") | ||
hs.alert.show("SelfControl started") | ||
prompt_timer:stop() | ||
return | ||
end | ||
end) | ||
end | ||
startSelfControl() | ||
end | ||
SYSTEM_WATCHER:start() | ||
|
||
selfControl() | ||
local selfcontrol_timer = hs.timer.new(60, selfControl) | ||
selfcontrol_timer:start() | ||
selfcontrol.start() | ||
SELFCONTROL_TIMER = hs.timer.new(60, selfcontrol.run) | ||
SELFCONTROL_TIMER:start() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
local time = require("hammer-control/time") | ||
|
||
local M = {} | ||
local BLOCK_FILE = "" | ||
|
||
local function isSelfControlRunning() | ||
local output = | ||
hs.execute("/Applications/SelfControl.app/Contents/MacOS/selfcontrol-cli is-running 2>&1") | ||
return string.match(output, "YES") | ||
end | ||
|
||
local function insertPassword() | ||
local prompt_timer | ||
prompt_timer = hs.timer.new(0.1, function() | ||
local security_prompt = hs.application.get("SecurityAgent") | ||
if security_prompt then | ||
local password = | ||
hs.execute("security find-generic-password -a $(whoami) -s hammer-control -w") | ||
|
||
security_prompt:activate(true) | ||
local front_app = hs.application.frontmostApplication() | ||
while not (front_app and front_app:name() == "SecurityAgent") do | ||
security_prompt:activate(true) | ||
front_app = hs.application.frontmostApplication() | ||
end | ||
hs.eventtap.keyStrokes(password) | ||
hs.eventtap.keyStroke({}, "return") | ||
|
||
if isSelfControlRunning() then | ||
prompt_timer:stop() | ||
return | ||
end | ||
end | ||
end) | ||
prompt_timer:start() | ||
end | ||
|
||
local function selfControlCallback(exit_code, _, std_error) | ||
if exit_code == 0 then | ||
print("SelfControl started") | ||
hs.alert.show("SelfControl started", 2) | ||
elseif string.match(std_error, "Blocklist is empty, or block does not end in the future") then | ||
local block_file_attributes = hs.fs.attributes(BLOCK_FILE) | ||
if not (block_file_attributes and block_file_attributes["mode"] == "file") then | ||
error("Blocklist file " .. BLOCK_FILE .. " does not exist") | ||
else | ||
error("End date ends in the past") | ||
end | ||
elseif string.match(std_error, "Blocklist could not be read from file") then | ||
error("Blocklist file " .. BLOCK_FILE .. " has an error in it. Save the blocklist again.") | ||
elseif string.match(std_error, "Block is already running") then | ||
error("SelfControl is already running") | ||
elseif string.match(std_error, "Authorization cancelled") then | ||
print("User tried to cancel. Restarting...") | ||
M.start() | ||
end | ||
end | ||
|
||
function M.start() | ||
if isSelfControlRunning() then | ||
return | ||
end | ||
|
||
local schedule = time.getSchedule() | ||
if not (schedule and schedule.end_time and schedule.blocklist) then | ||
return | ||
end | ||
|
||
local end_time = schedule.end_time | ||
BLOCK_FILE = schedule.blocklist | ||
if not (end_time and BLOCK_FILE) then | ||
return | ||
end | ||
|
||
local selfcontrol_command = "/Applications/SelfControl.app/Contents/MacOS/selfcontrol-cli" | ||
local selfcontrol_arguments = { | ||
"start", | ||
"--enddate", | ||
end_time, | ||
"--blocklist", | ||
hs.fs.pathToAbsolute(BLOCK_FILE), | ||
} | ||
|
||
local selfcontrol_task = | ||
hs.task.new(selfcontrol_command, selfControlCallback, selfcontrol_arguments) | ||
if not selfcontrol_task:start() then | ||
error("Couldn't start SelfControl task") | ||
return | ||
end | ||
|
||
insertPassword() | ||
end | ||
|
||
function M.run() | ||
time.incrementTime() | ||
M.start() | ||
end | ||
|
||
return M |
Oops, something went wrong.