Compare commits

...

1 Commits

Author SHA1 Message Date
Codex d8826152c6 Allow bounded playback to buffer ahead of the browser 2026-10-06 23:08:40 +08:00
8 changed files with 13 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
# v0.1.42 · 回放预缓冲调整
- 允许有限录像片段提前完成转换,减少逐秒限速造成的播放器缓冲等待。
- 继续使用最多 5 分钟的分段播放、自动续播、两路转换并发、单线程处理及有界临时缓存。
- 保留家谱全屏稳定性修复、30 天录像保留上限、磁盘容量保护和长暂停后的原位置恢复。
+1 -1
View File
@@ -1 +1 @@
0.1.41 0.1.42
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "zhao-steward-ui", "name": "zhao-steward-ui",
"private": true, "private": true,
"version": "0.1.41", "version": "0.1.42",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
+1 -1
View File
@@ -15,6 +15,6 @@ export function enhance(root){
export async function loadControllers(){ export async function loadControllers(){
enhance(document.getElementById('app')) enhance(document.getElementById('app'))
new MutationObserver(records=>{for(const record of records)for(const node of record.addedNodes)enhance(node)}).observe(document.getElementById('app'),{childList:true,subtree:true}) new MutationObserver(records=>{for(const record of records)for(const node of record.addedNodes)enhance(node)}).observe(document.getElementById('app'),{childList:true,subtree:true})
for(const path of [...scripts,'/vue-bridge.js'])await new Promise((resolve,reject)=>{const script=document.createElement('script');script.src=path+'?ui=0.1.41';script.onload=resolve;script.onerror=()=>reject(new Error('Could not load '+path));document.head.append(script)}) for(const path of [...scripts,'/vue-bridge.js'])await new Promise((resolve,reject)=>{const script=document.createElement('script');script.src=path+'?ui=0.1.42';script.onload=resolve;script.onerror=()=>reject(new Error('Could not load '+path));document.head.append(script)})
await window.ZhaoVue.boot() await window.ZhaoVue.boot()
} }
+1 -1
View File
@@ -73,7 +73,7 @@ def command(source, authorization, duration):
'-tune', 'zerolatency', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-tune', 'zerolatency', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p',
'-crf', '26', '-g', '20', '-bf', '0'] '-crf', '26', '-g', '20', '-bf', '0']
input_options = (['-rw_timeout', '15000000', '-headers', 'Authorization: ' + authorization + '\r\n'] input_options = (['-rw_timeout', '15000000', '-headers', 'Authorization: ' + authorization + '\r\n']
if authorization else ['-readrate', '1']) if authorization else [])
return [executable, '-hide_banner', '-loglevel', 'error', '-nostdin', return [executable, '-hide_banner', '-loglevel', 'error', '-nostdin',
'-threads', '1', '-filter_threads', '1'] + acceleration + input_options + [ '-threads', '1', '-filter_threads', '1'] + acceleration + input_options + [
'-analyzeduration', '1000000', '-probesize', '1000000', '-analyzeduration', '1000000', '-probesize', '1000000',
+2 -2
View File
@@ -53,10 +53,10 @@ class PlaybackCacheTests(unittest.TestCase):
self.assertEqual((fresh/'source.mp4').read_bytes(),b'active') self.assertEqual((fresh/'source.mp4').read_bytes(),b'active')
self.assertEqual(unrelated.read_text(),'keep') self.assertEqual(unrelated.read_text(),'keep')
def test_local_converter_is_paced_and_has_no_credentials(self): def test_local_converter_can_buffer_ahead_and_has_no_credentials(self):
with patch('playback.shutil.which', return_value='ffmpeg'), patch('playback.os.access', return_value=False): with patch('playback.shutil.which', return_value='ffmpeg'), patch('playback.os.access', return_value=False):
cmd=playback.command('/tmp/private/source.mp4', '', 300) cmd=playback.command('/tmp/private/source.mp4', '', 300)
self.assertIn('-readrate', cmd) self.assertNotIn('-readrate', cmd)
self.assertNotIn('-headers', cmd) self.assertNotIn('-headers', cmd)
self.assertIn('libx264', cmd) self.assertIn('libx264', cmd)
self.assertEqual(cmd[cmd.index('-threads')+1], '1') self.assertEqual(cmd[cmd.index('-threads')+1], '1')
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,3 +1,3 @@
<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="theme-color" content="#244d43"><link rel="icon" href="/zhao-icon.png"><link rel="apple-touch-icon" href="/zhao-icon.png"><title>赵府 · 智能数字管家</title> <script type="module" crossorigin src="/ui/assets/index-F3a-FbDz.js"></script> <!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="theme-color" content="#244d43"><link rel="icon" href="/zhao-icon.png"><link rel="apple-touch-icon" href="/zhao-icon.png"><title>赵府 · 智能数字管家</title> <script type="module" crossorigin src="/ui/assets/index-CSPlB4s9.js"></script>
<link rel="stylesheet" crossorigin href="/ui/assets/index-B2d9n-y0.css"> <link rel="stylesheet" crossorigin href="/ui/assets/index-B2d9n-y0.css">
</head><body><div id="app"></div></body></html> </head><body><div id="app"></div></body></html>