Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Install-on-Mac.command
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# Finder entry point. Dependency installation is described in docs/MACOS.md.
editkin_directory="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
/bin/bash "$editkin_directory/scripts/install-macos-community.sh" "$@"
editkin_status=$?
if [ -t 0 ]; then
printf '\nPress Return to close this window.\n'
read -r editkin_reply
fi
exit "$editkin_status"
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ npm run dev

The bundled demo videos are generated color bars with silent audio. You can use your own lawfully redistributable media when testing edits. Some advanced rendering, fonts, color transforms, captions, and native model features require separately obtained dependencies; a web build alone does not prove those paths.

## Local macOS installation

For a local community `.app`, see [the macOS installation guide](docs/MACOS.md).
After installing the prerequisites, run `bash scripts/install-macos-community.sh`
or double-click `Install-on-Mac.command` in a Git checkout. This builds on your Mac;
it is not an official installer or a portable binary download.

## Contribute

Start with the [public issue tracker](https://github.com/Hao0321/Editkin/issues), including tasks labeled `good first issue` or `help wanted`.
Expand Down
7 changes: 7 additions & 0 deletions README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,10 @@ npm run dev
外部 PR 視為不受信任的程式碼:CI 不持有正式簽章憑證,合併須經人工審查與檢查。自動掃描無法保證程式碼沒有惡意行為。發現漏洞請依 [安全通報](SECURITY.md)私下回報,不要在公開 Issue 放利用細節。

目前公開的是可協作的原始碼,**沒有通過正式安裝包的發行審查**。任何 PR 產物或自行建置的執行檔都不代表官方發行。正式下載會在相依授權、各發布平台的實機測試、最終檔案雜湊、SBOM、專案簽章與來源證明完成後另行公告;若尚無作業系統簽章,會明確標示並停用現有需要 Authenticode 的 Windows 自動更新。

## Mac 本機安裝

請先依[Mac 安裝指南](docs/MACOS.md)準備開發工具與依賴,再於 Git 原始碼目錄執行
`bash scripts/install-macos-community.sh`,或在 Finder 雙擊 `Install-on-Mac.command`。
預設安裝到 `~/Applications/Editkin Community.app`,遇到同名程式會停止,不會覆寫。
這是在自己的 Mac 編譯使用的社群版,仍依賴本機 Homebrew 函式庫,並非官方安裝包或可攜式下載版。
8 changes: 8 additions & 0 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ The Rust and Tauri source is included for development. The desktop media pipelin

Do not distribute a binary as an official Editkin release based solely on a passing web build or source test. A public installer needs a fresh, exact-artifact review: third-party corresponding source and notices (especially FFmpeg), platform-specific build and edit/export testing, final hashes and SBOM, a verified release identity, and provenance attestation. The current packaged Windows updater specifically requires Authenticode; an unsigned community build cannot use that updater. [RELEASE.md](RELEASE.md) tracks the available release paths.

### macOS local community app

[MACOS.md](MACOS.md) documents the prerequisites, the one-command build/install
helper, the Finder `.command` entry point, and verification limits. It builds a
new local app without overwriting an installed copy or altering the source
checkout. It relies on this Mac's installed runtime libraries and does not create
a redistributable or official release.

### Linux community desktop (GTK 0.19 migration)

Use Node.js 22.13+ on `PATH`, Rust 1.92 or newer (verification used 1.98.1), a C/C++ toolchain, and `pkg-config`. GTK **Rust crate** 0.19 still targets system GTK **3**, not GTK 4. The locked Linux features require GTK 3.24+, GLib/GIO 2.70+, WebKitGTK 4.1 API 2.40+, JavaScriptCoreGTK 4.1 API 2.38+, and libsoup 3.0+. These minimums come from the enabled sys-crate features and their `system-deps` metadata.
Expand Down
117 changes: 117 additions & 0 deletions docs/MACOS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Install a local macOS community build

This is a source-build helper for your own Mac, not an official download or a
standalone redistributable installer. It builds the current Git checkout and
uses your installed Node and FFmpeg libraries. Keep those dependencies installed.
It does not change Gatekeeper, remove quarantine attributes, install signing
credentials, or create official release metadata.

## 1. Install prerequisites once

Install Apple's Command Line Tools (`xcode-select --install`) and
[Homebrew](https://brew.sh/) using their official instructions. Then:

```sh
brew install node@22 rust ffmpeg-full python@3.12
```

The helper discovers Homebrew's prefix on Apple Silicon and Intel Macs; it does
not assume one architecture. Node must be at least 22.13 and support `node:sqlite`,
Rust at least 1.92, and Python at least 3.9 with `venv`. FFmpeg must include the
`libx264` and `aac` encoders and the `ass`, `subtitles` and `drawtext` filters. Use a toolchain
that supports your macOS version. The minimum OS of the resulting app also depends
on these installed runtimes; the source project's 12.0 setting alone is not a
promise that a current Homebrew build runs on macOS 12.

## 2. Clone, then build and install

```sh
git clone https://github.com/Hao0321/Editkin.git
cd Editkin
bash scripts/install-macos-community.sh
```

Or open the cloned folder in Finder and double-click **Install-on-Mac.command**.
The `.command` file runs the same script and keeps the Terminal result visible.
The first build downloads npm packages, the pinned fontTools 4.60.2 Python wheel,
and locked Rust dependencies, generates the bundled OFL font faces, and compiles
the desktop shell. Allow time and disk space for a native Rust build.

Default destination: `~/Applications/Editkin Community.app`.
The installer does not launch the app. Open it in Finder after a successful build.
Do not run the installer with `sudo`.

To check prerequisites without downloads or writes, or choose another destination:

```sh
bash scripts/install-macos-community.sh --check
bash scripts/install-macos-community.sh --output "$HOME/Applications/Editkin Test.app"
```

An existing destination, including a symlink, is refused. For an update, build to
a new name, verify it, then replace your old copy yourself. Your video projects
are separate from the application bundle.

## What the helper does

- Copies Git-tracked working-tree files into a fresh `.rd/macos-community.*`
directory. Ignored files, personal media, credentials and local caches are not
copied. For development, stage newly added source files before testing the helper.
- Runs `npm ci`, creates an isolated Python virtual environment, generates the 43
static font faces, and verifies them with the existing font gate. Generated
manifests and metrics stay in the disposable source copy.
- Builds the web UI and real resident service with `--community`, then the Rust
shell with `community-desktop,tauri/custom-protocol`. The macOS-only invocation
sets `CARGO_PROFILE_RELEASE_PANIC=unwind` so the pinned objc2/Wry code can catch
recoverable WebKit URL-scheme cancellation exceptions during media playback.
- Copies the local runtimes and public resources into the new app, applies an
ad-hoc signature, and verifies the signature and bundled runtime launch probes.
Homebrew shared libraries remain dependencies of this Mac; this is not a
relocatable app for other computers.
- Records local community build identity and hashes, without private source paths.
It leaves the original checkout, system security settings and existing apps alone.

The successful build path is printed. Rust compilation caches stay under
`.rd/macos-community-target` for subsequent runs. Its `.rd/macos-community.*` directory can
be removed after verification; retain the app and its Homebrew dependencies.
If a build fails, the same directory remains for diagnosis. Fix the reported
prerequisite and rerun; the next attempt uses a fresh directory.

## First use and verification

1. Add your own video, photo or audio through **加入影片開始剪**.
2. For an existing `.editkin.json`, click **開啟之前的專案** at the bottom of the
home card. Inside the editor use **更多 → 專案與連線 → 開啟專案**. A project JSON
is not a media asset; importing it through **加入素材** currently produces an
OpenEXR manifest error. Finder project-file association is not provided here.
3. Check preview, pause/seek/replay, save/reopen, and export on your own Mac.
Use the repository's synthetic `public/demo-source.mp4` for a shareable check.
4. Play the exported MP4 separately. A successful source build or package-signature
check does not by itself prove correct preview, sound or rendering.

The community edition uses compatible preview. Private Creator Packs, speech
models, native GPU compositor, official updater identity and official Agent setup
are not included or certified by this helper. An unavailable Creator Pack message
does not mean the local installation failed. Advanced effects and scene-linear
ACES output need their separate prerequisites. See [BUILDING.md](BUILDING.md)
and [RELEASE.md](RELEASE.md) for source and release boundaries.

Only synthetic/public fixtures should accompany bug reports. Do not publish
project media, credentials, personal paths or unreviewed diagnostic logs.

## Contributor checks

```sh
bash -n scripts/install-macos-community.sh Install-on-Mac.command
python3 scripts/package-macos-community.test.py
python3 scripts/test_install_macos_community.py
npm run typecheck
npm test
npm run build
npm run source:scan
```

The helper is designed to discover both architectures. Report the exact machine,
OS and command actually tested; do not infer Intel or other macOS coverage from
an Apple Silicon run. Distribution of binaries still requires the separate
licensing, corresponding-source, signing and provenance review in RELEASE.md.
123 changes: 123 additions & 0 deletions scripts/install-macos-community.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash
# Build a local community app without changing the source checkout or an installed app.
set -euo pipefail

usage() {
cat <<'HELP'
Usage: bash scripts/install-macos-community.sh [--check] [--output /path/App.app]

Builds this Git checkout into a local, ad-hoc-signed macOS community app.
Default output: $HOME/Applications/Editkin Community.app
--check Check prerequisites only; no downloads or writes.
--output Choose a new .app path. Existing destinations are never replaced.

Prerequisites: Xcode Command Line Tools, Node >=22.13 (with npm), Rust >=1.92,
Python >=3.9 with venv, and FFmpeg/ffprobe with libx264, AAC, libass and drawtext.
Homebrew example: brew install node@22 rust ffmpeg-full python@3.12
This does not install Homebrew, change macOS security settings, or launch the app.
HELP
}
editkin_check=0
editkin_output="${HOME:?}/Applications/Editkin Community.app"
while [ "$#" -gt 0 ]; do
case "$1" in
--check) editkin_check=1; shift ;;
--output) [ "$#" -ge 2 ] || { usage >&2; exit 2; }; editkin_output="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) printf 'Unknown option: %s\n' "$1" >&2; usage >&2; exit 2 ;;
esac
done
[ "$(uname -s)" = Darwin ] || { echo 'This installer requires macOS.' >&2; exit 1; }
[ "$(id -u)" -ne 0 ] || { echo 'Run as your normal user, without sudo.' >&2; exit 1; }
editkin_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
cd "$editkin_root"

