plex-tui 0.4.2__tar.gz → 0.4.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/post-release-homebrew.yml +120 -3
  2. {plex_tui-0.4.2 → plex_tui-0.4.3}/AGENTS.md +9 -0
  3. {plex_tui-0.4.2 → plex_tui-0.4.3}/CHANGELOG.md +12 -0
  4. {plex_tui-0.4.2 → plex_tui-0.4.3}/PACKAGING.md +16 -6
  5. {plex_tui-0.4.2 → plex_tui-0.4.3}/PKG-INFO +11 -5
  6. {plex_tui-0.4.2 → plex_tui-0.4.3}/README.md +10 -4
  7. {plex_tui-0.4.2 → plex_tui-0.4.3}/RELEASE.md +11 -4
  8. {plex_tui-0.4.2 → plex_tui-0.4.3}/ROADMAP.md +4 -2
  9. {plex_tui-0.4.2 → plex_tui-0.4.3}/config.example.toml +5 -1
  10. plex_tui-0.4.3/docs/homebrew-install-time.md +171 -0
  11. {plex_tui-0.4.2 → plex_tui-0.4.3}/packaging/aur/.SRCINFO +3 -3
  12. {plex_tui-0.4.2 → plex_tui-0.4.3}/packaging/aur/PKGBUILD +2 -2
  13. {plex_tui-0.4.2 → plex_tui-0.4.3}/packaging/homebrew/README.md +12 -3
  14. {plex_tui-0.4.2 → plex_tui-0.4.3}/pyproject.toml +1 -1
  15. {plex_tui-0.4.2 → plex_tui-0.4.3}/scripts/check_release.py +38 -0
  16. plex_tui-0.4.3/scripts/measure_homebrew_install.py +154 -0
  17. plex_tui-0.4.3/scripts/prepare_homebrew_bottle_assets.py +70 -0
  18. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/__init__.py +1 -1
  19. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/app.py +33 -12
  20. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/config.py +1 -0
  21. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_app_helpers.py +8 -5
  22. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_app_navigation.py +26 -12
  23. plex_tui-0.4.3/tests/test_homebrew_bottle_assets.py +72 -0
  24. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_release_checks.py +27 -0
  25. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/aur.yml +0 -0
  26. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/bump.yml +0 -0
  27. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/ci.yml +0 -0
  28. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/post-release-aur.yml +0 -0
  29. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/publish-aur.yml +0 -0
  30. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/publish-pypi.yml +0 -0
  31. {plex_tui-0.4.2 → plex_tui-0.4.3}/.github/workflows/publish-testpypi.yml +0 -0
  32. {plex_tui-0.4.2 → plex_tui-0.4.3}/.gitignore +0 -0
  33. {plex_tui-0.4.2 → plex_tui-0.4.3}/LICENSE +0 -0
  34. {plex_tui-0.4.2 → plex_tui-0.4.3}/Makefile +0 -0
  35. {plex_tui-0.4.2 → plex_tui-0.4.3}/docs/assets/grid-view.png +0 -0
  36. {plex_tui-0.4.2 → plex_tui-0.4.3}/docs/assets/list-view.png +0 -0
  37. {plex_tui-0.4.2 → plex_tui-0.4.3}/docs/plex-integration-research.md +0 -0
  38. {plex_tui-0.4.2 → plex_tui-0.4.3}/packaging/aur/README.md +0 -0
  39. {plex_tui-0.4.2 → plex_tui-0.4.3}/scripts/stage_release.py +0 -0
  40. {plex_tui-0.4.2 → plex_tui-0.4.3}/scripts/update_aur_package.py +0 -0
  41. {plex_tui-0.4.2 → plex_tui-0.4.3}/scripts/update_homebrew_formula.py +0 -0
  42. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/__main__.py +0 -0
  43. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/artwork.py +0 -0
  44. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/auth.py +0 -0
  45. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/models.py +0 -0
  46. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/player.py +0 -0
  47. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/plex_service.py +0 -0
  48. {plex_tui-0.4.2 → plex_tui-0.4.3}/src/plextui/smoke.py +0 -0
  49. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_artwork.py +0 -0
  50. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_auth.py +0 -0
  51. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_cli.py +0 -0
  52. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_config.py +0 -0
  53. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_player.py +0 -0
  54. {plex_tui-0.4.2 → plex_tui-0.4.3}/tests/test_plex_service.py +0 -0
@@ -13,6 +13,7 @@ on:
13
13
 
14
14
  env:
15
15
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
16
+ HOMEBREW_NO_REQUIRE_TAP_TRUST: "1"
16
17
 
