-
Notifications
You must be signed in to change notification settings - Fork 1k
/
NightShift.swift
119 lines (98 loc) · 4.1 KB
/
NightShift.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//
// NightShift.swift
// Aerial
//
// Created by Guillaume Louel on 19/12/2019.
// Copyright © 2019 Guillaume Louel. All rights reserved.
//
import Foundation
struct NightShift {
static var isNightShiftDataCached = false
static var nightShiftAvailable = false
static var nightShiftSunrise = Date()
static var nightShiftSunset = Date()
// MARK: Night Shift
static func isAvailable() -> (Bool, reason: String) {
if #available(OSX 10.12.4, *) {
let (isAvailable, sunriseDate, sunsetDate, errorMessage) = NightShift.getInformation()
if isAvailable {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "j:mm:ss", options: 0, locale: Locale.current)
let sunriseString = dateFormatter.string(from: sunriseDate!)
let sunsetString = dateFormatter.string(from: sunsetDate!)
return (true, "Today’s sunrise: " + sunriseString + " Today’s sunset: " + sunsetString)
} else {
isNightShiftDataCached = true
return (false, errorMessage!)
}
} else {
return (false, "macOS 10.12.4 or above is required")
}
}
// swiftlint:disable:next large_tuple
static func getInformation() -> (Bool, sunrise: Date?, sunset: Date?, error: String?) {
// Sonoma workaround
if !Aerial.helper.underCompanion {
if #available(macOS 14.0, *) {
if CompanionBridge.nightShiftSunrise != nil {
debugLog("Nightshift using CompanionBridge data")
return (true, CompanionBridge.nightShiftSunrise, CompanionBridge.nightShiftSunset, nil)
} else {
return (false, nil, nil, "Sonoma requires Aerial Companion")
}
}
}
if isNightShiftDataCached {
return (nightShiftAvailable, nightShiftSunrise, nightShiftSunset, nil)
}
// On Catalina, corebrightnessdiag was moved to /usr/libexec/ !
var cbdpath = "/usr/bin/corebrightnessdiag"
if #available(OSX 10.15, *) {
cbdpath = "/usr/libexec/corebrightnessdiag"
}
let (nsInfo, ts) = Aerial.helper.shell(launchPath: cbdpath, arguments: ["nightshift-internal"])
if ts != 0 {
// Task didn't return correctly ? Abort
return (false, nil, nil, "Your Mac does not support Night Shift")
}
let lines = nsInfo?.split(separator: "\n")
if lines!.count < 5 {
// We get a couple of lines of output on unsupported Macs
return (false, nil, nil, "Your Mac does not support Night Shift")
}
var sunrise: Date?, sunset: Date?
for line in lines ?? [""] {
if line.contains("sunrise") {
if let gdate = getDateFromLine(String(line)) {
sunrise = gdate
}
} else if line.contains("sunset") {
if let gdate = getDateFromLine(String(line)) {
sunset = gdate
}
}
}
if sunset != nil && sunrise != nil {
nightShiftSunrise = sunrise!
nightShiftSunset = sunset!
nightShiftAvailable = true
isNightShiftDataCached = true
return (true, sunrise, sunset, nil)
}
// /usr/bin/corebrightnessdiag nightshift-internal | grep nextSunset | cut -d \" -f2
warnLog("Location services may be disabled, Night Shift can't detect Sunrise and Sunset times without them")
return (false, nil, nil, "Location services may be disabled")
}
// Helpers
private static func getDateFromLine(_ line: String) -> Date? {
let tmp = line.split(separator: "\"")
if tmp.count > 1 {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
if let dateObj = dateFormatter.date(from: String(tmp[1])) {
return dateObj
}
}
return nil
}
}