files: Ham Share's player — Auto quality, any by hand, or the file; 360 view; Transcode device setting
Every video plays YouTube's way: hls.js reads the connection and picks the quality, or one is picked by hand, or Original plays the file as it is. The qualities (a ladder by size, H.264) are made on the fly in 3 s pieces from wherever the viewer seeks, one ffmpeg per play, paused when far enough ahead. 360 videos open in a look-around view (drag, pinch or scroll to zoom from 8 to 300 degrees, phone motion). Settings -> Transcode device picks the machine and device that makes them, for every machine's files: a machine transcoding another's file reads it through the hub by a token for that one file. Replaces the codec/size picker and the single-quality re-encoder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f5f1cd79ba
commit
fc4126a0ed
+45
-7
@@ -145,6 +145,9 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
|
||||
.svc-tools { padding: 10px; display: flex; flex-direction: column; gap: 8px; border-bottom: 1px solid var(--border); }
|
||||
.svc-tools input { padding: 8px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-size: 14px; }
|
||||
.chip.on { color: var(--fg); border-color: var(--accent); } .chip.bad { color: var(--bad); }
|
||||
.chip.off { opacity: .55; cursor: default; } .chip.off:hover { color: var(--muted); border-color: var(--border); }
|
||||
.tc-list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.tc-host { font-weight: 600; margin-bottom: 6px; }
|
||||
.svc-rows { flex: 1; overflow-y: auto; }
|
||||
.svc-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; cursor: pointer; border-bottom: 1px solid var(--border); }
|
||||
.svc-row:hover { background: var(--bg3); } .svc-row.active { background: var(--bg3); box-shadow: inset 3px 0 0 var(--accent); }
|
||||
@@ -365,13 +368,48 @@ h2.section { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted);
|
||||
.preview { flex: 1; display: flex; align-items: center; justify-content: center; overflow: auto; padding: 12px; }
|
||||
.preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
|
||||
.preview video { max-width: 100%; max-height: 100%; background: #000; border-radius: 4px; outline: none; }
|
||||
.player { flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
||||
.player .preview { flex: 1; min-height: 0; }
|
||||
.play-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 6px 12px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--border); }
|
||||
.play-bar select { padding: 4px 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 5px; color: var(--fg); font-size: 12px; }
|
||||
.play-pick { margin: 12px; }
|
||||
.play-pick .row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
|
||||
.play-pick label { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
|
||||
/* the video player (Player.tsx): Ham Share's, in the viewer; full screen is the browser's, or
|
||||
on an iPhone the whole window */
|
||||
.vp { position: relative; flex: 1; min-height: 240px; background: #000; color: #fff; overflow: hidden; user-select: none; -webkit-user-select: none; outline: none; }
|
||||
.vp.max { position: fixed; inset: 0; z-index: 1000; }
|
||||
.vp-v { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: #000; }
|
||||
.vp-hidden { opacity: 0; pointer-events: none; }
|
||||
.vp-sphere { touch-action: none; cursor: grab; }
|
||||
.vp-sphere:active { cursor: grabbing; }
|
||||
.vp-bottom { position: absolute; left: 0; right: 0; bottom: 0; padding: 26px 8px calc(env(safe-area-inset-bottom) + 4px); background: linear-gradient(transparent, rgba(0, 0, 0, .75)); transition: opacity .25s; z-index: 2; }
|
||||
.vp.bare .vp-bottom, .vp.bare .vp-hint { opacity: 0; pointer-events: none; }
|
||||
.vp.bare { cursor: none; }
|
||||
.vp-row { display: flex; align-items: center; gap: 4px; }
|
||||
.vp-icon { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 19px; color: #fff; }
|
||||
.vp-icon:hover { background: rgba(255, 255, 255, .14); }
|
||||
.vp-icon.on { color: var(--accent); }
|
||||
.vp-time { font-size: 13px; font-variant-numeric: tabular-nums; padding: 0 6px; white-space: nowrap; }
|
||||
.vp-q { display: inline-flex; align-items: center; gap: 6px; padding: 7px 10px; border-radius: 17px; font-size: 13px; font-weight: 600; white-space: nowrap; color: #fff; }
|
||||
.vp-q:hover { background: rgba(255, 255, 255, .14); }
|
||||
.vp-seek { position: relative; height: 24px; margin: 0 8px; display: flex; align-items: center; }
|
||||
.vp-seek::before { content: ''; position: absolute; left: 0; right: 0; height: 4px; border-radius: 2px;
|
||||
background: linear-gradient(to right, var(--accent) var(--p), rgba(255, 255, 255, .45) var(--p) var(--b), rgba(255, 255, 255, .2) var(--b)); }
|
||||
.vp-seek input { position: relative; width: 100%; margin: 0; background: transparent; border: 0; padding: 0; height: 24px; -webkit-appearance: none; appearance: none; cursor: pointer; }
|
||||
.vp-seek input::-webkit-slider-runnable-track { height: 4px; background: transparent; }
|
||||
.vp-seek input::-moz-range-track { height: 4px; background: transparent; }
|
||||
.vp-seek input::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; margin-top: -5px; border-radius: 50%; background: var(--accent); border: 0; }
|
||||
.vp-seek input::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--accent); border: 0; }
|
||||
.vp-big { position: absolute; left: 50%; top: 50%; width: 68px; height: 68px; margin: -34px 0 0 -34px; border-radius: 50%; display: grid; place-items: center; background: rgba(0, 0, 0, .55); color: #fff; z-index: 2; padding-left: 4px; }
|
||||
.vp-spin { position: absolute; left: 50%; top: 50%; width: 46px; height: 46px; margin: -23px 0 0 -23px; border-radius: 50%; border: 4px solid rgba(255, 255, 255, .2); border-top-color: var(--accent); animation: vp-spin .8s linear infinite; z-index: 1; pointer-events: none; }
|
||||
@keyframes vp-spin { to { transform: rotate(360deg); } }
|
||||
.vp-err { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px; text-align: center; z-index: 1; }
|
||||
.vp-err p { margin: 0; max-width: 460px; line-height: 1.45; }
|
||||
.vp-note { position: absolute; left: 50%; top: 14px; transform: translateX(-50%); max-width: min(92%, 480px); padding: 9px 13px; border-radius: 8px; background: rgba(20, 20, 20, .92); font-size: 13px; line-height: 1.4; z-index: 3; cursor: pointer; }
|
||||
.vp-hint { position: absolute; left: 50%; bottom: 86px; transform: translateX(-50%); padding: 5px 11px; border-radius: 14px; background: rgba(0, 0, 0, .55); font-size: 12px; pointer-events: none; transition: opacity .25s; z-index: 1; white-space: nowrap; }
|
||||
.vp-menu { position: absolute; right: 8px; bottom: 60px; width: min(290px, calc(100% - 16px)); max-height: calc(100% - 76px); overflow-y: auto; padding: 6px; border-radius: 10px; background: rgba(24, 24, 24, .96); box-shadow: 0 8px 30px rgba(0, 0, 0, .5); z-index: 4; }
|
||||
.vp-menu-h { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: rgba(255, 255, 255, .55); padding: 6px 10px 4px; }
|
||||
.vp-menu button { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px; border-radius: 6px; text-align: left; font-size: 14px; color: #fff; }
|
||||
.vp-menu button:hover:not(:disabled) { background: rgba(255, 255, 255, .1); }
|
||||
.vp-menu button:disabled { opacity: .45; }
|
||||
.vp-menu button small { margin-left: auto; color: rgba(255, 255, 255, .6); font-size: 12px; white-space: nowrap; }
|
||||
.vp-menu .ck { width: 16px; flex: none; color: var(--accent); display: grid; place-items: center; }
|
||||
.vp-menu-f { border-top: 1px solid rgba(255, 255, 255, .12); margin-top: 6px; padding: 8px 10px 4px; font-size: 12px; color: rgba(255, 255, 255, .6); line-height: 1.4; }
|
||||
.vp-menu-f b { color: #fff; font-weight: 600; }
|
||||
.preview.audio { align-items: flex-start; }
|
||||
.audio-box { display: flex; flex-direction: column; align-items: center; gap: 10px; width: min(560px, 100%); margin-top: 8vh; }
|
||||
.audio-box .ficon { font-size: 48px; }
|
||||
|
||||
Reference in New Issue
Block a user