2026-10-20 22:08:12 -07:00
|
|
|
# Share a video to QueueCube
|
|
|
|
|
|
|
|
|
|
Open QueueCube once after updating to make saved players available to the share
|
|
|
|
|
extension. In Safari or a video app, share one HTTP(S) link, choose QueueCube,
|
2026-10-21 01:06:45 -07:00
|
|
|
and tap a saved player. The link is appended
|
2026-10-20 22:08:12 -07:00
|
|
|
and played immediately; existing queue entries remain. A successful request
|
|
|
|
|
shows the selected player and a Done button. Video support depends on the
|
|
|
|
|
player's existing mpv/yt-dlp support.
|
|
|
|
|
|
2026-10-21 01:06:45 -07:00
|
|
|
The extension shows only saved players and does not browse for nearby players.
|
|
|
|
|
Add players manually or with Bonjour discovery in QueueCube Settings first.
|
|
|
|
|
Allow local network access in the containing app to reach local players.
|
|
|
|
|
The extension handles URL attachments
|
2026-10-20 22:08:12 -07:00
|
|
|
(including UTF-8 data and the absolute-URL property-list form observed from
|
|
|
|
|
UIKit) and plain text containing one link. URL data keeps the same single-link
|
|
|
|
|
validation; property lists with a nonempty base or properties dictionary and
|
|
|
|
|
unrecognized binary forms are rejected.
|
|
|
|
|
Multiple different links, files, and links
|
|
|
|
|
with embedded user/password information are rejected.
|
|
|
|
|
|
|
|
|
|
## Data and permissions
|
|
|
|
|
|
|
|
|
|
The app and `net.buzzert.QueueCube.Share` extension share
|
|
|
|
|
`group.net.buzzert.QueueCube`. The app retains its original UserDefaults and
|
|
|
|
|
publishes a single versioned settings snapshot on read/save. The extension reads
|
|
|
|
|
that snapshot without changing the app's selected player or server list. No
|
|
|
|
|
queued link, credentials store, background transfer, or keychain group is added.
|
2026-10-21 01:06:45 -07:00
|
|
|
The extension has a local network usage declaration and the same HTTP transport
|
2026-10-20 22:08:12 -07:00
|
|
|
compatibility as the existing app; Catalyst adds only app sandbox and outgoing
|
|
|
|
|
network access.
|
|
|
|
|
|
|
|
|
|
The repository has no application authentication, login flow, or token store.
|
|
|
|
|
Requests reuse the existing URLSession client and configured server URLs.
|
|
|
|
|
Browser login cookies and credentials cached in another process are not shared.
|
|
|
|
|
Servers behind an authenticated reverse proxy may fail; this change does not
|
|
|
|
|
introduce a new authentication protocol or bypass access controls.
|
|
|
|
|
|
|
|
|
|
## Existing API sequence and failure behavior
|
|
|
|
|
|
|
|
|
|
All paths below are relative to the configured API base URL (usually `/api`).
|
|
|
|
|
No backend deployment is required.
|
|
|
|
|
|
|
|
|
|
| Request | Purpose |
|
|
|
|
|
| --- | --- |
|
|
|
|
|
| `GET /playlist` | Snapshot existing mpv item IDs before append. |
|
|
|
|
|
| `POST /playlist` with `{"url":"https://…"}` | Append once using the existing append-play operation. Starts only if idle. |
|
|
|
|
|
| `GET /playlist` | Poll for exactly one new ID matching the URL, then obtain its current zero-based index. |
|
|
|
|
|
| `POST /skip/{index}` | Select the new entry while retaining the queue. |
|
|
|
|
|
| `POST /play` | Clear pause, including on an already paused player. |
|
|
|
|
|
| `GET /nowplaying` | Confirm the new ID is current, is not paused, has no reported playback error, and its playback position advances across reads. |
|
|
|
|
|
|
|
|
|
|
The current server may acknowledge mutations before mpv finishes and may return
|
|
|
|
|
HTTP success even for an mpv failure. The extension verifies reads instead of
|
|
|
|
|
assuming a 2xx response means playback started. A selected but still loading
|
|
|
|
|
item does not count as success; playback position must advance for the intended
|
|
|
|
|
item. Verification polling checks a shared 20-second deadline between operations; each
|
|
|
|
|
HTTP request has an 8-second timeout. In-flight or sequential mutation requests
|
|
|
|
|
can extend completion beyond that window. Slow media may remain queued without
|
|
|
|
|
confirmed playback. This is a point-in-time
|
|
|
|
|
confirmation; media loading or decoding can fail later.
|
|
|
|
|
|
|
|
|
|
If preflight fails, no link has been added and the user can retry. Once append
|
|
|
|
|
has been attempted, any failure is treated as potentially partially completed:
|
|
|
|
|
the UI says either the link may already be queued or it was queued but playback
|
|
|
|
|
was not confirmed. It disables repeat submission for that share session and
|
|
|
|
|
asks the user to check QueueCube before sharing again. It never clears the queue,
|
|
|
|
|
rolls back another client's changes, or automatically retries a mutation.
|
|
|
|
|
|
|
|
|
|
Identical URLs already in the queue are distinguished using mpv IDs. Concurrent
|
|
|
|
|
identical new entries are ambiguous and are not selected. The existing skip API
|
|
|
|
|
uses an index, so another client can reorder the queue between lookup and skip;
|
|
|
|
|
verification catches a different resulting item, but cannot make these existing
|
|
|
|
|
endpoints atomic. No new backend contract is assumed.
|
|
|
|
|
|
|
|
|
|
## Building and validation
|
|
|
|
|
|
|
|
|
|
Build the QueueCube scheme to embed the extension on iOS and Mac Catalyst:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
xcodebuild -project ios/QueueCube.xcodeproj -scheme QueueCube -configuration Debug -destination 'generic/platform=iOS Simulator' -derivedDataPath /tmp/queuecube-build-simulator CODE_SIGNING_ALLOWED=NO build
|
|
|
|
|
xcodebuild -project ios/QueueCube.xcodeproj -scheme QueueCube -configuration Debug -destination 'platform=macOS,variant=Mac Catalyst' -derivedDataPath /tmp/queuecube-build-catalyst CODE_SIGNING_ALLOWED=NO build
|
|
|
|
|
swift test --package-path ios --scratch-path /tmp/queuecube-share-tests
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Unsigned builds validate compilation and embedding; they do not validate App
|
|
|
|
|
Group provisioning. For simulator UI tests of saved players, use normal local
|
|
|
|
|
ad-hoc signing (`CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY=- DEVELOPMENT_TEAM=`)
|
|
|
|
|
so Simulator registers the App Group container. This does not use an Apple
|
|
|
|
|
signing identity or provision a physical device. Before a future signed distribution,
|
|
|
|
|
register the extension ID and associate **both** app IDs with the App Group,
|
|
|
|
|
then update their profiles through the existing signing workflow. Fastlane maps
|
|
|
|
|
`QueueCube AppStore CI` and `QueueCube Share AppStore CI` separately and keeps
|
|
|
|
|
app/extension versions synchronized. Do not apply a single global bundle ID or
|
|
|
|
|
provisioning profile override to both targets.
|
|
|
|
|
|
|
|
|
|
For manual UI validation, use a dedicated simulator or test installation:
|
2026-10-21 01:06:45 -07:00
|
|
|
configure a test player in QueueCube, share a URL from Safari, verify saved-player
|
|
|
|
|
tap-to-play, the empty saved-player state, cancellation, invalid text, and
|
2026-10-20 22:08:12 -07:00
|
|
|
an offline/partially failing player. Confirm the old queue is retained and the
|
|
|
|
|
new item is current and unpaused. On macOS also confirm QueueCube appears in
|
|
|
|
|
Share extensions and can be invoked from a host app. Record signed-device and
|
|
|
|
|
live-player gaps explicitly; unit mocks cannot establish those behaviors.
|