Skip to content

Commit f40b2d9

Browse files
committed
Add Safari extension support
1 parent b400bd1 commit f40b2d9

18 files changed

Lines changed: 167 additions & 97 deletions

.env.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
# code; non-prefixed vars are silently ignored.
44

55
# ---------------------------------------------------------------------------
6-
# REQUIREDbuild fails fast if missing.
6+
# OPTIONALonly needed for reverse proxy video mode and zen music.
77
#
88
# Macify CDN base URL. Single host that serves both:
99
# - GET <BASE>/itunes-assets/... → reverse proxy to sylvan.apple.com
1010
# - GET <BASE>/music/musicNNNNN.mp3 → R2 bucket of zen-mode music
1111
#
12+
# Leave this unset for the Safari self-use build. The extension defaults to
13+
# direct Apple streaming from https://sylvan.apple.com with no local videos.
14+
#
1215
# Set up: deploy cloudflare-worker/worker.js to a Worker route on
1316
# <BASE>/itunes-assets/*, and bind your music R2 bucket to <BASE>.
1417
# No trailing slash.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ dist/
1111
releases/
1212
*.zip
1313

14+
# Generated by `xcrun safari-web-extension-packager`; contains local signing settings.
15+
Macify - Gorgeous Aerial Videos as Your New Tab/
16+
1417
# Private AI context (per-machine, not for the public repo)
1518
local-context.md
1619
CLAUDE.md

README.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# Macify — macOS Aerial Screensavers in Chrome's New Tab
1+
# Macify — macOS Aerial Screensavers in Safari or Chrome's New Tab
22

