Restructure step R: the app is Starsync (dev.foxyz.starsync)
- Linux app id dev.foxyz.starsync, binary starsync; Windows starsync.exe, company foxyz; server starsync-server; Dart package starsync; archives starsync-<ver>-*. - 1.2.x compatibility: watch_together and watch-together-server launchers (Linux) / copies (Windows) in the archive; the updater accepts both names and relaunches the new binary; update.sh/.bat use whichever server exists. - First start copies (never moves) the old support folder and this app's Hive boxes out of ~/Documents into <support>/hive; a marker makes it run once; AppDirs is a port; settings schema version with ordered migrations. - Launcher entry dev.foxyz.starsync.desktop; the old one removed. - Repository name and URLs unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4ca02c3cf
commit
51c1c5ab78
96 files changed
+1169
-489
No files matched your search
+71
-19
@@ -9,7 +9,7 @@ Plain overview first: [HOW-IT-WORKS.md](HOW-IT-WORKS.md). Wire format:
|
||||
|---|---|---|
|
||||
| `packages/core` | protocol messages, sync engine (`SyncEngine`), constants, config, Range parsing, logging, Jellyfin client, updater, watched rule (`WatchSession`); `testing.dart` (test support for all three packages, not in `core.dart`: `FlakyProxy`) | pure Dart, no Flutter |
|
||||
| `packages/server` | Relic HTTP + WebSocket server (`SyncServer`, `ServerHub`, `Session`, media endpoint, relay buffer, Jellyfin relay), the `serve()` entrypoint, `bin/server.dart` (dedicated server) | pure Dart, no Flutter |
|
||||
| `apps/desktop` | Flutter app: UI, `SyncClient`, `Connection`, `SessionCoordinator`, `PlaybackController` (media_kit/mpv), `ServerIsolate`, update UI (`UpdateController`) | ships with `watch-together-server` |
|
||||
| `apps/desktop` | Flutter app: UI, `SyncClient`, `Connection`, `SessionCoordinator`, `PlaybackController` (media_kit/mpv), `ServerIsolate`, update UI (`UpdateController`) | ships with `starsync-server` |
|
||||
| `tool` | harnesses: `range_logger`, `shaper`, `fake_viewer`, `e2e_check` | dev only |
|
||||
| `deploy` | systemd unit for the dedicated server | |
|
||||
|
||||
@@ -58,7 +58,7 @@ size (`ServerIsolate.setFile`): the host's in-session File swap then sends a
|
||||
cancelled, solo starts again with the same media. Stop leaves without
|
||||
asking.
|
||||
- **Dedicated server**: `bin/server.dart` compiled with `dart compile exe`
|
||||
and shipped next to the app as `watch-together-server`. It parses flags
|
||||
and shipped next to the app as `starsync-server`. It parses flags
|
||||
(`--port`, `--secret`, `--name`, `--media`, `--advertise-host`,
|
||||
`--jellyfin <file>`, `--[no-]yt-dlp`, `--yt-dlp-dir`, `--yt-dlp-cookies`, `--config`; default port 8080) into the same map and calls `serve`
|
||||
(`--log-dir` only picks where its log files go, see "Logging")
|
||||
@@ -1174,6 +1174,10 @@ handed on from there (the coordinator gets its `Notifier`, `Connection` and
|
||||
options, warm-up.
|
||||
- `SystemNotifications`: an interface only; desktop shows none
|
||||
(`NoSystemNotifications`).
|
||||
- `AppDirsPort` (`DesktopAppDirs`): where Hive and the logs live
|
||||
(`AppDirs`, "Desktop UI"), and the copy of the data from before the
|
||||
rename; resolved in `main` before the composition root exists, so not a
|
||||
`Ports` field.
|
||||
Still direct: the player (`PlaybackController`, media_kit, and its
|
||||
`AppYtDlp.instance.mpvRawOptions`), the updater's restart
|
||||
(`Process.start`), the session's own file reads for what it plays or
|
||||
@@ -1503,11 +1507,38 @@ Settings persist in two Hive boxes: `connect_form` (last form, recent
|
||||
servers and links, the profile picture and colour; saved even when a join
|
||||
fails) and
|
||||
`settings`. Where Hive and the logs live is `AppDirs`
|
||||
(`platform/app_dirs.dart`, resolved once in `main`): Hive's default folder
|
||||
(the documents folder) and `<app support>/logs`; with `STARSYNC_PROFILE`
|
||||
(DEVELOPMENT "Dev loop") `<app support>/profiles/<name>/hive` and `logs`,
|
||||
and the window title gets ` [<name>]`. yt-dlp, shaders and caches stay
|
||||
shared. Link media names are a web page's title (see "yt-dlp"), else
|
||||
(`platform/ports/app_dirs.dart`, resolved once in `main` by the
|
||||
`AppDirsPort`, `DesktopAppDirs` on the desktop): `<app support>/hive` and
|
||||
`<app support>/logs`; with `STARSYNC_PROFILE` (DEVELOPMENT "Dev loop")
|
||||
`<app support>/profiles/<name>/hive` and `logs`, and the window title gets
|
||||
` [<name>]`. yt-dlp, shaders and caches stay shared. The app support
|
||||
folder is path_provider's: Linux `~/.local/share/dev.foxyz.starsync` (the
|
||||
application id), Windows `%APPDATA%\foxyz\Starsync` (the exe's company and
|
||||
product name).
|
||||
|
||||
**Data from before the rename** (`platform/data_migration.dart`, run by
|
||||
`DesktopAppDirs.resolve` before Hive opens and the log starts; its lines
|
||||
are logged once the log is open): once per support folder (the marker
|
||||
`<app support>/migration.json`: `migratedFrom`, `hiveFrom`, `boxes`,
|
||||
`files`), the first existing old support folder (Linux
|
||||
`moe.senkochan.watch_together`, then `watch_together`, next to the new one;
|
||||
Windows `%APPDATA%\com.example\watch_together`) is copied in whole
|
||||
(profiles, logs, shaders, yt-dlp; modes kept, so `cookies.txt` stays 0600;
|
||||
symlinks as links), and the app's own Hive boxes (`appHiveBoxes`:
|
||||
`settings`, `connect_form`, `files`, `jellyfin`, `track_prefs`, `.hive`
|
||||
and `.lock`, by name only, never other apps' boxes there) from the
|
||||
documents folder, where `Hive.initFlutter()` kept them up to 1.2.x, into
|
||||
`<app support>/hive`. Copied, never moved (1.2.x keeps working), never
|
||||
over a file already there. Lines name paths and counts, never contents.
|
||||
The caches folder (thumbnails, the AniList schedule) is not copied: it
|
||||
refills.
|
||||
|
||||
**Settings schema** (`state/settings_schema.dart`): the `settings` box
|
||||
stores `schemaVersion`; `migrateSettings` (run when `AppSettings` loads)
|
||||
applies the ordered `settingsMigrations` steps past the stored version up
|
||||
to `settingsSchemaVersion`, stamping the version after each. 1 is the
|
||||
layout of 1.2.x (a box without a version is at 1, no steps yet); a box
|
||||
from a newer build is left alone. Link media names are a web page's title (see "yt-dlp"), else
|
||||
derived from the URL path, never containing a query string.
|
||||
|
||||
Jellyfin on the desktop (`lib/src/jellyfin/`, over the core client):
|
||||
@@ -1697,7 +1728,7 @@ dedicated server (`package:logging` loggers named by area: `relay`,
|
||||
`app`).
|
||||
|
||||
- **Where**: the app writes `<app support>/logs/app-YYYY-MM-DD.log`
|
||||
(Linux `~/.local/share/moe.senkochan.watch_together/logs`; with a
|
||||
(Linux `~/.local/share/dev.foxyz.starsync/logs`; with a
|
||||
profile `<app support>/profiles/<name>/logs`, see `AppDirs` under
|
||||
"Desktop UI"); its hosted server's records arrive over the isolate's
|
||||
`events` port and go in the same file as `server.<logger>` (`relogLine`). The dedicated server
|
||||
@@ -1809,13 +1840,19 @@ status.
|
||||
|
||||
`assets/icon/icon.svg` is the source; `icon_<size>.png` and the Windows
|
||||
`app_icon.ico` are rendered from it (rsvg-convert, magick). The GTK
|
||||
application id is `moe.senkochan.watch_together`, which Wayland uses as the
|
||||
window's `app_id`; compositors take the icon from the `.desktop` file of
|
||||
that id. A tarball install has none, so on start a Linux release build
|
||||
(`platform/desktop_entry.dart`, skipped in debug) writes
|
||||
`~/.local/share/applications/moe.senkochan.watch_together.desktop` (Exec =
|
||||
the running binary) and the icons into the hicolor theme, only when they
|
||||
changed. The runner also sets the window icon from the bundle (X11).
|
||||
application id is `dev.foxyz.starsync` (also the X11 `WM_CLASS`, from
|
||||
`g_set_prgname`), which Wayland uses as the window's `app_id`; compositors
|
||||
take the icon from the `.desktop` file of that id. A tarball install has
|
||||
none, so on start a Linux release build (`platform/desktop_entry.dart`,
|
||||
skipped in debug) writes
|
||||
`~/.local/share/applications/dev.foxyz.starsync.desktop` (Exec = the
|
||||
running binary, `StartupWMClass` and `Icon` = the id) and the icons into
|
||||
the hicolor theme, only when they changed, and deletes the entry and
|
||||
icons 1.2.x wrote under its id `moe.senkochan.watch_together` (those exact
|
||||
files only). The runner also sets the window icon from the bundle (X11).
|
||||
Windows: the exe's version resource (`windows/runner/Runner.rc`) says
|
||||
company `foxyz`, product `Starsync`; the window class is
|
||||
`STARSYNC_WINDOW`.
|
||||
|
||||
## Updater
|
||||
|
||||
@@ -1829,8 +1866,23 @@ folder (same filesystem, so moves are renames; the folder must be
|
||||
user-writable). Each top-level entry is moved aside and the new one moved in,
|
||||
with rollback on failure (writing the running executable fails with ETXTBSY;
|
||||
rename works). A packaged install is detected by `data/` and `lib/` next to
|
||||
the binary (app or server, same folder); anything else exits with "update
|
||||
manually". A manifest whose
|
||||
the binary (app or server, same folder; Windows: `data/` and
|
||||
`flutter_windows.dll`), whatever the binary is called; anything else exits
|
||||
with "update manually". The archive must contain the running binary's name;
|
||||
an old name (`watch_together`, `watch-together-server`, `.exe` on
|
||||
Windows) is also satisfied by the new one (`starsync`, `starsync-server`).
|
||||
**Names before the rename**: the archive (`starsync-<ver>-<platform>`,
|
||||
top folder `starsync-<ver>/`) also carries those old names, because a
|
||||
1.2.x updater checks that its own name is in the archive and then restarts
|
||||
it, and VPS units and old `update.sh` copies run `watch-together-server`.
|
||||
Linux: shell launchers (`lib/src/update/bundle/watch_together`,
|
||||
`watch-together-server`, `exec` the new binary next to the resolved
|
||||
script); Windows: copies of `starsync.exe` and `starsync-server.exe` (same
|
||||
version resource, so the same data folder). After an update the app
|
||||
restarts `relaunchExecutable(...)`: the running binary, or for an old name
|
||||
the new one next to it, so a copy started by 1.2.x moves to `starsync.exe`
|
||||
on its first own update. `update.sh` / `update.bat` run `starsync-server`,
|
||||
else the old name. A manifest whose
|
||||
protocol is newer than the local one is a required update. Windows apply
|
||||
renames in-use files to `*.old` (swept on next start); CI tests it against a
|
||||
running exe on NTFS. The manifest's `assets` maps `linux-x64` /
|
||||
@@ -1842,9 +1894,9 @@ About and the tooltip of the strip's Settings tab): a release's version,
|
||||
a test build's with its commit (`GIT_COMMIT`, short hash, `-dirty` with
|
||||
uncommitted changes, passed by `tool/package_linux.sh`), and for a dev
|
||||
run the pubspec's version (`FLUTTER_BUILD_NAME`, which the Flutter tool
|
||||
defines for every build and run) with "dev run". CLI: `watch-together-server --upgrade` (no display needed;
|
||||
defines for every build and run) with "dev run". CLI: `starsync-server --upgrade` (no display needed;
|
||||
the shipped `update.sh` / `update.bat` run it), `--check-update` prints only;
|
||||
it ends with "restart the server to run <version>". `watch_together --upgrade`
|
||||
it ends with "restart the server to run <version>". `starsync --upgrade`
|
||||
does the same from the app binary. In the app, `UpdateController`
|
||||
(`apps/desktop/lib/src/update/`) runs the same code for the update bar
|
||||
(`UpdateBar`, `screens/home/update_indicator.dart`): a band across the
|
||||
|
||||
+11
-5
@@ -21,7 +21,7 @@ cd apps/desktop && flutter pub get && flutter run -d linux
|
||||
cd apps/desktop && flutter build linux --release --dart-define=APP_VERSION=<x.y.z>
|
||||
tool/package_linux.sh [--skip-build] [--noupload] # dist/*.tar.gz
|
||||
powershell -File tool/package_windows.ps1 [-SkipBuild] # dist/*.zip (on Windows)
|
||||
cd packages/server && dart compile exe --define=APP_VERSION=<x.y.z> bin/server.dart -o watch-together-server
|
||||
cd packages/server && dart compile exe --define=APP_VERSION=<x.y.z> bin/server.dart -o starsync-server
|
||||
```
|
||||
|
||||
`APP_VERSION` defaults to `0.0.0-dev`; the packagers stamp it from the
|
||||
@@ -30,7 +30,13 @@ also passes `GIT_COMMIT` (what the app shows: "Updater" in
|
||||
[ARCHITECTURE.md](ARCHITECTURE.md)). Setting `DISCORD_WEBHOOK_URL` makes the packager post the
|
||||
tarball to Discord (never commit it). The packager always compiles the
|
||||
dedicated server (with the Flutter SDK's `dart`) into the tarball as
|
||||
`watch-together-server`, also with `--skip-build`.
|
||||
`starsync-server`, also with `--skip-build`. The app binary is `starsync`
|
||||
(`BINARY_NAME`; Linux application id `dev.foxyz.starsync`), the archive
|
||||
`dist/starsync-<version>-linux-x64.tar.gz` / `-windows-x64.zip` with one
|
||||
top folder `starsync-<version>/`; it also carries the names up to 1.2.x
|
||||
(`watch_together`, `watch-together-server`: launchers on Linux, copies on
|
||||
Windows; "Updater" in [ARCHITECTURE.md](ARCHITECTURE.md)). The Dart
|
||||
package of the app is `starsync` (`package:starsync/...`).
|
||||
|
||||
## Dev loop
|
||||
|
||||
@@ -224,8 +230,8 @@ unexpectedly` line just before it is expected. Without the app:
|
||||
|
||||
After a session, read the log files rather than reproducing
|
||||
("Logging" in [ARCHITECTURE.md](ARCHITECTURE.md) has what goes in them):
|
||||
the app's are `~/.local/share/moe.senkochan.watch_together/logs/app-*.log`
|
||||
on Linux (on Windows under `%APPDATA%`; Settings → About → "Open logs
|
||||
the app's are `~/.local/share/dev.foxyz.starsync/logs/app-*.log`
|
||||
on Linux (on Windows `%APPDATA%\foxyz\Starsync\logs`; Settings → About → "Open logs
|
||||
folder" finds it anywhere), with the hosted server's lines
|
||||
in the same file; a dedicated server prints its folder at start
|
||||
(`--log-dir`). Users send theirs with Settings → About → "Copy
|
||||
@@ -259,7 +265,7 @@ rasterizer: missing or blocked GPU drivers, `LIBGL_ALWAYS_SOFTWARE=1`);
|
||||
no usable EGL context: check `render env:` for an X11 session or a
|
||||
`GDK_BACKEND` / `FLUTTER_LINUX_RENDERER` override). Its reason is only on
|
||||
stderr: have the user start the app from a terminal
|
||||
(`watch-together 2>&1 | grep VideoOutput`). `hwdec-current=no` on the
|
||||
(`./starsync 2>&1 | grep VideoOutput`). `hwdec-current=no` on the
|
||||
first-frame line means software decoding (no hwdec for that codec, or it
|
||||
is off), not software rendering.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ A five-minute tour. Details: [ARCHITECTURE.md](ARCHITECTURE.md), wire format:
|
||||
|
||||
- **Host from the app**: the app you click Host in also runs the server.
|
||||
Simplest. The server lives as long as that app.
|
||||
- **Dedicated server**: `watch-together-server`, a separate program in the
|
||||
- **Dedicated server**: `starsync-server`, a separate program in the
|
||||
release tarball, for an always-on box. See the README.
|
||||
|
||||
Friends join either way with Join a friend in the strip at the top of the
|
||||
|
||||
+14
-14
@@ -85,15 +85,6 @@ the automatic continuation and countdown, relay state), the device
|
||||
(client id, library and folders, match corrections, watch history,
|
||||
settings, notification prefs, what this app is sourcing) and the
|
||||
integrations (Jellyfin played/resume, AniList list).
|
||||
R. Rename (before step 1, so dev builds install side by side with 1.2.x):
|
||||
app id `dev.foxyz.starsync`, binary, Windows company `foxyz`; Hive out
|
||||
of `~/Documents` into the app's support folder, copied not moved;
|
||||
a settings schema version with ordered migrations; `AppDirs` (today
|
||||
Hive and logs, and `STARSYNC_PROFILE`) becomes a port and the default
|
||||
moves next to the profiles;
|
||||
the 1.3.0 archive still contains `watch_together(.exe)` so 1.2.x's
|
||||
self-update restart works; the old `.desktop` entry removed; the
|
||||
manifest kept at the old URL; VPS `ExecStart`/`update.sh` paths.
|
||||
1. Connection + Identity + Presence; proto 16 opened (version ranges on
|
||||
both sides, refusal frame, identity, grace, presence, relay resume,
|
||||
ids in the feed); later steps add fields, it is frozen at the 1.3.0
|
||||
@@ -161,9 +152,14 @@ proto 16 together at the 1.3.0 release. Rooms are out (no room id).
|
||||
No Windows dev builds: restructure testing happens on Linux; Windows
|
||||
friends stay on 1.2.x until the 1.3.0 release (Windows-only fixes like
|
||||
P30 reach them then).
|
||||
Rename to Starsync everywhere (repo, app id, data folder, updater URL
|
||||
migration) is its own step; app id `dev.foxyz.starsync`, Windows
|
||||
company name `foxyz` (replacing Flutter's default `com.example`). Auto
|
||||
Left of the rename (app, binaries, archives and data folder are
|
||||
Starsync): the repository (`Foxyz/sync_replay_project`) and with it the
|
||||
manifest and asset URLs (a new manifest URL needs a release that reads
|
||||
both first); the dedicated server's fallback folder
|
||||
`~/.cache/watch-together`, the release token file
|
||||
`~/.config/watch-together-release-token`, Jellyfin's client name "Watch
|
||||
Together" (devices are listed under it) and `WatchTogetherApp`; dropping
|
||||
the 1.2.x launchers from the archive once nobody updates from 1.2.x. Auto
|
||||
sit-out: idle or minimised for a while sets you Away, activity sets you
|
||||
In; it replaces the 10-minute auto-unready.
|
||||
|
||||
@@ -338,8 +334,12 @@ over `wss://`/`https://` (`/health.tls`); apps use `wss://` when offered,
|
||||
5. **Ops**: Check shaders on Windows; the relay e2e "source drops
|
||||
uncleanly and resumes" fails about half the time under the full suite.
|
||||
|
||||
6. **Windows: first real use.** CI builds and publishes
|
||||
`watch-together-<ver>-windows-x64.zip` (libmpv bundled) and runs the
|
||||
6. **Windows: first real use.** Check the rename at 1.3.0: a 1.2.x
|
||||
install updates and restarts (`watch_together.exe`, a copy of
|
||||
`starsync.exe`), the data in `%APPDATA%\foxyz\Starsync` came over from
|
||||
`%APPDATA%\com.example\watch_together` and Documents, the next update
|
||||
restarts `starsync.exe`. CI builds and publishes
|
||||
`starsync-<ver>-windows-x64.zip` (libmpv bundled) and runs the
|
||||
updater tests on NTFS; a friend has joined from it. Still unchecked:
|
||||
fullscreen controls, hosting (firewall prompt), in-app update from one
|
||||
release to the next. The rest of the desktop tests are not in CI.
|
||||
|
||||
Reference in new issue
Block a user