Files
Home-of-CS/content/post/dev_20251223_2/install(with_dock_icon).sh
T
2026-04-23 13:39:28 +08:00

198 lines
5.8 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
username=$(whoami)
script_dir=$(dirname "$0")
cd $script_dir
echo "==Tesuto Alarm Dec 2025(By Cirrus)安装程序=="
echo "当前用户: $username"
echo "当前目录: $script_dir"
echo ""
echo "检测程序是否正在运行:"
if launchctl list | grep -q cn.org.cirrus.tesutoalarmdec2025;then
echo "在运行,先终止进程,再安装。"
echo ""
launchctl stop cn.org.cirrus.tesutoalarmdec2025
launchctl unload /Users/$username/Library/LaunchAgents/cn.org.cirrus.tesutoalarmdec2025.plist
echo ""
echo "继续安装。"
else
echo "不在运行,继续安装。"
fi
echo ""
echo "提示:程序文件默认保存目录:"
echo "二进制文件:${script_dir}/tesuto"
echo "STDOUT目录:${script_dir}/tesuto.log"
echo "STDERR目录:${script_dir}/tesuto.error.log"
echo "注意:请勿重命名、移动、修改、删除。"
echo ""
echo "请输入声音文件的绝对路径:(直接回车表示$script_dir/sound.mp3"
read sound
if [ "$sound" == "" ];then
sound="${script_dir}/sound.mp3"
fi
echo "注意:为保证程序运行正常,请保持该文件在原目录,且未重命名。"
echo ""
echo "请输入闹铃JSON文件的保存文件夹目录:(以“/”结尾,请勿加上alarms.json"
echo "(直接回车表示$script_dir/"
read jsonpath
if [ "$jsonpath" == "" ];then
jsonpath="${script_dir}/"
fi
cat > ${jsonpath}alarms.json << EOF
[
{
"name": "Test1",
"hour": 8,
"minute": 45,
"triggered": false
},
{
"name": "Test2",
"hour": 9,
"minute": 41,
"triggered": false
}
]
EOF
cat > ./tesuto.swift << EOF
import UniformTypeIdentifiers
import SwiftUI
import Combine
class Alarm: Codable, ObservableObject
{
let name: String
let hour: Int
let minute: Int
var triggered: Bool
}
let app = NSApplication.shared
NSApp.setActivationPolicy(.regular)
let sound = NSSound(contentsOf: URL(fileURLWithPath: ("$sound" as NSString).expandingTildeInPath), byReference: false)
if sound != nil
{
print("\(Date()): 读取声音文件成功")
print("尝试播放:(2秒后停止)")
fflush(stdout)
sound?.play()
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
{
sound?.stop()
}
}
else
{
print("\(Date()): 读取声音文件失败")
fflush(stdout)
}
var alarms: [Alarm] = []
func readJSON(url: URL) -> Bool
{
do
{
let json = try Data(contentsOf: url)
let loadedData = try JSONDecoder().decode([Alarm].self, from: json)
alarms = loadedData
print("\(Date()): 读取JSON成功")
print("闹钟数据:")
for alarm in alarms
{
print("\n名称:\(alarm.name)")
print("时间:\(alarm.hour):\(alarm.minute)")
}
fflush(stdout)
return true
}
catch
{
print("\(Date()): 读取JSON失败(\(error))")
fflush(stdout)
return false
}
}
func perform(for alarm: Alarm)
{
let window = NSAlert()
window.messageText = "闹钟提醒"
window.informativeText = "\(alarm.name) - \(alarm.hour):\(alarm.minute)"
window.addButton(withTitle: "关闭\(alarm.name)")
print("\(Date()): 触发\(alarm.name) - \(alarm.hour):\(alarm.minute)")
fflush(stdout)
sound?.play()
Task
{
try await Task.sleep(nanoseconds: 1 * 60 * 1_000_000_000)
sound?.stop()
print("\(Date()): 超时自动关闭\(alarm.name) - \(alarm.hour):\(alarm.minute)")
fflush(stdout)
return
}
window.runModal()
sound?.stop()
print("\(Date()): 手动关闭\(alarm.name) - \(alarm.hour):\(alarm.minute)")
fflush(stdout)
}
let timer = Timer.publish(every: 1, on: .main, in: .default).autoconnect()
var cancellables = Set<AnyCancellable>()
_ = readJSON(url: URL(fileURLWithPath: ("${jsonpath}alarms.json" as NSString).expandingTildeInPath))
timer.sink
{
_ in
let now = Date()
let calendar = Calendar.current
let currentSecond = calendar.component(.second, from: now)
if currentSecond < 3
{
let currentHour = calendar.component(.hour, from: now)
let currentMinute = calendar.component(.minute, from: now)
for alarm in alarms
{
if alarm.hour == currentHour && alarm.minute == currentMinute && !alarm.triggered
{
perform(for: alarm)
alarm.triggered.toggle()
DispatchQueue.main.asyncAfter(deadline: .now() + 5)
{
alarm.triggered.toggle()
print("\(Date()): 清除\(alarm.name)的triggered标识")
fflush(stdout)
}
}
}
}
}
.store(in: &cancellables)
RunLoop.current.run()
EOF
swiftc tesuto.swift
cat > ./cn.org.cirrus.tesutoalarmdec2025.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>cn.org.cirrus.tesutoalarmdec2025</string>
<key>ProgramArguments</key>
<array>
<string>${script_dir}/tesuto</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>${script_dir}/tesuto.log</string>
<key>StandardErrorPath</key>
<string>${script_dir}/tesuto.error.log</string>
</dict>
</plist>
EOF
cp ./cn.org.cirrus.tesutoalarmdec2025.plist /Users/$username/Library/LaunchAgents/cn.org.cirrus.tesutoalarmdec2025.plist
launchctl load /Users/$username/Library/LaunchAgents/cn.org.cirrus.tesutoalarmdec2025.plist
echo ""
echo "如果听到您指定音频文件的开头2秒,则表明程序安装完成。"
echo "详见cirrus.log。"
echo "更改时区代码较为麻烦,故请您将就看,把每个时间的小时数+8即可。"