33
![GitHub Repo stars](https://img.shields.io/github/stars/jason5ng32/macOS-Screen-Saver-as-Chrome-New-Tab)
44
![GitHub](https://img.shields.io/github/license/jason5ng32/macOS-Screen-Saver-as-Chrome-New-Tab)
55
![Chrome Web Store Version](https://img.shields.io/chrome-web-store/v/lgdipcalomggcjkohjhkhkbcpgladnoe)
66
![GitHub contributors](https://img.shields.io/github/contributors/jason5ng32/macOS-Screen-Saver-as-Chrome-New-Tab)
77

8-
Replace Chrome's new tab page with macOS's aerial screensaver videos and a small set of calm, optional widgets. macOS is **not** required — videos are streamed from Apple's CDN and play in any platform that runs Chrome.
8+
Replace Safari or Chrome's new tab page with macOS's aerial screensaver videos and a small set of calm, optional widgets. macOS is **not** required — videos are streamed from Apple's CDN.
99

1010
![screenshot](docs/screenshot.png)
1111

1212
## Features
1313

1414
- 🎥 **156 aerial videos** in 4K SDR, sourced from Apple's current macOS catalog (Landscapes, Cities, Underwater, Space, and more).
1515
- 🌤️ **Live weather** — current temperature, "feels like", 3-day forecast, sunrise/sunset, UV, wind, air quality. Powered by [Open-Meteo](https://open-meteo.com/), no API key required.
16-
- 📌 **Top sites** widget pulled from Chrome's built-in list (no history permission needed).
16+
- 📌 **Top sites** widget pulled from the browser's built-in list when available (no history permission needed).
1717
- 💬 **Random quotes** from a curated 500-entry public-domain set.
1818
- 🧘 **Zen mode** — fullscreen the video with optional ambient music.
1919
- 🔤 **4 languages** — English, 简体中文, 繁體中文, 日本語.
@@ -22,19 +22,19 @@ Replace Chrome's new tab page with macOS's aerial screensaver videos and a small
2222

2323
[Install from Chrome Web Store](https://chromewebstore.google.com/detail/macify-macos-screensaver/lgdipcalomggcjkohjhkhkbcpgladnoe).
2424

25-
Or load unpacked: see [Building from source](#building-from-source).
25+
Or load unpacked: see [Building from source](#building-from-source). For a local Safari build, see [SAFARI.md](SAFARI.md).
2626

2727
## Choosing a video source
2828

2929
Three options. Each section in the extension's settings page also includes a built-in step-by-step setup guide — this README only summarises.
3030

3131
### 1. Apple Server (default)
3232

33-
Streams directly from `sylvan.apple.com`. Chrome may not trust Apple's certificate by default; two ways to fix it:
33+
Streams directly from `sylvan.apple.com`. If direct video playback fails, two fallback paths are available:
3434

35-
**Option A — Reverse proxy (default on, easiest).** Video requests are routed through a hosted Cloudflare Worker that handles the certificate dance. Zero local setup. Convenient but should not be relied on long-term — set up local hosting or trust the cert when possible.
35+
**Option A — Reverse proxy.** Video requests are routed through your own Cloudflare Worker. Convenient, but it requires a CDN host you control.
3636

37-
**Option B — Trust Apple's cert manually (cleanest).** Visit [https://sylvan.apple.com](https://sylvan.apple.com) once in Chrome. You'll see a security warning — click "Advanced", then "Proceed to sylvan.apple.com (unsafe)". Chrome remembers the trust and direct connection works thereafter.
37+
**Option B — Trust Apple's cert manually.** Visit [https://sylvan.apple.com](https://sylvan.apple.com) once in the target browser. If you see a security warning, use the browser's advanced option to proceed. The browser should remember that trust.
3838

3939
![Chrome warning when trusting sylvan.apple.com](docs/chromewarnning.jpg)
4040

@@ -84,21 +84,20 @@ In Macify settings, switch the source to **Local server** and confirm the URL is
8484

8585
## Permissions
8686

87-
Macify requests three permissions, all non-sensitive:
87+
Macify requests two permissions, both non-sensitive:
8888

8989
| Permission | Used for |
9090
|---|---|
9191
| `storage` | Persist user preferences and cache weather data. |
92-
| `topSites` | Read Chrome's most-visited list for the Top Sites widget. |
93-
| `favicon` | Show favicons next to Top Sites entries (uses Chrome's built-in cache; no external network). |
92+
| `topSites` | Read the browser's most-visited list for the Top Sites widget when supported. |
9493

9594
No `history` permission. No host permissions for arbitrary sites.
9695

9796
## Building from source
9897

9998
Requirements: Node.js 20+ and npm.
10099

101-
The build is **not zero-config** — Macify needs a CDN you control for the Apple aerial reverse proxy and the zen-mode music. The published Chrome Store build uses my own infrastructure; if you fork, you bring your own. The build refuses to run without these set.
100+
The default self-use build is zero-config: it streams directly from Apple and does not require a CDN. A CDN is only needed for the optional Apple aerial reverse proxy and zen-mode music.
102101

103102
### 1. Stand up your CDN host
104103

@@ -134,13 +133,13 @@ Skip this if you don't care — the worker still works.
134133
git clone https://github.com/jason5ng32/macOS-Screen-Saver-as-Chrome-New-Tab.git
135134
cd macOS-Screen-Saver-as-Chrome-New-Tab
136135
cp .env.example .env
137-
# edit .env — fill in VITE_MACIFY_BASE (required)
136+
# edit .env only if you want VITE_MACIFY_BASE for proxy/music
138137
# and VITE_APPLE_PROXY_KEY (only if you set up the WAF rule above)
139138
npm install
140139
npm run build
141140
```
142141

143-
If `.env` is missing or incomplete the build aborts with a list of what's missing. See [`.env.example`](.env.example) for the full reference.
142+
See [`.env.example`](.env.example) for the full optional environment reference.
144143

145144
### 3. Load the extension
146145

SAFARI.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Safari self-use build
2+
3+
This fork defaults to direct Apple streaming for Safari:
4+
5+
- video source: Apple Server
6+
- reverse proxy: off
7+
- local video server: not required
8+
- zen music: off unless `VITE_MACIFY_BASE` is configured
9+
10+
The video playlist still points at Apple's `https://sylvan.apple.com` aerial
11+
assets. Nothing needs to be downloaded locally.
12+
13+
## Build
14+
15+
```bash
16+
npm install
17+
npm run build:safari
18+
```
19+
20+
The extension bundle is written to `dist/`.
21+
22+
## Package for Safari
23+
24+
Install full Xcode first. Apple's Safari converter is not included with the
25+
Command Line Tools-only install.
26+
27+
```bash
28+
npm run package:safari
29+
```
30+
31+
Open the generated Xcode project, sign it for local development, run the app,
32+
then enable the extension in Safari settings.
33+
34+
## Optional proxy
35+
36+
If direct Apple playback fails in Safari, set up your own Cloudflare Worker
37+
using `cloudflare-worker/worker.js`, set `VITE_MACIFY_BASE`, rebuild, and turn
38+
on "Use reverse proxy" in the extension settings.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
"name": "macify",
33
"version": "2.0.0-dev",
44
"private": true,
5-
"description": "Transform Chrome's new tab into a macOS aerial screensaver.",
5+
"description": "Transform Safari or Chrome's new tab into a macOS aerial screensaver.",
66
"license": "MIT",
77
"type": "module",
88
"scripts": {
99
"dev": "vite",
1010
"build": "vite build",
11+
"build:safari": "vite build && node scripts/prepare-safari-dist.mjs",
12+
"package:safari": "npm run build:safari && xcrun safari-web-extension-packager dist --macos-only",
1113
"preview": "vite preview",
1214
"zip": "node scripts/zip.js",
1315
"build:quotes": "node scripts/build-quotes.mjs",

scripts/prepare-safari-dist.mjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { readFile, writeFile } from 'node:fs/promises';
2+
import { resolve, dirname } from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const __dirname = dirname(fileURLToPath(import.meta.url));
6+
const root = resolve(__dirname, '..');
7+
const dist = resolve(root, 'dist');
8+
const manifestPath = resolve(dist, 'manifest.json');
9+
10+
const manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
11+
12+
// The background script only opens the options page on install/update.
13+
// Removing it avoids Safari service-worker module compatibility warnings.
14+
delete manifest.background;
15+
16+
if (Array.isArray(manifest.permissions)) {
17+
manifest.permissions = manifest.permissions.filter((p) => p !== 'topSites');
18+
if (manifest.permissions.length === 0) {
19+
delete manifest.permissions;
20+
}
21+
}
22+
23+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
24+
console.log('Prepared Safari-compatible dist/manifest.json');

src/_locales/en/messages.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"message": "Macify - Gorgeous Aerial Videos as Your New Tab"
44
},
55
"ext_description": {
6-
"message": "Transform Chrome's new tab into macOS's gorgeous aerial screensaver videos."
6+
"message": "Transform your new tab into macOS's gorgeous aerial screensaver videos."
77
},
88
"options_title": {
99
"message": "Macify Settings"
@@ -228,7 +228,7 @@
228228
"message": "Why might Apple's server need extra setup?"
229229
},
230230
"video_apple_help_intro": {
231-
"message": "Chrome doesn't always trust Apple's sylvan.apple.com certificate, so direct video loading may fail. Two ways to make it work:"
231+
"message": "Some browsers may not trust Apple's sylvan.apple.com certificate, so direct video loading can fail. Two ways to make it work:"
232232
},
233233
"video_apple_help_option1_title": {
234234
"message": "Option 1 — Use the reverse proxy (easy)"
@@ -243,7 +243,7 @@
243243
"message": "Open"
244244
},
245245
"video_apple_help_option2_body_post": {
246-
"message": "in Chrome once. You'll see a security warning — click Advanced, then \"Proceed to sylvan.apple.com (unsafe)\". Chrome remembers your trust and direct connection works from then on."
246+
"message": "in the target browser once. If you see a security warning, open the advanced option and proceed. The browser should remember your trust after that."
247247
},
248248
"video_local_help_title": {
249249
"message": "Set up a local Apache server (one-time)"
@@ -282,7 +282,7 @@
282282
"message": "Translation"
283283
},
284284
"options_translation_description": {
285-
"message": "Translates English mottos into your display language using Chrome's built-in on-device Translator API. No new network requests beyond the one-time model download."
285+
"message": "Translates English mottos into your display language when the browser provides an on-device Translator API. No new network requests beyond the one-time model download."
286286
},
287287
"options_translation_model_label": {
288288
"message": "Model"
@@ -306,7 +306,7 @@
306306
"message": "Not supported for this language pair"
307307
},
308308
"options_translation_status_no_api": {
309-
"message": "Your browser doesn't support the Translator API (requires Chrome 138+)"
309+
"message": "Your browser doesn't support the Translator API"
310310
},
311311
"options_translation_download_button": {
312312
"message": "Download model now"

src/_locales/ja/messages.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"message": "Macify - 華麗なエアリアル動画の新しいタブ"
44
},
55
"ext_description": {
6-
"message": "Chromeの新しいタブをmacOSの美しいエアリアル・スクリーンセーバー動画に変えます。"
6+
"message": "新しいタブをmacOSの美しいエアリアル・スクリーンセーバー動画に変えます。"
77
},
88
"options_title": {
99
"message": "Macify 設定"
@@ -228,7 +228,7 @@
228228
"message": "Apple のサーバーで追加設定が必要な理由"
229229
},
230230
"video_apple_help_intro": {
231-
"message": "Chrome が Apple の sylvan.apple.com の証明書を信頼しないことがあり、動画の直接読み込みに失敗する可能性があります。2つの解決方法:"
231+
"message": "一部のブラウザでは Apple の sylvan.apple.com の証明書を信頼せず、動画の直接読み込みに失敗する可能性があります。2つの解決方法:"
232232
},
233233
"video_apple_help_option1_title": {
234234
"message": "方法 1 — リバースプロキシを使う(簡単)"
@@ -240,10 +240,10 @@
240240
"message": "方法 2 — Apple の証明書を手動で信頼する(最もクリーン)"
241241
},
242242
"video_apple_help_option2_body_pre": {
243-
"message": "Chrome で"
243+
"message": "対象ブラウザで"
244244
},
245245
"video_apple_help_option2_body_post": {
246-
"message": "を一度開きます。セキュリティ警告が表示されたら、「詳細」→「sylvan.apple.com にアクセスする (安全ではありません)」をクリック。Chrome が信頼を記憶し、以降は直接接続が機能します。"
246+
"message": "を一度開きます。セキュリティ警告が表示されたら、詳細オプションを開いて続行してください。ブラウザが信頼を記憶すれば、以降は直接接続が機能します。"
247247
},
248248
"video_local_help_title": {
249249
"message": "ローカル Apache サーバーを設定する(一回だけ)"
@@ -282,7 +282,7 @@
282282
"message": "翻訳"
283283
},
284284
"options_translation_description": {
285-
"message": "Chrome 内蔵の on-device Translator API を使い、英語の格言を表示言語に翻訳します。初回のモデルダウンロード以外、新たなネットワークリクエストはありません。"
285+
"message": "ブラウザが on-device Translator API を提供している場合、英語の格言を表示言語に翻訳します。初回のモデルダウンロード以外、新たなネットワークリクエストはありません。"
286286
},
287287
"options_translation_model_label": {
288288
"message": "モデル"
@@ -306,7 +306,7 @@
306306
"message": "この言語ペアは未対応"
307307
},
308308
"options_translation_status_no_api": {
309-
"message": "お使いのブラウザは Translator API 未対応です(Chrome 138+ が必要)"
309+
"message": "お使いのブラウザは Translator API 未対応です"
310310
},
311311
"options_translation_download_button": {
312312
"message": "モデルをダウンロード"

src/_locales/zh_CN/messages.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"message": "Macify - 华丽的航拍视频新标签页"
44
},
55
"ext_description": {
6-
"message": "将 Chrome 的新标签页变成 macOS 的华丽航拍屏保视频。"
6+
"message": "将新标签页变成 macOS 的华丽航拍屏保视频。"
77
},
88
"options_title": {
99
"message": "Macify 设置"
@@ -228,7 +228,7 @@
228228
"message": "为什么苹果服务器可能需要额外配置?"
229229
},
230230
"video_apple_help_intro": {
231-
"message": "Chrome 不一定信任苹果 sylvan.apple.com 的证书,直连视频可能失败。两种解决方案:"
231+
"message": "部分浏览器不一定信任苹果 sylvan.apple.com 的证书,直连视频可能失败。两种解决方案:"
232232
},
233233
"video_apple_help_option1_title": {
234234
"message": "方案 1 — 启用反向代理(简单)"
@@ -240,10 +240,10 @@
240240
"message": "方案 2 — 手动信任苹果证书(最干净)"
241241
},
242242
"video_apple_help_option2_body_pre": {
243-
"message": "在 Chrome 里打开"
243+
"message": "在目标浏览器里打开"
244244
},
245245
"video_apple_help_option2_body_post": {
246-
"message": "一次。会出现安全警告——点「高级」,然后点「继续访问 sylvan.apple.com(不安全)」。Chrome 会记住你的信任,之后直连就没问题了。"
246+
"message": "一次。如果出现安全警告,打开高级选项并继续访问。浏览器通常会记住你的信任,之后直连就没问题了。"
247247
},
248248
"video_local_help_title": {
249249
"message": "搭建本地 Apache 服务器(一次性配置)"
@@ -282,7 +282,7 @@
282282
"message": "翻译"
283283
},
284284
"options_translation_description": {
285-
"message": "使用 Chrome 内建的 on-device Translator API 把英文格言翻译成你设置的显示语言。除首次模型下载外,无任何新的网络请求。"
285+
"message": "当浏览器提供 on-device Translator API 时,把英文格言翻译成你设置的显示语言。除首次模型下载外,无任何新的网络请求。"
286286
},
287287
"options_translation_model_label": {
288288
"message": "模型"
@@ -306,7 +306,7 @@
306306
"message": "此语言对不支持"
307307
},
308308
"options_translation_status_no_api": {
309-
"message": "你的浏览器不支持 Translator API(需要 Chrome 138+)"
309+
"message": "你的浏览器不支持 Translator API"
310310
},
311311
"options_translation_download_button": {
312312
"message": "下载模型"

src/_locales/zh_TW/messages.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"message": "Macify - 華麗的空拍影片新分頁"
44
},
55
"ext_description": {
6-
"message": "將 Chrome 的新分頁變成 macOS 的華麗空拍螢幕保護影片。"
6+
"message": "將新分頁變成 macOS 的華麗空拍螢幕保護影片。"
77
},
88
"options_title": {
99
"message": "Macify 設定"
@@ -228,7 +228,7 @@
228228
"message": "為什麼蘋果伺服器可能需要額外設定?"
229229
},
230230
"video_apple_help_intro": {
231-
"message": "Chrome 不一定信任蘋果 sylvan.apple.com 的憑證,直連影片可能失敗。兩種解決方案:"
231+
"message": "部分瀏覽器不一定信任蘋果 sylvan.apple.com 的憑證,直連影片可能失敗。兩種解決方案:"
232232
},
233233
"video_apple_help_option1_title": {
234234
"message": "方案 1 — 啟用反向代理(簡單)"
@@ -240,10 +240,10 @@
240240
"message": "方案 2 — 手動信任蘋果憑證(最乾淨)"
241241
},
242242
"video_apple_help_option2_body_pre": {
243-
"message": "在 Chrome 裡開啟"
243+
"message": "在目標瀏覽器裡開啟"
244244
},
245245
"video_apple_help_option2_body_post": {
246-
"message": "一次。會出現安全性警告——點「進階」,然後點「繼續前往 sylvan.apple.com(不安全)」。Chrome 會記住你的信任,之後直連就沒問題了。"
246+
"message": "一次。如果出現安全性警告,請開啟進階選項並繼續前往。瀏覽器通常會記住你的信任,之後直連就沒問題了。"
247247
},
248248
"video_local_help_title": {
249249
"message": "架設本地 Apache 伺服器(一次性設定)"
@@ -282,7 +282,7 @@
282282
"message": "翻譯"
283283
},
284284
"options_translation_description": {
285-
"message": "使用 Chrome 內建的 on-device Translator API 把英文格言翻譯成你設定的顯示語言。除首次模型下載外,無任何新的網路請求。"
285+
"message": "當瀏覽器提供 on-device Translator API 時,把英文格言翻譯成你設定的顯示語言。除首次模型下載外,無任何新的網路請求。"
286286
},
287287
"options_translation_model_label": {
288288
"message": "模型"
@@ -306,7 +306,7 @@
306306
"message": "此語言對不支援"
307307
},
308308
"options_translation_status_no_api": {
309-
"message": "你的瀏覽器不支援 Translator API(需要 Chrome 138+)"
309+
"message": "你的瀏覽器不支援 Translator API"
310310
},
311311
"options_translation_download_button": {
312312
"message": "下載模型"

0 commit comments

Comments
 (0)