@geekapps/silo-elements-nextjs 0.3.17 → 0.3.18

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.
package/dist/index.js CHANGED
@@ -1536,8 +1536,47 @@ function MediaUploader({
1536
1536
  var AUTO_QUALITY = {
1537
1537
  id: "auto",
1538
1538
  label: "Auto",
1539
- type: "auto"
1539
+ type: "auto",
1540
+ supported: true
1540
1541
  };
1542
+ function deviceSupportsHdr() {
1543
+ if (typeof window === "undefined") return false;
1544
+ try {
1545
+ return window.matchMedia("(dynamic-range: high)").matches;
1546
+ } catch {
1547
+ return false;
1548
+ }
1549
+ }
1550
+ function deviceSupportsOpus() {
1551
+ if (typeof window === "undefined") return false;
1552
+ try {
1553
+ if (typeof MediaSource !== "undefined" && MediaSource.isTypeSupported) {
1554
+ if (MediaSource.isTypeSupported('audio/mp4; codecs="opus"')) return true;
1555
+ }
1556
+ const a = document.createElement("audio");
1557
+ return a.canPlayType('audio/ogg; codecs="opus"') !== "" || a.canPlayType('video/mp4; codecs="opus"') !== "";
1558
+ } catch {
1559
+ return false;
1560
+ }
1561
+ }
1562
+ function deviceSupportsCodec(codecStr) {
1563
+ if (typeof window === "undefined") return true;
1564
+ try {
1565
+ if (typeof MediaSource !== "undefined" && MediaSource.isTypeSupported) {
1566
+ return MediaSource.isTypeSupported(`video/mp4; codecs="${codecStr}"`);
1567
+ }
1568
+ return true;
1569
+ } catch {
1570
+ return true;
1571
+ }
1572
+ }
1573
+ function isHdrLevel(level) {
1574
+ const range = level?.videoRange ?? level?.video_range ?? "";
1575
+ return range === "PQ" || range === "HLG" || range === "HDR10" || typeof level?.name === "string" && /hdr/i.test(level.name);
1576
+ }
1577
+ function isHdrAudioCodec(codecStr) {
1578
+ return /opus/i.test(codecStr);
1579
+ }
1541
1580
  var PLAYBACK_SPEEDS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2];
1542
1581
  function Source(_props) {
1543
1582
  return null;
@@ -2317,23 +2356,28 @@ function Video({
2317
2356
  hls.on(Hls.Events.MANIFEST_PARSED, (_, data) => {
2318
2357
  const levels = data.levels ?? hls.levels ?? [];
2319
2358
  console.debug("[Silo/hls] MANIFEST_PARSED levels=", levels.length, "audioTracks=", hls.audioTracks?.length ?? 0);
2359
+ const hdrSupported = deviceSupportsHdr();
2360
+ const opusSupported = deviceSupportsOpus();
2320
2361
  setQualities([
2321
2362
  AUTO_QUALITY,
2322
- ...levels.map((level, index) => ({
2323
- id: `hls-${index}`,
2324
- label: level.name ?? (level.height ? `${level.height}p` : `${index + 1}`),
2325
- type: "hls",
2326
- index
2327
- }))
2363
+ ...levels.map((level, index) => {
2364
+ const hdr = isHdrLevel(level);
2365
+ const codecStr = level.videoCodec ?? level.attrs?.CODECS ?? "";
2366
+ const supported = hdr ? hdrSupported : deviceSupportsCodec(codecStr);
2367
+ const baseName = level.name ?? (level.height ? `${level.height}p` : `${index + 1}`);
2368
+ const label = hdr ? `${baseName} HDR` : baseName;
2369
+ return { id: `hls-${index}`, label, type: "hls", index, supported, hdr };
2370
+ })
2328
2371
  ]);
2329
2372
  const tracks = hls.audioTracks ?? [];
2330
2373
  console.debug("[Silo/hls] audio tracks:", tracks.map((t) => ({ name: t.name, lang: t.lang, url: t.url })));
2331
2374
  if (tracks.length > 1) {
2332
2375
  setAudioTracks(
2333
- tracks.map((t, i) => ({
2334
- id: i,
2335
- label: t.name ?? t.lang ?? `Track ${i + 1}`
2336
- }))
2376
+ tracks.map((t, i) => {
2377
+ const codec = t.attrs?.CODECS ?? t.codecSet ?? "";
2378
+ const supported = isHdrAudioCodec(codec) ? opusSupported : true;
2379
+ return { id: i, label: t.name ?? t.lang ?? `Track ${i + 1}`, supported };
2380
+ })
2337
2381
  );
2338
2382
  if (pinnedAudio === -1) setSelectedAudio(hls.audioTrack ?? 0);
2339
2383
  }
@@ -2344,12 +2388,14 @@ function Video({
2344
2388
  hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, (_, data) => {
2345
2389
  const tracks = data.audioTracks ?? [];
2346
2390
  console.debug("[Silo/hls] AUDIO_TRACKS_UPDATED", tracks.length);
2391
+ const opusSupported = deviceSupportsOpus();
2347
2392
  if (tracks.length > 1) {
2348
2393
  setAudioTracks(
2349
- tracks.map((t, i) => ({
2350
- id: i,
2351
- label: t.name ?? t.lang ?? `Track ${i + 1}`
2352
- }))
2394
+ tracks.map((t, i) => {
2395
+ const codec = t.attrs?.CODECS ?? t.codecSet ?? "";
2396
+ const supported = isHdrAudioCodec(codec) ? opusSupported : true;
2397
+ return { id: i, label: t.name ?? t.lang ?? `Track ${i + 1}`, supported };
2398
+ })
2353
2399
  );
2354
2400
  }
2355
2401
  if (pinnedAudio >= 0 && hls.audioTrack !== pinnedAudio) {
@@ -3043,48 +3089,56 @@ function Video({
3043
3089
  ]
3044
3090
  }
3045
3091
  ),
3046
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [...qualities].reverse().map((quality) => /* @__PURE__ */ jsxs(
3047
- "button",
3048
- {
3049
- type: "button",
3050
- onClick: () => {
3051
- changeQuality(quality.id);
3052
- setSettingsTab("root");
3053
- },
3054
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
3055
- children: [
3056
- /* @__PURE__ */ jsx(
3057
- "svg",
3058
- {
3059
- className: `size-4 shrink-0 ${selectedQuality === quality.id ? "text-white" : "text-transparent"}`,
3060
- viewBox: "0 0 16 16",
3061
- fill: "none",
3062
- children: /* @__PURE__ */ jsx(
3063
- "path",
3092
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: [...qualities].reverse().map((quality) => {
3093
+ const unavailable = quality.supported === false;
3094
+ return /* @__PURE__ */ jsxs(
3095
+ "button",
3096
+ {
3097
+ type: "button",
3098
+ onClick: () => {
3099
+ if (unavailable) return;
3100
+ changeQuality(quality.id);
3101
+ setSettingsTab("root");
3102
+ },
3103
+ disabled: unavailable,
3104
+ className: `flex w-full items-center gap-3 px-4 py-2.5 text-sm transition ${unavailable ? "cursor-not-allowed opacity-40" : "hover:bg-white/8"}`,
3105
+ children: [
3106
+ /* @__PURE__ */ jsx(
3107
+ "svg",
3108
+ {
3109
+ className: `size-4 shrink-0 ${selectedQuality === quality.id ? "text-white" : "text-transparent"}`,
3110
+ viewBox: "0 0 16 16",
3111
+ fill: "none",
3112
+ children: /* @__PURE__ */ jsx(
3113
+ "path",
3114
+ {
3115
+ d: "M3 8l3.5 3.5L13 4.5",
3116
+ stroke: "currentColor",
3117
+ strokeWidth: "1.8",
3118
+ strokeLinecap: "round",
3119
+ strokeLinejoin: "round"
3120
+ }
3121
+ )
3122
+ }
3123
+ ),
3124
+ /* @__PURE__ */ jsxs("span", { className: "flex-1 text-left", children: [
3125
+ /* @__PURE__ */ jsxs(
3126
+ "span",
3064
3127
  {
3065
- d: "M3 8l3.5 3.5L13 4.5",
3066
- stroke: "currentColor",
3067
- strokeWidth: "1.8",
3068
- strokeLinecap: "round",
3069
- strokeLinejoin: "round"
3128
+ className: selectedQuality === quality.id ? "font-semibold text-white" : "text-white/55",
3129
+ children: [
3130
+ quality.label,
3131
+ quality.id === "auto" ? " (ABR)" : ""
3132
+ ]
3070
3133
  }
3071
- )
3072
- }
3073
- ),
3074
- /* @__PURE__ */ jsxs(
3075
- "span",
3076
- {
3077
- className: selectedQuality === quality.id ? "font-semibold text-white" : "text-white/55",
3078
- children: [
3079
- quality.label,
3080
- quality.id === "auto" ? " (ABR)" : ""
3081
- ]
3082
- }
3083
- )
3084
- ]
3085
- },
3086
- quality.id
3087
- )) })
3134
+ ),
3135
+ unavailable && /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-[10px] text-white/30", children: "N\xE3o dispon\xEDvel" })
3136
+ ] })
3137
+ ]
3138
+ },
3139
+ quality.id
3140
+ );
3141
+ }) })
3088
3142
  ] }),
3089
3143
  settingsTab === "subtitles" && /* @__PURE__ */ jsxs("div", { children: [
3090
3144
  /* @__PURE__ */ jsxs(
@@ -3306,45 +3360,53 @@ function Video({
3306
3360
  ]
3307
3361
  }
3308
3362
  ),
3309
- /* @__PURE__ */ jsx("div", { className: "py-1.5", children: audioTracks.map((track) => /* @__PURE__ */ jsxs(
3310
- "button",
3311
- {
3312
- type: "button",
3313
- onClick: () => {
3314
- changeAudio(track.id);
3315
- setSettingsTab("root");
3316
- },
3317
- className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
3318
- children: [
3319
- /* @__PURE__ */ jsx(
3320
- "svg",
3321
- {
3322
- className: `size-4 shrink-0 ${selectedAudio === track.id ? "text-white" : "text-transparent"}`,
3323
- viewBox: "0 0 16 16",
3324
- fill: "none",
3325
- children: /* @__PURE__ */ jsx(
3326
- "path",
3363
+ /* @__PURE__ */ jsx("div", { className: "py-1.5", children: audioTracks.map((track) => {
3364
+ const unavailable = track.supported === false;
3365
+ return /* @__PURE__ */ jsxs(
3366
+ "button",
3367
+ {
3368
+ type: "button",
3369
+ onClick: () => {
3370
+ if (unavailable) return;
3371
+ changeAudio(track.id);
3372
+ setSettingsTab("root");
3373
+ },
3374
+ disabled: unavailable,
3375
+ className: `flex w-full items-center gap-3 px-4 py-2.5 text-sm transition ${unavailable ? "cursor-not-allowed opacity-40" : "hover:bg-white/8"}`,
3376
+ children: [
3377
+ /* @__PURE__ */ jsx(
3378
+ "svg",
3379
+ {
3380
+ className: `size-4 shrink-0 ${selectedAudio === track.id ? "text-white" : "text-transparent"}`,
3381
+ viewBox: "0 0 16 16",
3382
+ fill: "none",
3383
+ children: /* @__PURE__ */ jsx(
3384
+ "path",
3385
+ {
3386
+ d: "M3 8l3.5 3.5L13 4.5",
3387
+ stroke: "currentColor",
3388
+ strokeWidth: "1.8",
3389
+ strokeLinecap: "round",
3390
+ strokeLinejoin: "round"
3391
+ }
3392
+ )
3393
+ }
3394
+ ),
3395
+ /* @__PURE__ */ jsxs("span", { className: "flex-1 text-left", children: [
3396
+ /* @__PURE__ */ jsx(
3397
+ "span",
3327
3398
  {
3328
- d: "M3 8l3.5 3.5L13 4.5",
3329
- stroke: "currentColor",
3330
- strokeWidth: "1.8",
3331
- strokeLinecap: "round",
3332
- strokeLinejoin: "round"
3399
+ className: selectedAudio === track.id ? "font-semibold text-white" : "text-white/55",
3400
+ children: track.label
3333
3401
  }
3334
- )
3335
- }
3336
- ),
3337
- /* @__PURE__ */ jsx(
3338
- "span",
3339
- {
3340
- className: selectedAudio === track.id ? "font-semibold text-white" : "text-white/55",
3341
- children: track.label
3342
- }
3343
- )
3344
- ]
3345
- },
3346
- track.id
3347
- )) })
3402
+ ),
3403
+ unavailable && /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-[10px] text-white/30", children: "N\xE3o dispon\xEDvel" })
3404
+ ] })
3405
+ ]
3406
+ },
3407
+ track.id
3408
+ );
3409
+ }) })
3348
3410
  ] }),
3349
3411
  settingsTab === "playback" && /* @__PURE__ */ jsxs("div", { children: [
3350
3412
  /* @__PURE__ */ jsxs(