webui: 录制时间范围改用TimePicker,选择时间 (#1211)
* 录制时间范围前端改为选择 * 配置文件注释 * fixx * bug fix * Update TemplateModal.tsx * 修改css
This commit is contained in:
1 parent
a34bcdad6b
commit
4cf8de648c
6 files changed
+75
-54
No files matched your search
@@ -101,7 +101,7 @@ export interface LiveStreamerEntity {
|
||||
upload_id?: number;
|
||||
status?: string | React.ReactNode;
|
||||
format?: string;
|
||||
time_range?: string;
|
||||
time_range?: string | Date[];
|
||||
excluded_keywords?: string[];
|
||||
preprocessor?: Record<'run', string>[];
|
||||
segment_processor?: Record<'run', string>[];
|
||||
|
||||
@@ -78,6 +78,7 @@ const TemplateModal: React.FC<TemplateModalProps> = ({ children, entity, onOk })
|
||||
remark: values?.remark?.trim(),
|
||||
url: values?.url?.trim(),
|
||||
format: values?.format?.trim(),
|
||||
time_range: JSON.stringify(values?.time_range?.map((date: Date) => date.toISOString())),
|
||||
}
|
||||
await onOk(values)
|
||||
setVisible(false)
|
||||
@@ -104,6 +105,15 @@ const TemplateModal: React.FC<TemplateModalProps> = ({ children, entity, onOk })
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
if (entity && entity.time_range && typeof entity.time_range === "string") {
|
||||
const tr: string[] = JSON.parse(entity.time_range)
|
||||
entity.time_range = tr.map(t => new Date(t))
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{childrenWithProps}
|
||||
@@ -205,18 +215,29 @@ const TemplateModal: React.FC<TemplateModalProps> = ({ children, entity, onOk })
|
||||
style={{ width: 176 }}
|
||||
helpText="视频保存格式。不支持stream-gears下载器和Youtube平台。"
|
||||
/>
|
||||
|
||||
|
||||
<Collapse keepDOM>
|
||||
<Collapse.Panel header="更多设置" itemKey="processors">
|
||||
<Form.Input
|
||||
<Form.TimePicker
|
||||
field="time_range"
|
||||
type="timeRange"
|
||||
placeholder=" "
|
||||
extraText={
|
||||
<div style={{ fontSize: '14px' }}>
|
||||
格式:'01:00:00-02:00:00'(时:分:秒-时:分:秒)
|
||||
如果设置了录制时间范围,不在时间范围内,将不进行录制<br/>
|
||||
下载器需使用ffmpeg或streamlink
|
||||
</div>
|
||||
}
|
||||
label="录制时间范围"
|
||||
placeholder="01:00:00-02:00:00"
|
||||
label={{
|
||||
text: '录制时间范围',
|
||||
optional: true,
|
||||
style: {
|
||||
fontSize: '18px',
|
||||
marginBottom: '4px',
|
||||
paddingBottom: '8px',
|
||||
borderBottom: '1px solid var(--semi-color-border)',
|
||||
}
|
||||
}}
|
||||
style={{ width: 176 }}
|
||||
/>
|
||||
|
||||
|
||||
+19
-19
@@ -1,7 +1,8 @@
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import httpx
|
||||
from datetime import datetime, time, timezone, timedelta
|
||||
from datetime import datetime, timezone
|
||||
from biliup.config import config
|
||||
import logging
|
||||
|
||||
@@ -32,26 +33,25 @@ logger = logging.getLogger('biliup')
|
||||
|
||||
|
||||
def check_timerange(name):
|
||||
time_range = config['streamers'].get(name, {}).get('time_range')
|
||||
now = datetime.now(tz=timezone(timedelta(hours=8))).time()
|
||||
logger.debug(f"{name}: 校验时间范围 {time_range} 当前时间 {now.strftime('%H:%M:%S')}")
|
||||
|
||||
if not time_range or '-' not in time_range:
|
||||
return True
|
||||
|
||||
try:
|
||||
start_time, end_time = map(time_string_to_time, time_range.split('-'))
|
||||
except (ValueError, IndexError) as e:
|
||||
logger.exception(f"Invalid time range format: {e}")
|
||||
time_range_str = config['streamers'].get(name, {}).get('time_range')
|
||||
if not time_range_str:
|
||||
return True
|
||||
time_range = json.loads(time_range_str)
|
||||
if not isinstance(time_range, (list, tuple)) or len(time_range) != 2:
|
||||
return True
|
||||
|
||||
start = datetime.fromisoformat(time_range[0].replace('Z', '+00:00')).time()
|
||||
end = datetime.fromisoformat(time_range[1].replace('Z', '+00:00')).time()
|
||||
except Exception as e:
|
||||
logger.error(f'parsing time range {e}')
|
||||
return True
|
||||
|
||||
if start_time > end_time:
|
||||
is_in_range = now >= start_time or now <= end_time
|
||||
else:
|
||||
is_in_range = start_time <= now <= end_time
|
||||
return is_in_range
|
||||
now = datetime.now(timezone.utc).time()
|
||||
|
||||
# Normal interval (e.g. 16:00 → 20:00)
|
||||
if start <= end:
|
||||
return start <= now <= end
|
||||
|
||||
def time_string_to_time(time_string):
|
||||
h, m, s = map(int, time_string.split(':'))
|
||||
return time(h, m, s)
|
||||
# Cross‑midnight (e.g. 23:00 → 04:00)
|
||||
return now >= start or now <= end
|
||||
+27
-27
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
@@ -11,7 +12,7 @@ import shutil
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import AsyncGenerator, List, Callable, Optional
|
||||
from urllib.parse import urlparse
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import requests
|
||||
from requests.utils import DEFAULT_ACCEPT_ENCODING
|
||||
@@ -599,41 +600,40 @@ def get_valid_filename(name):
|
||||
return s
|
||||
|
||||
|
||||
def get_duration(segment_time_str, time_range):
|
||||
def get_duration(segment_time_str, time_range_str):
|
||||
"""
|
||||
计算当前时间到给定结束时间的时差
|
||||
如果计算的时差大于segment_time,则返回segment_time。
|
||||
"""
|
||||
if not time_range or '-' not in time_range:
|
||||
return segment_time_str
|
||||
end_time_str = time_range.split('-')[1]
|
||||
|
||||
now = datetime.now()
|
||||
end_time_today_str = now.strftime("%Y-%m-%d") + " " + end_time_str
|
||||
end_time_today = datetime.strptime(end_time_today_str, "%Y-%m-%d %H:%M:%S")
|
||||
# 判断结束时间是否是第二天的时间
|
||||
if now > end_time_today:
|
||||
end_time_today += timedelta(days=1)
|
||||
|
||||
time_diff = end_time_today - now
|
||||
if segment_time_str:
|
||||
segment_time_parts = list(map(int, segment_time_str.split(":")))
|
||||
segment_time = timedelta(hours=segment_time_parts[0],
|
||||
minutes=segment_time_parts[1], seconds=segment_time_parts[2])
|
||||
|
||||
if time_diff > segment_time:
|
||||
try:
|
||||
time_range = json.loads(time_range_str)
|
||||
if not isinstance(time_range, (list, tuple)) or len(time_range) != 2:
|
||||
return segment_time_str
|
||||
end_time = datetime.fromisoformat(time_range[1].replace('Z', '+00:00')).time()
|
||||
except Exception as e:
|
||||
return segment_time_str
|
||||
|
||||
# 增加10s,防止time_diff过小多次执行下载
|
||||
if time_diff.total_seconds() <= 60:
|
||||
time_diff = time_diff + timedelta(seconds=10)
|
||||
now = datetime.now(timezone.utc).time()
|
||||
now_sec = now.hour * 3600 + now.minute * 60 + now.second
|
||||
end_sec = end_time.hour * 3600 + end_time.minute * 60 + end_time.second
|
||||
|
||||
hours, remainder = divmod(time_diff.total_seconds(), 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
# 计算到结束时间的秒数
|
||||
diff = end_sec - now_sec if end_sec >= now_sec else (24 * 3600 - now_sec + end_sec)
|
||||
|
||||
to_parameter = f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"
|
||||
try:
|
||||
h, m, s = map(int, segment_time_str.split(':'))
|
||||
segment_sec = h * 3600 + m * 60 + s
|
||||
except Exception:
|
||||
return segment_time_str
|
||||
|
||||
return to_parameter
|
||||
if diff > segment_sec:
|
||||
return segment_time_str
|
||||
|
||||
hours = diff // 3600
|
||||
minutes = (diff % 3600) // 60
|
||||
seconds = diff % 60
|
||||
|
||||
return f"{hours:02}:{minutes:02}:{seconds:02}"
|
||||
|
||||
|
||||
class BatchCheck(ABC):
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ user_cookie = "cookies.json" ### 使用指定的账号上传
|
||||
#use_live_cover = true # 获取BILIBILI直播间封面并作为投稿封面。此封面优先级低于单个主播指定的自定义封面。
|
||||
tags = ["biliup", "视频标签"]
|
||||
#format = "mp4" ### 视频保存格式。如需使用mp4格式,必须切换downloader为ffmpeg或者streamlink,youtube不支持。
|
||||
#time_range = "01:00:00-23:00:00" ### 录制时间范围
|
||||
#time_range: "[\"2025-03-26T16:00:00.000Z\",\"2025-03-27T15:59:59.000Z\"]" ### 录制时间范围 ISO 8601 格式的时间数组字符串
|
||||
#excluded_keywords: ### 如果房间名包含关键词,则停止或不录制该场直播,每个关键词需单独一行
|
||||
### 开始下载直播时触发,将按自定义顺序执行自定义操作 注:preprocessor仅支持shell指令
|
||||
#preprocessor = [
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ streamers:
|
||||
tags:
|
||||
- biliup
|
||||
- 视频标签
|
||||
#time_range: "01:00:00-23:00:00" ### 录制时间范围
|
||||
#time_range: "[\"2025-03-26T16:00:00.000Z\",\"2025-03-27T15:59:59.000Z\"]" ### 录制时间范围 ISO 8601 格式的时间数组字符串
|
||||
#excluded_keywords: ### 如果房间名包含关键词,则停止或不录制该场直播,每个关键词需单独一行
|
||||
#preprocessor: ### 开始下载直播时触发,将按自定义顺序执行自定义操作 注:preprocessor仅支持shell指令
|
||||
#- run: sh ./run.sh, ### 执行任意命令,等同于在shell中运行,preprocessor输出的数据为JSON格式,包含主播名字(name)、开播地址(url)和开播时间(start_time)(时间戳)
|
||||
|
||||
Reference in new issue
Block a user