cursedbelt 5.97.0 → 5.99.0

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 (81) hide show
  1. package/dist/react/media/FocusViewer.d.ts.map +1 -1
  2. package/dist/react/media/FocusViewer.js +3 -2
  3. package/dist/react/media/FocusViewer.js.map +1 -1
  4. package/dist/react/media/ImageOriginalToggle.d.ts +22 -0
  5. package/dist/react/media/ImageOriginalToggle.d.ts.map +1 -0
  6. package/dist/react/media/ImageOriginalToggle.js +16 -0
  7. package/dist/react/media/ImageOriginalToggle.js.map +1 -0
  8. package/dist/react/media/VideoPlayer.d.ts.map +1 -1
  9. package/dist/react/media/VideoPlayer.js +9 -3
  10. package/dist/react/media/VideoPlayer.js.map +1 -1
  11. package/dist/react/media/VideoQualitySelect.d.ts +24 -0
  12. package/dist/react/media/VideoQualitySelect.d.ts.map +1 -0
  13. package/dist/react/media/VideoQualitySelect.js +34 -0
  14. package/dist/react/media/VideoQualitySelect.js.map +1 -0
  15. package/dist/react/media/hlsSource.d.ts +14 -2
  16. package/dist/react/media/hlsSource.d.ts.map +1 -1
  17. package/dist/react/media/hlsSource.js +27 -6
  18. package/dist/react/media/hlsSource.js.map +1 -1
  19. package/dist/react/media/imageOriginal.d.ts +69 -0
  20. package/dist/react/media/imageOriginal.d.ts.map +1 -0
  21. package/dist/react/media/imageOriginal.js +98 -0
  22. package/dist/react/media/imageOriginal.js.map +1 -0
  23. package/dist/react/media/imageOriginalEntry.d.ts +9 -0
  24. package/dist/react/media/imageOriginalEntry.d.ts.map +1 -0
  25. package/dist/react/media/imageOriginalEntry.js +9 -0
  26. package/dist/react/media/imageOriginalEntry.js.map +1 -0
  27. package/dist/react/media/index.d.ts +5 -0
  28. package/dist/react/media/index.d.ts.map +1 -1
  29. package/dist/react/media/index.js +6 -0
  30. package/dist/react/media/index.js.map +1 -1
  31. package/dist/react/media/useImageOriginal.d.ts +21 -0
  32. package/dist/react/media/useImageOriginal.d.ts.map +1 -0
  33. package/dist/react/media/useImageOriginal.js +63 -0
  34. package/dist/react/media/useImageOriginal.js.map +1 -0
  35. package/dist/react/media/videoPlayer.css +23 -0
  36. package/dist/react/media/videoQuality.d.ts +113 -0
  37. package/dist/react/media/videoQuality.d.ts.map +1 -0
  38. package/dist/react/media/videoQuality.js +185 -0
  39. package/dist/react/media/videoQuality.js.map +1 -0
  40. package/dist/react/media/vidstackQuality.d.ts +27 -0
  41. package/dist/react/media/vidstackQuality.d.ts.map +1 -0
  42. package/dist/react/media/vidstackQuality.js +51 -0
  43. package/dist/react/media/vidstackQuality.js.map +1 -0
  44. package/dist/react/media-gallery/MediaGallery.d.ts.map +1 -1
  45. package/dist/react/media-gallery/MediaGallery.js +42 -10
  46. package/dist/react/media-gallery/MediaGallery.js.map +1 -1
  47. package/dist/react/media-gallery/mediaGallery.css +42 -0
  48. package/dist/react/media-gallery/mediaGalleryModel.d.ts.map +1 -1
  49. package/dist/react/media-gallery/mediaGalleryModel.js +5 -2
  50. package/dist/react/media-gallery/mediaGalleryModel.js.map +1 -1
  51. package/dist/react/media-gallery/types.d.ts +10 -0
  52. package/dist/react/media-gallery/types.d.ts.map +1 -1
  53. package/dist/react/sharing/SharePanel.d.ts.map +1 -1
  54. package/dist/react/sharing/SharePanel.js +2 -1
  55. package/dist/react/sharing/SharePanel.js.map +1 -1
  56. package/package.json +8 -2
  57. package/scripts/paths.ts +1 -1
  58. package/scripts/styleAreas.ts +2 -1
  59. package/src/react/media/FocusViewer.tsx +9 -1
  60. package/src/react/media/ImageOriginalToggle.tsx +51 -0
  61. package/src/react/media/VideoPlayer.spec.tsx +44 -1
  62. package/src/react/media/VideoPlayer.tsx +17 -3
  63. package/src/react/media/VideoQualitySelect.spec.tsx +47 -0
  64. package/src/react/media/VideoQualitySelect.tsx +81 -0
  65. package/src/react/media/hlsSource.spec.ts +10 -0
  66. package/src/react/media/hlsSource.ts +41 -7
  67. package/src/react/media/imageOriginal.spec.tsx +183 -0
  68. package/src/react/media/imageOriginal.ts +114 -0
  69. package/src/react/media/imageOriginalEntry.ts +8 -0
  70. package/src/react/media/index.ts +9 -0
  71. package/src/react/media/useImageOriginal.ts +97 -0
  72. package/src/react/media/videoPlayer.css +23 -0
  73. package/src/react/media/videoQuality.spec.ts +135 -0
  74. package/src/react/media/videoQuality.ts +248 -0
  75. package/src/react/media/vidstackQuality.tsx +65 -0
  76. package/src/react/media-gallery/MediaGallery.spec.tsx +26 -0
  77. package/src/react/media-gallery/MediaGallery.tsx +57 -17
  78. package/src/react/media-gallery/mediaGallery.css +42 -0
  79. package/src/react/media-gallery/mediaGalleryModel.ts +4 -2
  80. package/src/react/media-gallery/types.ts +10 -0
  81. package/src/react/sharing/SharePanel.tsx +2 -1