# Finder-launched .command files may not inherit the user's shell PATH.
editkin_brew="$(command -v brew || true)"
if [ -z "$editkin_brew" ]; then
for editkin_candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do
if [ -x "$editkin_candidate" ]; then editkin_brew="$editkin_candidate"; break; fi
done
fi
if [ -n "$editkin_brew" ]; then
editkin_prefix="$("$editkin_brew" --prefix)"
export PATH="$editkin_prefix/opt/node@22/bin:$editkin_prefix/opt/ffmpeg-full/bin:$editkin_prefix/opt/python@3.12/libexec/bin:$editkin_prefix/bin:$PATH"
fi
if [ -d "$HOME/.cargo/bin" ]; then export PATH="$PATH:$HOME/.cargo/bin"; fi
for editkin_tool in git node npm cargo rustc python3 ffmpeg ffprobe xcrun codesign; do
command -v "$editkin_tool" >/dev/null || { printf 'Missing %s. See --help for prerequisites.\n' "$editkin_tool" >&2; exit 1; }
done
xcrun --find clang >/dev/null
node --input-type=module -e 'const [a,b]=process.versions.node.split(".").map(Number);if(a<22||(a===22&&b<13))throw Error("Node >=22.13 required");await import("node:sqlite")'
python3 -c 'import sys,venv; assert sys.version_info >= (3,9), "Python >=3.9 required"'
python3 -c 'import subprocess; v=subprocess.check_output(["rustc","--version"],text=True).split()[1].split("."); assert tuple(map(int,v[:2])) >= (1,92), "Rust >=1.92 required"'
editkin_ffmpeg="$(command -v ffmpeg)"
editkin_ffprobe="$(command -v ffprobe)"
editkin_node="$(command -v node)"
for editkin_encoder in libx264 aac; do
"$editkin_ffmpeg" -hide_banner -encoders 2>/dev/null | awk -v item="$editkin_encoder" '$2 == item {found=1} END {exit !found}' || {
printf 'FFmpeg is missing encoder %s. Install ffmpeg-full.\n' "$editkin_encoder" >&2; exit 1;
}
done
for editkin_filter in ass subtitles drawtext; do
"$editkin_ffmpeg" -hide_banner -filters 2>/dev/null | awk -v item="$editkin_filter" '$2 == item {found=1} END {exit !found}' || {
printf 'FFmpeg is missing filter %s. Install ffmpeg-full.\n' "$editkin_filter" >&2; exit 1;
}
done
"$editkin_ffprobe" -version >/dev/null
# Resolve before entering the isolated build, including paths containing spaces.
editkin_output="$(python3 -c 'import os,sys; print(os.path.abspath(sys.argv[1]))' "$editkin_output")"
case "$editkin_output" in *.app) ;; *) echo '--output must end in .app' >&2; exit 2 ;; esac
[ ! -e "$editkin_output" ] && [ ! -L "$editkin_output" ] || { echo 'Destination exists; choose a new --output path. Nothing was replaced.' >&2; exit 1; }
[ "$(git rev-parse --show-toplevel)" = "$editkin_root" ] || { echo 'Run from an Editkin Git checkout.' >&2; exit 1; }
printf 'Prerequisites OK (%s). Local community build; not an official release.\n' "$(uname -m)"
[ "$editkin_check" -eq 0 ] || exit 0