17
18
  jobs:
18
19
  publish-tap:
@@ -133,14 +134,127 @@ jobs:
133
134
  "${{ steps.tap.outputs.path }}/Formula/plex-tui.rb" \
134
135
  "${{ steps.release.outputs.version }}"
135
136
 
136
- - name: Audit formula
137
+ - name: Check tap update need
137
138
  if: steps.release.outputs.publish == 'true'
139
+ id: tap-update
140
+ working-directory: ${{ steps.tap.outputs.path }}
141
+ env:
142
+ VERSION: ${{ steps.release.outputs.version }}
143
+ run: |
144
+ set -euo pipefail
145
+
146
+ bottle_release="plex-tui-${VERSION}"
147
+ bottle_root_url="https://github.com/so1omon563/homebrew-plex-tui/releases/download/${bottle_release}"
148
+ needed=false
149
+
150
+ if ! git diff --quiet -- Formula/plex-tui.rb; then
151
+ needed=true
152
+ fi
153
+
154
+ if ! grep -Fq "root_url \"${bottle_root_url}\"" Formula/plex-tui.rb; then
155
+ needed=true
156
+ fi
157
+
158
+ {
159
+ echo "needed=${needed}"
160
+ echo "bottle_release=${bottle_release}"
161
+ echo "bottle_root_url=${bottle_root_url}"
162
+ } >> "$GITHUB_OUTPUT"
163
+
164
+ if [ "$needed" = "false" ]; then
165
+ echo "Homebrew tap is already up to date with bottle metadata."
166
+ fi
167
+
168
+ - name: Build Homebrew bottle
169
+ if: steps.release.outputs.publish == 'true' && steps.tap-update.outputs.needed == 'true'
170
+ id: bottle
171
+ timeout-minutes: 60
172
+ working-directory: ${{ steps.tap.outputs.path }}
173
+ env:
174
+ BOTTLE_ROOT_URL: ${{ steps.tap-update.outputs.bottle_root_url }}
175
+ VERSION: ${{ steps.release.outputs.version }}
176
+ run: |
177
+ set -euo pipefail
178
+
179
+ brew --version
180
+ brew config
181
+ brew info so1omon563/plex-tui/plex-tui
182
+
183
+ (
184
+ while true; do
185
+ sleep 60
186
+ echo "Still building Homebrew bottle for plex-tui ${VERSION} at $(date -u +%Y-%m-%dT%H:%M:%SZ)."
187
+ done
188
+ ) &
189
+ heartbeat_pid=$!
190
+ trap 'kill "$heartbeat_pid" 2>/dev/null || true' EXIT
191
+
192
+ brew uninstall --ignore-dependencies so1omon563/plex-tui/plex-tui >/dev/null 2>&1 || true
193
+ brew install --verbose --build-bottle so1omon563/plex-tui/plex-tui
194
+ kill "$heartbeat_pid" 2>/dev/null || true
195
+ trap - EXIT
196
+
197
+ rm -f plex-tui--*.bottle.json plex-tui--*.bottle.tar.gz
198
+ brew bottle \
199
+ --json \
200
+ --no-rebuild \
201
+ --root-url "$BOTTLE_ROOT_URL" \
202
+ so1omon563/plex-tui/plex-tui
203
+
204
+ bottle_json="$(find "$PWD" -maxdepth 1 -name 'plex-tui--*.bottle.json' -print -quit)"
205
+ if [ -z "$bottle_json" ]; then
206
+ echo "brew bottle did not produce bottle JSON" >&2
207
+ exit 1
208
+ fi
209
+
210
+ bottle_dir="${RUNNER_TEMP}/homebrew-bottles"
211
+ rm -rf "$bottle_dir"
212
+ mkdir -p "$bottle_dir"
213
+ python "${GITHUB_WORKSPACE}/scripts/prepare_homebrew_bottle_assets.py" \
214
+ "$bottle_json" \
215
+ --output-dir "$bottle_dir"
216
+
217
+ brew bottle --merge --write --no-commit "$bottle_json"
218
+
219
+ {
220
+ echo "json_path=${bottle_json}"
221
+ echo "upload_dir=${bottle_dir}"
222
+ } >> "$GITHUB_OUTPUT"
223
+
224
+ - name: Publish Homebrew bottle assets
225
+ if: steps.release.outputs.publish == 'true' && steps.tap-update.outputs.needed == 'true'
226
+ working-directory: ${{ steps.bottle.outputs.upload_dir }}
227
+ env:
228
+ GH_TOKEN: ${{ secrets.PACKAGING_PR_TOKEN }}
229
+ VERSION: ${{ steps.release.outputs.version }}
230
+ BOTTLE_RELEASE: ${{ steps.tap-update.outputs.bottle_release }}
231
+ run: |
232
+ set -euo pipefail
233
+
234
+ if gh release view "$BOTTLE_RELEASE" --repo so1omon563/homebrew-plex-tui >/dev/null 2>&1; then
235
+ gh release edit "$BOTTLE_RELEASE" \
236
+ --repo so1omon563/homebrew-plex-tui \
237
+ --title "plex-tui ${VERSION} Homebrew bottle"
238
+ else
239
+ gh release create "$BOTTLE_RELEASE" \
240
+ --repo so1omon563/homebrew-plex-tui \
241
+ --target main \
242
+ --title "plex-tui ${VERSION} Homebrew bottle" \
243
+ --notes "Homebrew bottle assets for plex-tui ${VERSION}."
244
+ fi
245
+
246
+ gh release upload "$BOTTLE_RELEASE" ./* \
247
+ --repo so1omon563/homebrew-plex-tui \
248
+ --clobber
249
+
250
+ - name: Audit formula
251
+ if: steps.release.outputs.publish == 'true' && steps.tap-update.outputs.needed == 'true'
138
252
  working-directory: ${{ steps.tap.outputs.path }}
139
253
  run: |
140
254
  brew audit --strict --online so1omon563/plex-tui/plex-tui
141
255
 
142
256
  - name: Commit tap update
143
- if: steps.release.outputs.publish == 'true'
257
+ if: steps.release.outputs.publish == 'true' && steps.tap-update.outputs.needed == 'true'
144
258
  id: commit
145
259
  working-directory: ${{ steps.tap.outputs.path }}
146
260
  env:
@@ -172,15 +286,18 @@ jobs:
172
286
  GH_TOKEN: ${{ secrets.PACKAGING_PR_TOKEN }}
173
287
  VERSION: ${{ steps.release.outputs.version }}
174
288
  BRANCH: ${{ steps.commit.outputs.branch }}
289
+ BOTTLE_RELEASE: ${{ steps.tap-update.outputs.bottle_release }}
175
290
  run: |
176
291
  set -euo pipefail
177
292
 
293
+ pr_body="$(printf 'Automated Homebrew tap update for plex-tui %s.\n\nIncludes the generated bottle metadata for %s.\n' "$VERSION" "$BOTTLE_RELEASE")"
294
+
178
295
  pr_url="$(gh pr create \
179
296
  --repo so1omon563/homebrew-plex-tui \
180
297
  --base main \
181
298
  --head "$BRANCH" \
182
299
  --title "Update plex-tui to ${VERSION}" \
183
- --body "Automated Homebrew tap update for plex-tui ${VERSION}.")"
300
+ --body "$pr_body")"
184
301
 
185
302
  gh pr merge "$pr_url" \
186
303
  --repo so1omon563/homebrew-plex-tui \
@@ -184,6 +184,11 @@ Pull requests should include:
184
184
  Use PRs for repository changes. When publishing local commits, branch from
185
185
  `main` with a scoped name such as `codex/release-prep`, push that branch, and
186
186
  open a draft PR instead of pushing directly to `main`.
187
+ Create or switch to a scoped branch before doing repo work; do not keep feature
188
+ work in the local `main` working tree.
189
+ Repo work is not complete when a branch is merely pushed. Treat the workflow as
190
+ open until there is a draft PR for the branch or the work is explicitly
191
+ canceled.
187
192
 
188
193
  `main` is protected by repository rulesets. Changes must flow through PRs; force
189
194
  pushes and branch deletion are blocked. `plex-tui` requires the Python 3.11 and
@@ -198,6 +203,10 @@ merge should create the GitHub Release and publish package channels. Exceptions
198
203
  are allowed for packaging-only follow-ups, automation repair, docs-only
199
204
  maintenance, or other changes that should not create a new version tag; call out
200
205
  the reason in the PR body when omitting a bump marker.
206
+ When a change is judged release-worthy, do not only add `#release`: run the
207
+ scripted release prep in the same branch and keep the release marker in the PR
208
+ title. A release decision means both staged release files and a publishing
209
+ marker are required unless the release is explicitly canceled.
201
210
 
202
211
  When preparing or estimating a release version, fetch remote tags first with
203
212
  `git fetch --tags origin` and base the decision on the latest origin tag, not
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.4.3 - 2026-06-18
6
+
7
+ - Made the default `mpv` window open with `--autofit=80%`, keeping custom
8
+ Settings overrides for exact pixel sizes or other percentage presets, and
9
+ made the old `1280x720` preset cycle back to Default.
10
+ - Added Homebrew bottle publishing to the post-release tap automation so macOS
11
+ installs can pour a prebuilt `plex-tui` virtualenv instead of rebuilding
12
+ Python resources from source, with bounded verbose CI diagnostics for bottle
13
+ builds.
14
+ - Documented that Homebrew bottles are published for Apple Silicon macOS, while
15
+ Intel macOS remains supported through Homebrew's source-build path.
16
+
5
17
  ## 0.4.2 - 2026-06-18
6
18
 
7
19
  - Prefer episode stills and season posters for TV artwork while keeping show art
@@ -51,8 +51,12 @@ brew install plex-tui
51
51
  ```
52
52
 
53
53
  The formula depends on `mpv` and `python@3.13`, then installs the Python app in
54
- a Homebrew-managed virtualenv. The first install can take several minutes
55
- because native Python resources such as `pillow` are built from source.
54
+ a Homebrew-managed virtualenv. Post-release automation publishes Homebrew
55
+ bottles for Apple Silicon macOS so supported installs can pour the prebuilt app
56
+ virtualenv instead of rebuilding Python resources such as `pillow` from source.
57
+ Intel macOS remains supported through Homebrew's source install path while that
58
+ platform continues to be supported. If no matching bottle is available,
59
+ Homebrew falls back to the source install path.
56
60
  Homebrew 6 requires non-official taps to be trusted before Homebrew loads
57
61
  formulae from them. The `plex-tui` formula only uses Homebrew/core formula
58
62
  dependencies, so users do not need to trust any additional taps for `mpv`,
@@ -65,6 +69,10 @@ brew test so1omon563/plex-tui/plex-tui
65
69
  brew audit --strict --online so1omon563/plex-tui/plex-tui
66
70
  ```
67
71
 
72
+ Install-time investigation lives in `docs/homebrew-install-time.md`. Use
73
+ `scripts/measure_homebrew_install.py` to capture no-op upgrade, reinstall,
74
+ fresh-install, and bottle-pour timings before changing the tap formula.
75
+
68
76
  ### Arch AUR
69
77
 
70
78
  AUR package:
@@ -95,8 +103,8 @@ Validation is handled by `.github/workflows/aur.yml`, which runs inside
95
103
  For each new app release:
96
104
 
97
105
  1. Publish and validate PyPI.
98
- 2. Let the `Post-release Homebrew Publish` workflow update, validate, and merge
99
- the Homebrew tap formula.
106
+ 2. Let the `Post-release Homebrew Publish` workflow update, bottle, validate,
107
+ and merge the Homebrew tap formula.
100
108
  3. Let the `Post-release AUR Update` workflow update AUR metadata, open the
101
109
  packaging PR, approve it, and enable auto-merge.
102
110
  4. After the packaging PR merges and the `AUR Package` workflow passes on
@@ -111,9 +119,11 @@ The AUR automation requires:
111
119
  `ssh://aur@aur.archlinux.org/plex-tui.git`.
112
120
 
113
121
  The Homebrew automation uses `PACKAGING_PR_TOKEN`; that token must also be able
114
- to push branches and merge pull requests in `so1omon563/homebrew-plex-tui`.
122
+ to create or update GitHub Releases, upload bottle assets, push branches, and
123
+ merge pull requests in `so1omon563/homebrew-plex-tui`.
115
124
 
116
125
  ## Known Follow-Up
117
126
 
118
- - Investigate faster Homebrew installs without compromising formula quality.
127
+ - Continue validating Homebrew bottle publishing on release dry-runs and
128
+ follow-up packaging PRs.
119
129
  - Consider standalone artifacts only after the app behavior stabilizes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plex-tui
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: A small standalone Plex terminal UI.
5
5
  Project-URL: Homepage, https://github.com/so1omon563/plex-tui
6
6
  Project-URL: Issues, https://github.com/so1omon563/plex-tui/issues
@@ -108,9 +108,11 @@ brew install plex-tui
108
108
  plex-tui --smoke
109
109
  ```
110
110
 
111
- The Homebrew formula installs `mpv` automatically. The first install can take
112
- several minutes because native Python dependencies such as `pillow` are built
113
- from source.
111
+ The Homebrew formula installs `mpv` automatically. Apple Silicon macOS installs
112
+ use prebuilt bottles when available so Homebrew can pour the app virtualenv
113
+ instead of rebuilding native Python dependencies such as `pillow` from source.
114
+ Intel macOS installs still use Homebrew's source-build path while that platform
115
+ continues to be supported.
114
116
  Homebrew 6 requires non-official taps to be trusted before Homebrew loads
115
117
  formulae from them. `plex-tui` only depends on formulae from Homebrew/core, so no
116
118
  additional tap trust is required for its dependencies.
@@ -204,7 +206,11 @@ preferences are applied when matching streams are available, and the details
204
206
  pane shows the effective playback choices. Playback mode defaults to
205
207
  direct/default behavior and can be changed in Settings to force Plex
206
208
  transcoding with Original, 1080p 8 Mbps, 720p 4 Mbps, or 480p 2 Mbps quality
207
- presets.
209
+ presets. The default `mpv` launch uses `--autofit=80%` so videos open at a
210
+ comfortable size on modern displays; Settings can override this with values
211
+ such as `90%`, `1280x720`, or `80%x80%`. If an older config has an exact
212
+ `mpv_window_size = "1280x720"` override, cycle the mpv window-size setting once
213
+ to return to the Default preset.
208
214
 
209
215
  ## Key Bindings
210
216
 
@@ -71,9 +71,11 @@ brew install plex-tui
71
71
  plex-tui --smoke
72
72
  ```
73
73
 
74
- The Homebrew formula installs `mpv` automatically. The first install can take
75
- several minutes because native Python dependencies such as `pillow` are built
76
- from source.
74
+ The Homebrew formula installs `mpv` automatically. Apple Silicon macOS installs
75
+ use prebuilt bottles when available so Homebrew can pour the app virtualenv
76
+ instead of rebuilding native Python dependencies such as `pillow` from source.
77
+ Intel macOS installs still use Homebrew's source-build path while that platform
78
+ continues to be supported.
77
79
  Homebrew 6 requires non-official taps to be trusted before Homebrew loads
78
80
  formulae from them. `plex-tui` only depends on formulae from Homebrew/core, so no
79
81
  additional tap trust is required for its dependencies.
@@ -167,7 +169,11 @@ preferences are applied when matching streams are available, and the details
167
169
  pane shows the effective playback choices. Playback mode defaults to
168
170
  direct/default behavior and can be changed in Settings to force Plex
169
171
  transcoding with Original, 1080p 8 Mbps, 720p 4 Mbps, or 480p 2 Mbps quality
170
- presets.
172
+ presets. The default `mpv` launch uses `--autofit=80%` so videos open at a
173
+ comfortable size on modern displays; Settings can override this with values
174
+ such as `90%`, `1280x720`, or `80%x80%`. If an older config has an exact
175
+ `mpv_window_size = "1280x720"` override, cycle the mpv window-size setting once
176
+ to return to the Default preset.
171
177
 
172
178
  ## Key Bindings
173
179
 
@@ -124,9 +124,15 @@ be run manually with a release tag. It updates:
124
124
  - Formula URL and sha256.
125
125
  - Python resource blocks if dependencies changed.
126
126
  - Formula test expectations if version output changed.
127
+ - Homebrew bottle assets and the generated formula `bottle do` block.
127
128
 
128
- It then runs `brew audit --strict --online`, opens a tap PR, and merges it. This
129
- uses `PACKAGING_PR_TOKEN`, which must have access to the tap repository.
129
+ It builds the formula with `brew install --build-bottle`, generates bottle
130
+ metadata with `brew bottle --json`, uploads the bottle tarball to a
131
+ `plex-tui-X.Y.Z` GitHub Release in the tap repository, merges the generated
132
+ `bottle do` block into the formula, runs `brew audit --strict --online`, opens a
133
+ tap PR, and merges it. This uses `PACKAGING_PR_TOKEN`, which must have access to
134
+ create releases, upload assets, push branches, and merge pull requests in the
135
+ tap repository.
130
136
 
131
137
  If the automated workflow cannot run, update and validate manually:
132
138
 
@@ -186,8 +192,9 @@ To verify post-release packaging without publishing a new app release, manually
186
192
  dispatch the post-release workflows with the latest real release tag, for
187
193
  example `v0.3.6`. A healthy idempotent run should:
188
194
 
189
- - update and audit the Homebrew formula, then skip tap PR creation when there is
190
- no diff;
195
+ - update, bottle, and audit the Homebrew formula when bottle metadata is
196
+ missing; then skip tap PR creation on later reruns when the formula and bottle
197
+ block are already current;
191
198
  - regenerate and validate AUR metadata, then skip packaging PR auto-merge when
192
199
  there is no diff.
193
200
 
@@ -32,8 +32,10 @@
32
32
  requires the Python 3.11 and 3.13 checks before merge. Rulesets require PRs
33
33
  with zero approving reviews so automation branches can merge after checks
34
34
  without self-approval.
35
- - Improve Homebrew install time; the current formula works but builds native
36
- Python resources such as `pillow` from source.
35
+ - Improve Homebrew install time; baseline the current install/update paths with
36
+ `scripts/measure_homebrew_install.py`, then prioritize tap bottle automation.
37
+ The current formula works but builds Python resources from source, with
38
+ native compilation concentrated in `pillow`.
37
39
  - Keep post-release package publishing fully automated across PyPI, Homebrew,
38
40
  and AUR. Periodically dry-run existing release tags through the post-release
39
41
  workflows to confirm Homebrew and AUR no-op cleanly when already current.
@@ -14,7 +14,11 @@ client_identifier = "plex-tui-your-stable-client-id"
14
14
  # preferred_subtitle_language = "eng"
15
15
  # subtitle_mode can be "auto", "none", or "preferred".
16
16
  # subtitle_mode = "preferred"
17
- # Optional mpv window size passed as --autofit. Examples: "1280x720", "80%".
17
+ # Optional mpv window size passed as --autofit. Empty uses the app default
18
+ # "80%" for a more comfortable window on modern displays.
19
+ # Examples: "90%", "1280x720", "80%x80%".
20
+ # Existing exact-size overrides such as "1280x720" stay exact until reset or
21
+ # changed in Settings.
18
22
  # mpv_window_size = "1280x720"
19
23
  # playback_mode can be "auto" for direct/default playback or "transcode" to
20
24
  # force Plex transcoding.
@@ -0,0 +1,171 @@
1
+ # Homebrew Install-Time Investigation
2
+
3
+ The current Homebrew formula is correct for a Python application: it uses
4
+ `Language::Python::Virtualenv`, declares `python@3.13`, and installs explicit
5
+ Python `resource` blocks into a Homebrew-managed virtualenv. The slow path is
6
+ therefore expected formula work, not a known correctness bug.
7
+
8
+ ## Current Hypothesis
9
+
10
+ Fresh installs are slow because Homebrew installs the app from source resources.
11
+ Most dependencies are pure Python, but `pillow` is a native dependency and is
12
+ the most likely expensive build. Even no-op updates can feel slow because
13
+ Homebrew still evaluates the tap, dependency state, Python resources, and the
14
+ installed virtualenv before deciding there is little to do.
15
+
16
+ Baseline measurements on Apple silicon with `plex-tui 0.4.2`:
17
+
18
+ | Scenario | Auto-update | Result |
19
+ | --- | --- | ---: |
20
+ | `brew upgrade plex-tui` no-op | disabled | 0.5s |
21
+ | `brew upgrade plex-tui` no-op | enabled | 4.7s |
22
+ | `brew reinstall plex-tui` from source | disabled | 49.6s |
23
+ | `brew install plex-tui` after uninstall | disabled | 49.6s |
24
+ | `brew install --force-bottle plex-tui` from local bottle | disabled | 3.3s |
25
+ | `brew test plex-tui` | n/a | 3.0s |
26
+
27
+ The source install output reported `/opt/homebrew/Cellar/plex-tui/0.4.2` was
28
+ "built in 47 seconds". The local bottle prototype avoided that build and poured
29
+ successfully in 3.3 seconds, then passed `brew test`.
30
+
31
+ Separate these timing buckets before changing packaging:
32
+
33
+ - Homebrew overhead: auto-update, tap loading, dependency resolution, and audit
34
+ checks.
35
+ - System dependencies: `mpv` and `python@3.13` installation or upgrades.
36
+ - App resources: Python source resources installed into `libexec`.
37
+ - Native compilation: currently expected to be dominated by `pillow`.
38
+ - Post-install checks: `brew test` and smoke execution.
39
+
40
+ ## Dependency Layers
41
+
42
+ A truly first-time Homebrew install has two dependency layers:
43
+
44
+ - Formula dependencies: `mpv` and `python@3.13`, plus their recursive Homebrew
45
+ dependencies. On the measured machine these were already installed, but
46
+ `brew deps --installed so1omon563/plex-tui/plex-tui` listed the full runtime
47
+ stack, including `ffmpeg`, `vapoursynth`, `yt-dlp`, and many media libraries
48
+ below `mpv`.
49
+ - Python resources: the formula vendors every Python dependency into
50
+ `plex-tui`'s Homebrew-managed virtualenv. These resources are absent from a
51
+ fresh `plex-tui` install even if the user has similar packages elsewhere.
52
+
53
+ The Python resources currently installed by the formula are:
54
+
55
+ - `certifi`
56
+ - `charset-normalizer`
57
+ - `idna`
58
+ - `linkify-it-py`
59
+ - `markdown-it-py`
60
+ - `mdit-py-plugins`
61
+ - `mdurl`
62
+ - `pillow`
63
+ - `platformdirs`
64
+ - `PlexAPI`
65
+ - `Pygments`
66
+ - `requests`
67
+ - `rich`
68
+ - `textual`
69
+ - `typing-extensions`
70
+ - `uc-micro-py`
71
+ - `urllib3`
72
+
73
+ Homebrew logs from a `--build-bottle` install showed each Python resource being
74
+ built as a wheel from its source resource. Only `pillow` produced native
75
+ extensions and a compiler log. The installed virtualenv contains Pillow
76
+ extension modules such as `PIL/_imaging*.so`, and `brew linkage plex-tui` shows
77
+ links to `freetype`, `jpeg-turbo`, `libtiff`, and `little-cms2`.
78
+
79
+ ## Measurement Script
80
+
81
+ Use the local measurement helper from the repository root:
82
+
83
+ ```bash
84
+ python3 scripts/measure_homebrew_install.py --help
85
+ ```
86
+
87
+ Measure a no-op update path without changing the installed formula:
88
+
89
+ ```bash
90
+ python3 scripts/measure_homebrew_install.py --upgrade --test --output /tmp/plex-tui-brew-noop.json
91
+ ```
92
+
93
+ Measure a reinstall of the current formula:
94
+
95
+ ```bash
96
+ python3 scripts/measure_homebrew_install.py --reinstall --test --output /tmp/plex-tui-brew-reinstall.json
97
+ ```
98
+
99
+ Measure a fresh formula install after uninstalling only `plex-tui`:
100
+
101
+ ```bash
102
+ python3 scripts/measure_homebrew_install.py --fresh-install --test --output /tmp/plex-tui-brew-fresh.json
103
+ ```
104
+
105
+ Measure a bottle-pour path after adding a valid `bottle do` block to the tap
106
+ formula:
107
+
108
+ ```bash
109
+ python3 scripts/measure_homebrew_install.py --fresh-install --force-bottle --test --output /tmp/plex-tui-brew-bottle.json
110
+ ```
111
+
112
+ By default, the script sets `HOMEBREW_NO_AUTO_UPDATE=1` so measurements focus on
113
+ the formula and dependency work. Add `--allow-auto-update` when measuring the
114
+ full user-facing command cost.
115
+
116
+ ## Candidate Improvements
117
+
118
+ ### Bottle The Tap
119
+
120
+ Build and publish Homebrew bottles for `so1omon563/homebrew-plex-tui`, then add
121
+ a `bottle do` block to the formula. Homebrew automatically downloads a matching
122
+ bottle when one exists, which should avoid rebuilding the virtualenv and native
123
+ resources during ordinary installs.
124
+
125
+ This is the highest-impact path for first-install time in the current
126
+ measurement. A local `arm64_tahoe` bottle for `0.4.2` was 3.1MB, relocatable
127
+ with `cellar: :any`, and poured in 3.3 seconds. It requires a tap-side bottle
128
+ workflow, storage for bottle artifacts, formula `bottle do` updates, and
129
+ verification on the supported macOS runners.
130
+
131
+ ### Reduce Runtime Dependencies
132
+
133
+ Review whether any dependency can move from required runtime to an optional
134
+ feature. `pillow` is the main candidate because it enables rich artwork paths
135
+ but also brings native build cost. Removing or optionalizing it would require a
136
+ deliberate app fallback so Homebrew users do not lose expected artwork behavior
137
+ silently.
138
+
139
+ This path can improve both Homebrew and PyPI installs, but it changes app
140
+ capability and needs product judgment.
141
+
142
+ ### Keep The Formula Source-Based
143
+
144
+ Keep `virtualenv_install_with_resources` unchanged and improve docs only. This
145
+ preserves the simplest, most standard formula and avoids bottle automation, but
146
+ it does not solve the initial-install pain.
147
+
148
+ ### Standalone Artifacts
149
+
150
+ Standalone app artifacts could bypass Python resource installation entirely, but
151
+ they are a larger distribution project. Keep this behind bottle exploration
152
+ unless app packaging requirements change.
153
+
154
+ ## Next Slice
155
+
156
+ 1. Capture baseline timings for no-op upgrade, reinstall, and fresh install on
157
+ Apple silicon. Done for `0.4.2`.
158
+ 2. Prototype bottle creation in the tap repo and compare bottle-pour timing
159
+ against the baseline. Done locally for `arm64_tahoe`.
160
+ 3. Add tap automation that builds bottles, uploads them to a release asset, and
161
+ merges the generated `bottle do` block. Implemented in the post-release
162
+ Homebrew workflow.
163
+ 4. Keep optional `pillow` dependency reduction as a secondary path if bottle
164
+ automation proves too brittle.
165
+ 5. Update `PACKAGING.md` and the tap README once bottle automation is proven.
166
+
167
+ ## References
168
+
169
+ - Homebrew Bottles: https://docs.brew.sh/Bottles
170
+ - Homebrew Python formula guidance:
171
+ https://docs.brew.sh/Python-for-Formula-Authors
@@ -1,6 +1,6 @@
1
1
  pkgbase = plex-tui
2
2
  pkgdesc = Standalone Plex terminal UI with mpv playback
3
- pkgver = 0.4.1
3
+ pkgver = 0.4.2
4
4
  pkgrel = 1
5
5
  url = https://github.com/so1omon563/plex-tui
6
6
  arch = any
@@ -16,7 +16,7 @@ pkgbase = plex-tui
16
16
  depends = python-plexapi
17
17
  depends = python-rich
18
18
  depends = python-textual
19
- source = plex-tui-0.4.1.tar.gz::https://github.com/so1omon563/plex-tui/archive/refs/tags/v0.4.1.tar.gz
20
- sha256sums = 2271c6413ec204ba1250b812e6b9e98af37afaeb44006d5c17fb0f82cf419282
19
+ source = plex-tui-0.4.2.tar.gz::https://github.com/so1omon563/plex-tui/archive/refs/tags/v0.4.2.tar.gz
20
+ sha256sums = 0d7832319a5468a89ed4eeb2dd0bad543663922f215765f40490d9e67723dac7
21
21
 
22
22
  pkgname = plex-tui
@@ -1,6 +1,6 @@
1
1
  # Maintainer: so1omon
2
2
  pkgname=plex-tui
3
- pkgver=0.4.1
3
+ pkgver=0.4.2
4
4
  pkgrel=1
5
5
  pkgdesc="Standalone Plex terminal UI with mpv playback"
6
6
  arch=("any")
@@ -22,7 +22,7 @@ makedepends=(
22
22
  "python-wheel"
23
23
  )
24
24
  source=("$pkgname-$pkgver.tar.gz::$url/archive/refs/tags/v$pkgver.tar.gz")
25
- sha256sums=("2271c6413ec204ba1250b812e6b9e98af37afaeb44006d5c17fb0f82cf419282")
25
+ sha256sums=("0d7832319a5468a89ed4eeb2dd0bad543663922f215765f40490d9e67723dac7")
26
26
 
27
27
  build() {
28
28
  cd "$pkgname-$pkgver"
@@ -22,12 +22,21 @@ For each `plex-tui` release:
22
22
 
23
23
  1. Update the formula URL and sha256 for the new PyPI sdist.
24
24
  2. Refresh Python resource blocks if dependencies changed.
25
- 3. Run:
25
+ 3. Build and publish a Homebrew bottle, then merge the generated `bottle do`
26
+ block into the formula.
27
+ 4. Run:
26
28
 
27
29
  ```bash
28
30
  brew test so1omon563/plex-tui/plex-tui
29
31
  brew audit --strict --online so1omon563/plex-tui/plex-tui
30
32
  ```
31
33
 
32
- The current formula is correct but slow on first install because native Python
33
- resources such as `pillow` are built from source.
34
+ The source formula is correct but slow on first install because native Python
35
+ resources such as `pillow` are built from source. Release automation publishes
36
+ Apple Silicon macOS bottles so supported installs can pour a prebuilt
37
+ virtualenv. Intel macOS continues to use Homebrew's source-build path while that
38
+ platform remains supported.
39
+
40
+ Install-time investigation notes and the baseline measurement helper live in the
41
+ main repo at `docs/homebrew-install-time.md` and
42
+ `scripts/measure_homebrew_install.py`.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plex-tui"
7
- version = "0.4.2"
7
+ version = "0.4.3"
8
8
  description = "A small standalone Plex terminal UI."
9
9
  readme = "README.md"
10
10
  license = "MIT"