init
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# bark-notify
|
||||||
|
|
||||||
|
向手机发送 **Bark 通知** 的 Python 模块,覆盖全部通知类型与参数。uv 管理环境,**零第三方依赖**(仅标准库)。
|
||||||
|
|
||||||
|
- 服务器:标准 Bark 服务(`Server: Bark`),默认 `http://47.108.226.213:10086`,可用 `BARK_BASE_URL` 覆盖。
|
||||||
|
- 设备密钥:默认 `pvd3kWwHNFjKXNjiC2sMe7`,可用 `BARK_DEVICE_KEY` 覆盖。
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd bark-notify
|
||||||
|
uv sync # 创建 .venv 并以可编辑方式安装本项目
|
||||||
|
uv run bark-notify --help # 验证 CLI 可用
|
||||||
|
```
|
||||||
|
|
||||||
|
## 命令行用法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基础通知
|
||||||
|
uv run bark-notify "标题" "正文"
|
||||||
|
|
||||||
|
# 各级别(default / active / timeSensitive / critical / passive)
|
||||||
|
uv run bark-notify "紧急" "服务器告警" --level critical --sound alarm.caf --volume 10
|
||||||
|
uv run bark-notify "勿扰也提醒" "会议还有 5 分钟" --level timeSensitive
|
||||||
|
uv run bark-notify "只进通知中心" "静默内容" --level passive
|
||||||
|
|
||||||
|
# 特殊功能
|
||||||
|
uv run bark-notify "Markdown" "### 标题\n- 项1\n- 项2" # 正文原生支持 Markdown
|
||||||
|
uv run bark-notify "分组" "第1条" --group 演示
|
||||||
|
uv run bark-notify "跳转" "点击打开百度" --url https://www.baidu.com
|
||||||
|
uv run bark-notify "复制" "长按复制此文本" --copy "OPC 云超服"
|
||||||
|
uv run bark-notify "带图" "附带图片" --image https://picsum.photos/seed/x/400/300
|
||||||
|
uv run bark-notify "角标" "数字角标" --badge 5 --ttl 60
|
||||||
|
```
|
||||||
|
|
||||||
|
## Python API
|
||||||
|
|
||||||
|
```python
|
||||||
|
from bark_notify import BarkClient, Level, Notification, Sound
|
||||||
|
|
||||||
|
client = BarkClient() # 也可 BarkClient(base_url=..., device_key=...)
|
||||||
|
|
||||||
|
client.push(Notification(
|
||||||
|
title="部署完成",
|
||||||
|
body="**v2.4.0** 已上线 ✅",
|
||||||
|
level=Level.ACTIVE,
|
||||||
|
group="部署",
|
||||||
|
url="https://example.com/status",
|
||||||
|
))
|
||||||
|
|
||||||
|
# GET 快捷方式(适合快速测试,参数走查询串)
|
||||||
|
client.notify("测试", "正文", level="critical", group="x")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参数一览
|
||||||
|
|
||||||
|
| 参数 | CLI | 说明 |
|
||||||
|
|------|-----|------|
|
||||||
|
| `title` / `body` | 位置参数 | 标题 / 正文(正文支持 Markdown) |
|
||||||
|
| `level` | `--level` | `default` `active` `timeSensitive` `critical` `passive` |
|
||||||
|
| `sound` | `--sound` | 内置铃声名或远程铃声 URL |
|
||||||
|
| `badge` | `--badge` | 应用角标数字 |
|
||||||
|
| `group` | `--group` | 同组通知折叠 |
|
||||||
|
| `icon` | `--icon` | 通知图标 URL |
|
||||||
|
| `image` | `--image` | 附带图片 URL |
|
||||||
|
| `copy` | `--copy` | 长按复制的文本 |
|
||||||
|
| `url` | `--url` | 点击跳转 URL |
|
||||||
|
| `is_archive` | `--archive` | 存入历史记录 |
|
||||||
|
| `call` | `--call` | 连续响铃(呼叫声) |
|
||||||
|
| `ttl` | `--ttl` | 过期秒数,超时自动删除 |
|
||||||
|
| `volume` | `--volume` | critical 通知音量 0-10 |
|
||||||
|
|
||||||
|
## 级别差异速查
|
||||||
|
|
||||||
|
| 级别 | 横幅 | 声音 | 勿扰可送达 | 说明 |
|
||||||
|
|------|:----:|:----:|:---------:|------|
|
||||||
|
| `default` | ✅ | ✅ | ❌ | 跟随系统 |
|
||||||
|
| `active` | ✅ | ✅ | ❌ | 标准活跃通知 |
|
||||||
|
| `timeSensitive` | ✅ | ✅ | ✅ | 时效性 |
|
||||||
|
| `critical` | ✅ | ✅ | ✅ | 绕过静音强制响铃,需授权 |
|
||||||
|
| `passive` | ❌ | ❌ | — | 仅通知中心 |
|
||||||
|
|
||||||
|
## 内置铃声
|
||||||
|
|
||||||
|
`alarm.caf` `alarms.caf` `anticipate.caf` `bell.caf` `bloom.caf` `calypso.caf` `chime.caf` `choir.caf` `complete.caf` `completion.caf` `electronic.caf` `emergency.caf` `fanfare.caf` `glass.caf` `goblin.caf` `healthnotification.caf` `horn.caf` `ladders.caf` `mario.caf` `minuet.caf` `multiwayinvitation.caf` `newmail.caf` `newsflash.caf` `noir.caf` `payment.caf` `shake.caf` `sherwoodfanfare.caf` `silence.caf` `spell.caf` `suspense.caf` `telegraph.caf` `tiptoes.caf` `typewriters.caf` `update.caf`
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
| 变量 | 默认值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `BARK_BASE_URL` | `http://47.108.226.213:10086` | 服务器地址 |
|
||||||
|
| `BARK_DEVICE_KEY` | `pvd3kWwHNFjKXNjiC2sMe7` | 设备密钥 |
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
"""发送全部类型的 Bark 通知,用于在手机上逐项核对效果。
|
||||||
|
|
||||||
|
用法::
|
||||||
|
|
||||||
|
uv run python examples/send_all_types.py
|
||||||
|
|
||||||
|
可选参数:
|
||||||
|
|
||||||
|
--skip active critical 跳过部分级别
|
||||||
|
--device-key <key> 指定设备密钥
|
||||||
|
--base-url <url> 指定服务器地址
|
||||||
|
|
||||||
|
每发一条会在终端打印进度,手机端请对照标题核对。
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import time
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from bark_notify import BarkClient, Level, Notification
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: Optional[List[str]] = None) -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="发送全部类型的 Bark 通知")
|
||||||
|
parser.add_argument(
|
||||||
|
"--skip",
|
||||||
|
nargs="*",
|
||||||
|
choices=[level.value for level in Level],
|
||||||
|
default=[],
|
||||||
|
help="要跳过的级别(可多个)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--device-key", help="Bark 设备密钥")
|
||||||
|
parser.add_argument("--base-url", help="Bark 服务器地址")
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
client = BarkClient(base_url=args.base_url, device_key=args.device_key)
|
||||||
|
|
||||||
|
# 第一波:五种级别,逐项核对打扰程度差异
|
||||||
|
cases = [
|
||||||
|
("基础通知(default)", Level.DEFAULT, {}),
|
||||||
|
("活跃通知(active)", Level.ACTIVE, {}),
|
||||||
|
("时效性通知(timeSensitive)", Level.TIME_SENSITIVE, {}),
|
||||||
|
("紧急通知(critical)", Level.CRITICAL, {"sound": "alarm.caf", "volume": 10}),
|
||||||
|
("静默通知(passive)", Level.PASSIVE, {}),
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, (title, level, extra) in enumerate(cases, start=1):
|
||||||
|
if level.value in args.skip:
|
||||||
|
print(f"[{i}/{len(cases)}] 跳过 {level.value}")
|
||||||
|
continue
|
||||||
|
notification = Notification(
|
||||||
|
title=f"[{i}] {title}",
|
||||||
|
body=f"级别: {level.value}\n由 examples/send_all_types.py 发送",
|
||||||
|
level=level,
|
||||||
|
**extra,
|
||||||
|
)
|
||||||
|
client.push(notification)
|
||||||
|
print(f"[{i}/{len(cases)}] 已发送 {level.value}")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# 第二波:特殊功能
|
||||||
|
features = [
|
||||||
|
("[6] Markdown 富文本", "### 任务清单\n- [x] 发基础通知\n- [x] 发特殊通知\n- [ ] 核对效果\n\n**加粗** 与 *斜体* 测试 ✅", {}),
|
||||||
|
("[7] 自定义铃声", "使用 bells 铃声,不同于默认铃声。", {"sound": "bell.caf"}),
|
||||||
|
("[8] 分组折叠", "属于「演示分组」组,下一条同组。", {"group": "演示分组"}),
|
||||||
|
("[9] 分组折叠", "属于「演示分组」组,会与上一条折叠。", {"group": "演示分组"}),
|
||||||
|
("[10] 跳转链接", "点击这条会打开百度。", {"url": "https://www.baidu.com"}),
|
||||||
|
("[11] 复制文本", "长按这条可复制「OPC 云超服」。", {"copy": "OPC 云超服"}),
|
||||||
|
("[12] 带图片", "附带一张示例图片,需设备可加载外网图。", {"image": "https://picsum.photos/seed/bark/400/300"}),
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, (title, body, extra) in enumerate(features, start=6):
|
||||||
|
notification = Notification(title=title, body=body, **extra)
|
||||||
|
client.push(notification)
|
||||||
|
print(f"[{i}] 已发送 {title}")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
print("全部发送完成,请到手机端核对。")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[project]
|
||||||
|
name = "bark-notify"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "向手机发送 Bark 通知的 Python 模块,覆盖全部通知类型与参数(uv 管理)"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
bark-notify = "bark_notify.cli:main"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["src/bark_notify"]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
"""bark_notify — 向手机发送 Bark 通知,覆盖全部通知类型与参数。
|
||||||
|
|
||||||
|
用法示例::
|
||||||
|
|
||||||
|
from bark_notify import BarkClient, Level, Notification
|
||||||
|
|
||||||
|
client = BarkClient()
|
||||||
|
client.push(Notification(title="你好", body="世界", level=Level.CRITICAL, sound="alarm.caf"))
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .client import BarkClient, BarkError
|
||||||
|
from .types import Level, Notification, Sound
|
||||||
|
|
||||||
|
__version__ = "0.1.0"
|
||||||
|
__all__ = ["BarkClient", "BarkError", "Level", "Notification", "Sound"]
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
"""bark-notify 命令行入口。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from .client import BarkClient, BarkError
|
||||||
|
from .types import Level, Notification
|
||||||
|
|
||||||
|
|
||||||
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="bark-notify",
|
||||||
|
description="向手机发送 Bark 通知,覆盖全部通知类型与参数",
|
||||||
|
)
|
||||||
|
parser.add_argument("title", help="通知标题")
|
||||||
|
parser.add_argument("body", nargs="?", default="", help="通知正文(支持 Markdown)")
|
||||||
|
parser.add_argument("--subtitle", help="副标题")
|
||||||
|
parser.add_argument(
|
||||||
|
"--level",
|
||||||
|
choices=[level.value for level in Level],
|
||||||
|
default=Level.DEFAULT.value,
|
||||||
|
help="通知级别(默认 default)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--sound", help="铃声名(如 alarm.caf)或远程铃声 URL")
|
||||||
|
parser.add_argument("--badge", type=int, help="应用角标数字")
|
||||||
|
parser.add_argument("--group", help="分组名:同名通知折叠显示")
|
||||||
|
parser.add_argument("--icon", help="通知图标 URL")
|
||||||
|
parser.add_argument("--image", help="附带图片 URL")
|
||||||
|
parser.add_argument("--copy", help="长按通知复制的文本")
|
||||||
|
parser.add_argument("--url", help="点击通知跳转的 URL")
|
||||||
|
parser.add_argument("--archive", action="store_true", help="存入历史记录")
|
||||||
|
parser.add_argument("--call", action="store_true", help="连续响铃提醒(呼叫声)")
|
||||||
|
parser.add_argument("--ttl", type=int, help="过期时间(秒)")
|
||||||
|
parser.add_argument("--volume", type=int, choices=range(0, 11), help="关键通知音量 0-10")
|
||||||
|
parser.add_argument("--device-key", help="Bark 设备密钥(默认读 BARK_DEVICE_KEY)")
|
||||||
|
parser.add_argument("--base-url", help="Bark 服务器地址(默认读 BARK_BASE_URL)")
|
||||||
|
parser.add_argument("--json", dest="raw_json", action="store_true", help="输出服务器原始 JSON")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: Optional[List[str]] = None) -> int:
|
||||||
|
args = build_parser().parse_args(argv)
|
||||||
|
|
||||||
|
client_kwargs = {}
|
||||||
|
if args.base_url:
|
||||||
|
client_kwargs["base_url"] = args.base_url
|
||||||
|
if args.device_key:
|
||||||
|
client_kwargs["device_key"] = args.device_key
|
||||||
|
client = BarkClient(**client_kwargs)
|
||||||
|
|
||||||
|
notification = Notification(
|
||||||
|
title=args.title,
|
||||||
|
body=args.body,
|
||||||
|
subtitle=args.subtitle,
|
||||||
|
level=Level(args.level),
|
||||||
|
sound=args.sound,
|
||||||
|
badge=args.badge,
|
||||||
|
group=args.group,
|
||||||
|
icon=args.icon,
|
||||||
|
image=args.image,
|
||||||
|
copy=args.copy,
|
||||||
|
url=args.url,
|
||||||
|
is_archive=args.archive,
|
||||||
|
call=args.call,
|
||||||
|
ttl=args.ttl,
|
||||||
|
volume=args.volume,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = client.push(notification)
|
||||||
|
except BarkError as exc:
|
||||||
|
print(f"发送失败: {exc}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if args.raw_json:
|
||||||
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
|
else:
|
||||||
|
print(f"发送成功: {result.get('message')}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
"""Bark 推送客户端:基于标准 Bark 服务器 HTTP API,零第三方依赖。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from typing import Any, Dict, Optional, Union
|
||||||
|
|
||||||
|
from .types import Level, Notification, Sound
|
||||||
|
|
||||||
|
DEFAULT_BASE_URL = os.environ.get("BARK_BASE_URL", "http://47.108.226.213:10086")
|
||||||
|
DEFAULT_DEVICE_KEY = os.environ.get("BARK_DEVICE_KEY", "pvd3kWwHNFjKXNjiC2sMe7")
|
||||||
|
|
||||||
|
|
||||||
|
class BarkError(RuntimeError):
|
||||||
|
"""Bark 服务器返回失败或网络异常。"""
|
||||||
|
|
||||||
|
|
||||||
|
def _value_of(value: Union[Level, Sound, str, None]) -> Optional[str]:
|
||||||
|
"""枚举成员取其值,普通字符串原样返回。"""
|
||||||
|
if isinstance(value, (Level, Sound)):
|
||||||
|
return value.value
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_query(params: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""把 Python 值转成 GET 查询参数可接受的类型。"""
|
||||||
|
out: Dict[str, Any] = {}
|
||||||
|
for key, value in params.items():
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if isinstance(value, bool):
|
||||||
|
out[key] = "true" if value else "false"
|
||||||
|
else:
|
||||||
|
out[key] = _value_of(value)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
class BarkClient:
|
||||||
|
"""Bark 通知客户端。
|
||||||
|
|
||||||
|
支持两种推送方式:
|
||||||
|
|
||||||
|
- :meth:`push`:通过 ``POST /push`` 发送,支持全部参数(推荐)。
|
||||||
|
- :meth:`notify`:通过 ``GET /<key>/<title>/<body>`` 发送,适合快速测试。
|
||||||
|
|
||||||
|
地址与密钥默认从环境变量读取,也可在构造时显式传入:
|
||||||
|
|
||||||
|
- ``BARK_BASE_URL``:服务器地址,默认 ``http://47.108.226.213:10086``。
|
||||||
|
- ``BARK_DEVICE_KEY``:设备密钥。
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
base_url: Optional[str] = None,
|
||||||
|
device_key: Optional[str] = None,
|
||||||
|
timeout: float = 10.0,
|
||||||
|
) -> None:
|
||||||
|
self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
|
||||||
|
self.device_key = device_key or DEFAULT_DEVICE_KEY
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
def push(self, notification: Notification) -> Dict[str, Any]:
|
||||||
|
"""通过 ``POST /push`` 推送一条完整通知,返回服务器 JSON 响应。"""
|
||||||
|
payload = self._payload(notification)
|
||||||
|
payload["device_key"] = self.device_key
|
||||||
|
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||||
|
return self._request("/push", data=data)
|
||||||
|
|
||||||
|
def notify(self, title: str, body: str = "", **kwargs: Any) -> Dict[str, Any]:
|
||||||
|
"""GET 快捷推送:``/<key>/<title>/<body>?<params>``。
|
||||||
|
|
||||||
|
``kwargs`` 中除 ``title/body`` 外的键会转成查询参数,
|
||||||
|
布尔值转 ``true/false``,例如 ``level="critical"``、``group="x"``。
|
||||||
|
"""
|
||||||
|
encoded_title = urllib.parse.quote(title)
|
||||||
|
encoded_body = urllib.parse.quote(body)
|
||||||
|
path = f"/{self.device_key}/{encoded_title}/{encoded_body}"
|
||||||
|
params = _normalize_query(kwargs)
|
||||||
|
params.pop("title", None)
|
||||||
|
params.pop("body", None)
|
||||||
|
if params:
|
||||||
|
path += "?" + urllib.parse.urlencode(params)
|
||||||
|
return self._request(path)
|
||||||
|
|
||||||
|
# ---------- 内部工具 ----------
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _payload(notification: Notification) -> Dict[str, Any]:
|
||||||
|
"""把 Notification 转成 POST /push 的 JSON body(camelCase 键)。"""
|
||||||
|
payload: Dict[str, Any] = {
|
||||||
|
"title": notification.title,
|
||||||
|
"body": notification.body,
|
||||||
|
"level": _value_of(notification.level) or Level.DEFAULT.value,
|
||||||
|
}
|
||||||
|
optional: Dict[str, Any] = {
|
||||||
|
"subtitle": notification.subtitle,
|
||||||
|
"sound": _value_of(notification.sound),
|
||||||
|
"badge": notification.badge,
|
||||||
|
"group": notification.group,
|
||||||
|
"icon": notification.icon,
|
||||||
|
"image": notification.image,
|
||||||
|
"copy": notification.copy,
|
||||||
|
"url": notification.url,
|
||||||
|
"isArchive": notification.is_archive,
|
||||||
|
"call": notification.call,
|
||||||
|
"ttl": notification.ttl,
|
||||||
|
"volume": notification.volume,
|
||||||
|
}
|
||||||
|
for key, value in optional.items():
|
||||||
|
if value is not None:
|
||||||
|
payload[key] = value
|
||||||
|
return payload
|
||||||
|
|
||||||
|
def _request(self, path: str, data: Optional[bytes] = None) -> Dict[str, Any]:
|
||||||
|
url = self.base_url + path
|
||||||
|
req = urllib.request.Request(url, data=data)
|
||||||
|
if data is not None:
|
||||||
|
req.add_header("Content-Type", "application/json")
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
||||||
|
raw = resp.read().decode("utf-8")
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
raw = exc.read().decode("utf-8", errors="replace")
|
||||||
|
except urllib.error.URLError as exc:
|
||||||
|
raise BarkError(f"网络错误: {exc}") from exc
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = json.loads(raw)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
result = {"code": -1, "message": raw.strip()}
|
||||||
|
if result.get("code") != 200:
|
||||||
|
raise BarkError(f"Bark 返回异常: code={result.get('code')} message={result.get('message')}")
|
||||||
|
return result
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
"""Bark 通知的类型定义:级别枚举、铃声枚举与通知数据类。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import enum
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Level(enum.Enum):
|
||||||
|
"""通知级别:决定在 iOS 上的打扰程度。"""
|
||||||
|
|
||||||
|
DEFAULT = "default"
|
||||||
|
#: 跟随系统默认设置,标准横幅 + 默认铃声。
|
||||||
|
ACTIVE = "active"
|
||||||
|
#: 标准活跃通知。
|
||||||
|
TIME_SENSITIVE = "timeSensitive"
|
||||||
|
#: 时效性通知:即使开启勿扰模式也能送达。
|
||||||
|
CRITICAL = "critical"
|
||||||
|
#: 关键通知:绕过静音/勿扰开关,强制响铃(需设备授权此应用)。
|
||||||
|
PASSIVE = "passive"
|
||||||
|
#: 被动通知:仅进通知中心,无横幅、无声音。
|
||||||
|
|
||||||
|
|
||||||
|
class Sound(enum.Enum):
|
||||||
|
"""Bark 内置铃声(也可直接传自定义远程铃声 URL)。"""
|
||||||
|
|
||||||
|
DEFAULT = "default"
|
||||||
|
ALARM = "alarm.caf"
|
||||||
|
ALARMS = "alarms.caf"
|
||||||
|
ANTICIPATE = "anticipate.caf"
|
||||||
|
BELL = "bell.caf"
|
||||||
|
BLOOM = "bloom.caf"
|
||||||
|
CALYPSO = "calypso.caf"
|
||||||
|
CHIME = "chime.caf"
|
||||||
|
CHOIR = "choir.caf"
|
||||||
|
COMPLETE = "complete.caf"
|
||||||
|
COMPLETION = "completion.caf"
|
||||||
|
ELECTRONIC = "electronic.caf"
|
||||||
|
EMERGENCY = "emergency.caf"
|
||||||
|
FANFARE = "fanfare.caf"
|
||||||
|
GLASS = "glass.caf"
|
||||||
|
GOBLIN = "goblin.caf"
|
||||||
|
HEALTH_NOTIFICATION = "healthnotification.caf"
|
||||||
|
HORN = "horn.caf"
|
||||||
|
LADDERS = "ladders.caf"
|
||||||
|
MARIO = "mario.caf"
|
||||||
|
MINUET = "minuet.caf"
|
||||||
|
MULTIWAY_INVITATION = "multiwayinvitation.caf"
|
||||||
|
NEW_MAIL = "newmail.caf"
|
||||||
|
NEWS_FLASH = "newsflash.caf"
|
||||||
|
NOIR = "noir.caf"
|
||||||
|
PAYMENT = "payment.caf"
|
||||||
|
SHAKE = "shake.caf"
|
||||||
|
SHERWOOD_FANFARE = "sherwoodfanfare.caf"
|
||||||
|
SILENCE = "silence.caf"
|
||||||
|
SPELL = "spell.caf"
|
||||||
|
SUSPENSE = "suspense.caf"
|
||||||
|
TELEGRAPH = "telegraph.caf"
|
||||||
|
TIPTOES = "tiptoes.caf"
|
||||||
|
TYPEWRITERS = "typewriters.caf"
|
||||||
|
UPDATE = "update.caf"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Notification:
|
||||||
|
"""一条完整的 Bark 通知,覆盖服务器支持的全部参数。"""
|
||||||
|
|
||||||
|
title: str
|
||||||
|
body: str = ""
|
||||||
|
#: 副标题。
|
||||||
|
subtitle: Optional[str] = None
|
||||||
|
#: 通知级别,默认 ``Level.DEFAULT``。
|
||||||
|
level: Level = Level.DEFAULT
|
||||||
|
#: 铃声名(如 ``alarm.caf``)或远程铃声 URL。
|
||||||
|
sound: Optional[str] = None
|
||||||
|
#: 应用角标数字。
|
||||||
|
badge: Optional[int] = None
|
||||||
|
#: 分组名:同名的通知会在通知中心折叠成一组。
|
||||||
|
group: Optional[str] = None
|
||||||
|
#: 通知图标 URL。
|
||||||
|
icon: Optional[str] = None
|
||||||
|
#: 通知附带的图片 URL。
|
||||||
|
image: Optional[str] = None
|
||||||
|
#: 长按通知时复制的文本。
|
||||||
|
copy: Optional[str] = None
|
||||||
|
#: 点击通知跳转的 URL。
|
||||||
|
url: Optional[str] = None
|
||||||
|
#: 是否存入 Bark 历史记录。
|
||||||
|
is_archive: bool = False
|
||||||
|
#: 是否连续响铃提醒(呼叫声)。
|
||||||
|
call: bool = False
|
||||||
|
#: 过期时间(秒),超时后通知自动删除。
|
||||||
|
ttl: Optional[int] = None
|
||||||
|
#: 关键通知的音量(0-10),需要 critical 级别。
|
||||||
|
volume: Optional[int] = None
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bark-notify"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
Reference in New Issue
Block a user