mkdir -p .rd
editkin_work="$(mktemp -d "$editkin_root/.rd/macos-community.XXXXXX")"
# Copy only Git-tracked working-tree files, never ignored media, caches or secrets.
# Builds and generated fonts remain in .rd; the original source stays unchanged.
python3 - "$editkin_root" "$editkin_work/source" <<'PY'
import pathlib, shutil, subprocess, sys
root, target = map(pathlib.Path, sys.argv[1:])
target.mkdir()
for raw in subprocess.check_output(['git', 'ls-files', '-z'], cwd=root).split(b'\0'):
if not raw: continue
rel = pathlib.Path(raw.decode('utf8'))
if rel.is_absolute() or '..' in rel.parts: raise ValueError('Unsafe tracked path')
source = root / rel
if any(p.is_symlink() for p in (source, *source.parents)):
raise ValueError('Symlink in tracked source: ' + str(rel))
if not source.is_file(): raise ValueError('Missing tracked source: ' + str(rel))
dest = target / rel
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, dest)
PY
cd "$editkin_work/source"
printf 'Building in %s\n' "$editkin_work"
npm ci --no-audit --no-fund
python3 -m venv "$editkin_work/venv"
"$editkin_work/venv/bin/python" -m pip install --disable-pip-version-check --only-binary=:all: 'fonttools==4.60.2'
"$editkin_work/venv/bin/python" scripts/build-static-font-pack.py --source public/fonts --stage "$editkin_work/fonts" --workers 2
# Only the disposable source copy receives generated manifests and faces.
python3 - "$editkin_work/fonts" public/fonts <<'PY'
import pathlib, shutil, sys
source, target = map(pathlib.Path, sys.argv[1:])
shutil.rmtree(target)
shutil.copytree(source, target)
PY
node scripts/open-font-gate.mjs public/fonts --generated-dir=src/generated --refresh-generated --self-test
npm run build
node scripts/build-desktop.mjs --community
# objc2 can catch WebKit URL-scheme cancellation exceptions only with unwinding.
# Keep this scoped to this macOS community build, not other release profiles.
export CARGO_PROFILE_RELEASE_PANIC=unwind
export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-4}"
export CARGO_TARGET_DIR="$editkin_root/.rd/macos-community-target"
export TAURI_CONFIG='{"bundle":{"resources":[]}}'
cargo build --release --locked --manifest-path src-tauri/Cargo.toml --features community-desktop,tauri/custom-protocol
python3 scripts/package-macos-community.py --repo "$editkin_work/source" \
--binary "$CARGO_TARGET_DIR/release/editkin" --node "$editkin_node" \
--ffmpeg "$editkin_ffmpeg" --ffprobe "$editkin_ffprobe" --output "$editkin_output"
printf '\nInstalled: %s\nOpen it in Finder when ready. Keep Homebrew dependencies installed.\n' "$editkin_output"
printf 'Build files (removable after verification): %s\n' "$editkin_work"
Loading