@@ -0,0 +1,185 @@
1
+ /**
2
+ * A video's quality choice — YouTube's menu: Auto · Max · each rung — remembered per viewer.
3
+ *
4
+ * ── Why the choice exists (forge task 3868, the owner's ruling of 2026-10-28) ─────────────
5
+ * A ladder's top rung is now the ORIGINAL's own stream wherever the browser can play it
6
+ * (binary-server's `planLadder`: an `o<height>` rung is a stream copy, no loss). hls.js was
7
+ * capped to the player's size (`capLevelToPlayerSize`, task 3219 — *"lower bandwidth usage"*),
8
+ * so a windowed player played 480/720 on any connection, which is the blur the owner kept
9
+ * seeing. Both wishes stand, so they became two choices instead of one setting:
10
+ *
11
+ * | choice | what hls.js does |
12
+ * |---|---|
13
+ * | `auto` | adapts to bandwidth, never above what the player can show (the cap ON) |
14
+ * | `max` | adapts to bandwidth, up to the original, whatever the player's size (the cap OFF) |
15
+ * | a height | that rung, fixed — the nearest rung at or below it on a film without it |
16
+ *
17
+ * ── 🔴 Remembered as a HEIGHT, never as a level index ──────────────────────────────────
18
+ * Every film has its own ladder: index 3 is 1080p on one and the 2160 original on the next.
19
+ * A height means the same thing on every film, and a film whose ladder has no such rung takes
20
+ * the nearest one below it (`levelIndexFor`) — "1080p" on a 720p film is its 720p, not
21
+ * nothing.
22
+ *
23
+ * ── 🔴 Per VIEWER, so `localStorage` ───────────────────────────────────────────────────
24
+ * A phone on cellular and the TV want different answers, and a viewer's device is where the
25
+ * answer belongs; a server-side preference would hand the TV's "Max" to the phone. Every
26
+ * surface reads the one key, so a choice made in the gallery stage carries into the focus
27
+ * viewer and the next film.
28
+ *
29
+ * ── Native HLS cannot choose ────────────────────────────────────────────────────────────
30
+ * Safari and every iPhone play the ladder with no library, and a page has no API to pick a
31
+ * rung there — the browser adapts by itself. The control stays VISIBLE and disabled, with the
32
+ * reason (`NATIVE_HLS_REASON`), per the fleet's one-UI rule.
33
+ */
34
+ /** The one key every player reads and writes. */
35
+ export const VIDEO_QUALITY_KEY = 'cb.video-quality';
36
+ export const NATIVE_HLS_REASON = 'This browser plays the stream itself and picks the quality on its own — Safari and iPhone let a page choose nothing';
37
+ export const NO_LADDER_REASON = 'This video has one quality: it is playing the file itself, not a ladder';
38
+ /** The stored string back into a choice. Anything unreadable is `auto`, the safe default. */
39
+ export function parseVideoQuality(raw) {
40
+ if (raw === 'max')
41
+ return 'max';
42
+ const height = Number(raw);
43
+ return Number.isInteger(height) && height > 0 ? height : 'auto';
44
+ }
45
+ export function serializeVideoQuality(choice) {
46
+ return typeof choice === 'number' ? String(choice) : choice;
47
+ }
48
+ /** Guarded: storage throws in a private window, and is absent in a worker or on the server. */
49
+ function store() {
50
+ try {
51
+ return globalThis.localStorage ?? null;
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ export function readVideoQuality() {
58
+ try {
59
+ return parseVideoQuality(store()?.getItem(VIDEO_QUALITY_KEY));
60
+ }
61
+ catch {
62
+ return 'auto';
63
+ }
64
+ }
65
+ export function writeVideoQuality(choice) {
66
+ try {
67
+ store()?.setItem(VIDEO_QUALITY_KEY, serializeVideoQuality(choice));
68
+ }
69
+ catch {
70
+ /* a full or refused store only means the choice lasts this film */
71
+ }
72
+ }
73
+ /** A rung playlist under an `o<height>/` directory is the original's stream copy. */
74
+ const ORIGINAL_RUNG = /(^|\/)o\d+\/[^/]*$/;
75
+ /** The ladder's rungs, tallest first, one per height. */
76
+ export function rungLevels(levels) {
77
+ const byHeight = new Map();
78
+ for (const level of levels) {
79
+ const height = level.height ?? 0;
80
+ if (height <= 0)
81
+ continue;
82
+ const uri = (level.uri ?? level.url?.[0] ?? '').split('?')[0] ?? '';
83
+ const original = ORIGINAL_RUNG.test(uri);
84
+ const had = byHeight.get(height);
85
+ byHeight.set(height, { height, original: original || (had?.original ?? false) });
86
+ }
87
+ return [...byHeight.values()].sort((a, b) => b.height - a.height);
88
+ }
89
+ /**
90
+ * The hls.js level a choice plays: `-1` (adaptive) for `auto` and `max`, else the rung of that
91
+ * height — or the tallest below it, or the shortest when every rung is taller.
92
+ */
93
+ export function levelIndexFor(levels, choice) {
94
+ if (typeof choice !== 'number' || levels.length === 0)
95
+ return -1;
96
+ let best = -1;
97
+ let shortest = -1;
98
+ levels.forEach((level, index) => {
99
+ const height = level.height ?? 0;
100
+ if (shortest === -1 || height < (levels[shortest]?.height ?? 0))
101
+ shortest = index;
102
+ if (height <= choice && (best === -1 || height > (levels[best]?.height ?? 0)))
103
+ best = index;
104
+ });
105
+ return best === -1 ? shortest : best;
106
+ }
107
+ /** A control that can choose nothing, with the reason. */
108
+ export function unavailableQuality(reason) {
109
+ return { levels: [], choice: readVideoQuality(), playingHeight: null, unavailable: reason, select: writeVideoQuality };
110
+ }
111
+ /** hls.js's event names, as strings, so this module never imports the library. */
112
+ const MANIFEST_PARSED = 'hlsManifestParsed';
113
+ const LEVEL_SWITCHED = 'hlsLevelSwitched';
114
+ /**
115
+ * Drive `hls` by the viewer's remembered choice, and report it.
116
+ *
117
+ * The cap is set before the first fragment (a `max` viewer never loads a capped first rung),
118
+ * and a fixed rung is applied when the manifest is parsed — the first moment the levels exist.
119
+ * A later choice switches with `nextLevel`: the next fragment plays the new rung, and what is
120
+ * already buffered still plays, so changing quality never stalls the picture.
121
+ *
122
+ * Returns the unbind. `engine.destroy()` drops the listeners too; the unbind is for a surface
123
+ * that keeps the engine.
124
+ */
125
+ export function bindHlsQuality(hls, onChange) {
126
+ let choice = readVideoQuality();
127
+ let playingHeight = null;
128
+ // Read through this: an engine that has not parsed a manifest (or a spec's fake) has none.
129
+ const levels = () => hls.levels ?? [];
130
+ hls.capLevelToPlayerSize = choice === 'auto';
131
+ const emit = () => onChange({
132
+ levels: rungLevels(levels()),
133
+ choice,
134
+ playingHeight,
135
+ unavailable: levels().length > 1 ? null : NO_LADDER_REASON,
136
+ select,
137
+ });
138
+ const select = (next) => {
139
+ choice = next;
140
+ writeVideoQuality(next);
141
+ hls.capLevelToPlayerSize = next === 'auto';
142
+ hls.nextLevel = levelIndexFor(levels(), next);
143
+ emit();
144
+ };
145
+ const onParsed = () => {
146
+ const index = levelIndexFor(levels(), choice);
147
+ if (index !== -1)
148
+ hls.currentLevel = index;
149
+ emit();
150
+ };
151
+ const onSwitched = (_event, data) => {
152
+ const level = typeof data?.level === 'number' ? levels()[data.level] : undefined;
153
+ playingHeight = level?.height ?? null;
154
+ emit();
155
+ };
156
+ hls.on(MANIFEST_PARSED, onParsed);
157
+ hls.on(LEVEL_SWITCHED, onSwitched);
158
+ if (levels().length > 0)
159
+ emit();
160
+ return () => {
161
+ hls.off(MANIFEST_PARSED, onParsed);
162
+ hls.off(LEVEL_SWITCHED, onSwitched);
163
+ };
164
+ }
165
+ /** A rung's menu label: `2160p · Original`, `720p`. */
166
+ export function rungLabel(level) {
167
+ return level.original ? `${level.height}p · Original` : `${level.height}p`;
168
+ }
169
+ export function createVideoQualityStore() {
170
+ let current = null;
171
+ const listeners = new Set();
172
+ return {
173
+ get: () => current,
174
+ set: (control) => {
175
+ current = control;
176
+ for (const listener of listeners)
177
+ listener();
178
+ },
179
+ subscribe: (listener) => {
180
+ listeners.add(listener);
181
+ return () => listeners.delete(listener);
182
+ },
183
+ };
184
+ }
185
+ //# sourceMappingURL=videoQuality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"videoQuality.js","sourceRoot":"","sources":["../../../src/react/media/videoQuality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The quality menu on cursedbelt's Vidstack player (forge task 3868) — kept out of
3
+ * `VideoPlayer.tsx` so the `./react/media/video-player` subpath exports what it always did.
4
+ */
5
+ import { type MediaProviderAdapter } from '@vidstack/react';
6
+ import type { DefaultVideoLayoutSlots } from '@vidstack/react/player/layouts/default';
7
+ import { type VideoQualityStore } from './videoQuality.js';
8
+ /**
9
+ * The viewer's quality choice on Vidstack's hls.js (forge task 3868) — the same choice, read from
10
+ * the same key, as every `hlsSource.ts` surface (`videoQuality.ts` has what each one means).
11
+ *
12
+ * 🔴 Auto is capped at the player's size HERE TOO. Vidstack's hls.js ran with the library's
13
+ * defaults, so this stage alone fetched the top rung into any size of player; with that rung now
14
+ * the ORIGINAL (a 4K film's is ~20 Mbps), Auto means the same thing on every surface, and Max is
15
+ * the one remembered choice that lifts the cap.
16
+ *
17
+ * Safari's own HLS (Vidstack's plain `VideoProvider` playing a ladder) and the progressive copy
18
+ * can choose nothing, and say why.
19
+ */
20
+ export declare function bindVidstackQuality(provider: MediaProviderAdapter | null, store: VideoQualityStore, ladder: boolean): void;
21
+ /**
22
+ * Quality beside the settings cog, where YouTube keeps it. It REPLACES Vidstack's own quality
23
+ * submenu (hidden in `videoPlayer.css`): that one has no Max, remembers nothing, and two menus
24
+ * choosing one thing would disagree.
25
+ */
26
+ export declare function qualitySlots(store: VideoQualityStore): DefaultVideoLayoutSlots;
27
+ //# sourceMappingURL=vidstackQuality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vidstackQuality.d.ts","sourceRoot":"","sources":["../../../src/react/media/vidstackQuality.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAEtF,OAAO,EAOL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,EACrC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,OAAO,GACd,IAAI,CAcN;AAQD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,uBAAuB,CAG9E"}
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The quality menu on cursedbelt's Vidstack player (forge task 3868) — kept out of
4
+ * `VideoPlayer.tsx` so the `./react/media/video-player` subpath exports what it always did.
5
+ */
6
+ import { isHLSProvider } from '@vidstack/react';
7
+ import { useSyncExternalStore } from 'react';
8
+ import { bindHlsQuality, NATIVE_HLS_REASON, NO_LADDER_REASON, readVideoQuality, unavailableQuality, } from './videoQuality.js';
9
+ import { VideoQualitySelect } from './VideoQualitySelect.js';
10
+ /**
11
+ * The viewer's quality choice on Vidstack's hls.js (forge task 3868) — the same choice, read from
12
+ * the same key, as every `hlsSource.ts` surface (`videoQuality.ts` has what each one means).
13
+ *
14
+ * 🔴 Auto is capped at the player's size HERE TOO. Vidstack's hls.js ran with the library's
15
+ * defaults, so this stage alone fetched the top rung into any size of player; with that rung now
16
+ * the ORIGINAL (a 4K film's is ~20 Mbps), Auto means the same thing on every surface, and Max is
17
+ * the one remembered choice that lifts the cap.
18
+ *
19
+ * Safari's own HLS (Vidstack's plain `VideoProvider` playing a ladder) and the progressive copy
20
+ * can choose nothing, and say why.
21
+ */
22
+ export function bindVidstackQuality(provider, store, ladder) {
23
+ if (!provider) {
24
+ store.set(null);
25
+ return;
26
+ }
27
+ if (isHLSProvider(provider)) {
28
+ store.set(null);
29
+ provider.config = { ...provider.config, capLevelToPlayerSize: readVideoQuality() === 'auto' };
30
+ provider.onInstance((hls) => {
31
+ bindHlsQuality(hls, store.set);
32
+ });
33
+ return;
34
+ }
35
+ store.set(unavailableQuality(ladder ? NATIVE_HLS_REASON : NO_LADDER_REASON));
36
+ }
37
+ /** The quality menu in the bar, re-rendered by the store alone — see `VideoQualityStore`. */
38
+ function QualitySlot({ store }) {
39
+ const control = useSyncExternalStore(store.subscribe, store.get, store.get);
40
+ return _jsx(VideoQualitySelect, { className: 'cbvp-quality', control: control, fieldStyle: false });
41
+ }
42
+ /**
43
+ * Quality beside the settings cog, where YouTube keeps it. It REPLACES Vidstack's own quality
44
+ * submenu (hidden in `videoPlayer.css`): that one has no Max, remembers nothing, and two menus
45
+ * choosing one thing would disagree.
46
+ */
47
+ export function qualitySlots(store) {
48
+ const pair = { beforeSettingsMenu: _jsx(QualitySlot, { store: store }) };
49
+ return { ...pair, smallLayout: { ...pair }, largeLayout: { ...pair } };
50
+ }
51
+ //# sourceMappingURL=vidstackQuality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vidstackQuality.js","sourceRoot":"","sources":["../../../src/react/media/vidstackQuality.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAA6B,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EACL,cAAc,EAEd,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAqC,EACrC,KAAwB,EACxB,MAAe;IAEf,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IACD,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,QAAQ,CAAC,MAAM,GAAG,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,KAAK,MAAM,EAAE,CAAC;QAC9F,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1B,cAAc,CAAC,GAAkC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,6FAA6F;AAC7F,SAAS,WAAW,CAAC,EAAE,KAAK,EAAgC;IAC1D,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5E,OAAO,KAAC,kBAAkB,IAAC,SAAS,EAAC,cAAc,EAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,GAAI,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,IAAI,GAAG,EAAE,kBAAkB,EAAE,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,GAAI,EAAE,CAAC;IACnE,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;AACzE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../src/react/media-gallery/MediaGallery.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../src/react/media-gallery/MediaGallery.tsx"],"names":[],"mappings":"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"}
@@ -43,6 +43,9 @@ import { DenseGalleryDetail, DenseGalleryShell } from '../media/DenseGalleryShel
43
43
  import { CBGD_BARE_TILE_HEIGHT } from '../media/VirtualMediaGrid.js';
44
44
  import { useGalleryReturn } from './galleryReturn.js';
45
45
  import { useHlsSource } from '../media/hlsSource.js';
46
+ import { VideoQualitySelect } from '../media/VideoQualitySelect.js';
47
+ import { ImageOriginalToggle } from '../media/ImageOriginalToggle.js';
48
+ import { useImageOriginal } from '../media/useImageOriginal.js';
46
49
  import { isRecoverableFault, probeSourceFault, sourceFaultMessage, } from '../media/sourceFault.js';
47
50
  import { HoverScrubVideoThumb, useCanHover } from '../media/HoverScrubVideoThumb.js';
48
51
  import { isPlayPauseSpace } from '../media/playerSpaceKey.js';
@@ -605,12 +608,12 @@ function useStageVolume(ref) {
605
608
  */
606
609
  function NativeVideoStage({ hlsUrl, streamUrl, poster, repeat, onEnded, onFault, }) {
607
610
  const ref = React.useRef(null);
608
- useHlsSource(ref, { hlsUrl, streamUrl }, { ...(onFault ? { onFault } : {}) });
611
+ const quality = useHlsSource(ref, { hlsUrl, streamUrl }, { ...(onFault ? { onFault } : {}) });
609
612
  useStageVolume(ref);
610
- return (_jsx("video", { ref: ref, className: 'cbmg-stage-video', poster: poster, controls: true, autoPlay: true, playsInline: true, loop: repeat,
611
- // A looping element never fires `ended`, so passing both would silently disable
612
- // auto-advance rather than combining the two. See `VideoPlayerProps.loop`.
613
- onEnded: repeat ? undefined : onEnded }));
613
+ return (_jsxs("div", { className: 'cbmg-stage-native', children: [_jsx("video", { ref: ref, className: 'cbmg-stage-video', poster: poster, controls: true, autoPlay: true, playsInline: true, loop: repeat,
614
+ // A looping element never fires `ended`, so passing both would silently disable
615
+ // auto-advance rather than combining the two. See `VideoPlayerProps.loop`.
616
+ onEnded: repeat ? undefined : onEnded }), _jsx(VideoQualitySelect, { className: 'cbmg-stage-quality', control: quality })] }));
614
617
  }
615
618
  /**
616
619
  * The stage for a source that ANSWERED — `404`, `410`, a spent `403`, anything that is not
@@ -674,14 +677,43 @@ function NativeVideoSurface({ item, media, streamUrl, repeat, onEnded, reAsk, })
674
677
  * title — which reads as the archive being broken. {@link probeSourceFault} is the only way
675
678
  * to tell them apart and it runs solely on this path, after the browser has already given up.
676
679
  */
677
- function ImageSurface({ item, url, reAsk, }) {
680
+ function ImageSurface({ item, url, originalUrl, reAsk, }) {
678
681
  const { fault, report } = useSourceFault(reAsk);
682
+ // How wide the picture is DRAWN, and how wide the web copy is — the two numbers that decide
683
+ // whether the original is needed (`useImageOriginal`). The `<img>` is `contain`ed with max
684
+ // sizes, so its own box IS the drawn picture.
685
+ const [drawnWidth, setDrawnWidth] = useState(0);
686
+ const [webWidth, setWebWidth] = useState(0);
687
+ const observer = useRef(null);
688
+ const measure = useCallback((img) => {
689
+ observer.current?.disconnect();
690
+ observer.current = null;
691
+ if (!img || typeof ResizeObserver === 'undefined')
692
+ return;
693
+ observer.current = new ResizeObserver(() => setDrawnWidth(img.clientWidth));
694
+ observer.current.observe(img);
695
+ }, []);
696
+ const original = useImageOriginal({
697
+ src: url,
698
+ originalSrc: originalUrl,
699
+ mime: item.mime,
700
+ name: item.name,
701
+ drawnWidth,
702
+ webWidth,
703
+ });
679
704
  if (fault) {
680
705
  return _jsx(StageSourceFault, { item: item, category: 'image', fault: fault, subject: 'This picture' });
681
706
  }
682
- return (_jsx("div", { className: 'cbgd-stage-img', "data-turned": isTurned(item) ? 'true' : undefined, children: _jsx("img", { src: url, alt: item.name, style: orientationStyle(item), onError: () => {
683
- void probeSourceFault(url).then(report);
684
- } }) }));
707
+ return (_jsxs("div", { className: 'cbgd-stage-img', "data-turned": isTurned(item) ? 'true' : undefined, children: [_jsx("img", { ref: measure, src: original.src, alt: item.name, style: orientationStyle(item), onLoad: (event) => {
708
+ // Only the WEB copy's size is the threshold — the original's is what it is past.
709
+ if (original.src === url)
710
+ setWebWidth(event.currentTarget.naturalWidth);
711
+ setDrawnWidth(event.currentTarget.clientWidth);
712
+ }, onError: () => {
713
+ // The original failing is `useImageOriginal`'s own case (it decodes before the swap);
714
+ // a fault here is the web copy's.
715
+ void probeSourceFault(original.src).then(report);
716
+ } }), _jsx(ImageOriginalToggle, { className: 'cbgd-stage-original', control: original.control })] }));
685
717
  }
686
718
  /** The big stage — the right viewer per category. */
687
719
  function GalleryStage({ item, mediaCache, bytesCache, loadBytes, nativeVideoStage, repeat, onEnded, onStep, canStep, fullscreenOnDoubleClick, fillWindow, onFillWindowChange, }) {
@@ -735,7 +767,7 @@ function GalleryStage({ item, mediaCache, bytesCache, loadBytes, nativeVideoStag
735
767
  return _jsx(StageLoading, { label: resolving ? 'Loading…' : 'Image unavailable.' });
736
768
  // `key`ed on the URL for the reason the video stage is: a new URL — including the one a
737
769
  // re-ask mints — is a new attempt and must not inherit the previous one's fault.
738
- return _jsx(ImageSurface, { item: item, url: media.url, reAsk: refresh }, media.url);
770
+ return _jsx(ImageSurface, { item: item, url: media.url, originalUrl: media.originalUrl, reAsk: refresh }, media.url);
739
771
  }
740
772
  if (category === 'audio') {
741
773
  if (!media.url)