feat: auto slice videos (#151)

* feat: auto slice videos
fix #150
* refactor: add copyright
* docs: update readme
* refactor: adjust icons
* style: adjust style
* style: substitue icons
This commit is contained in:
John Howe
2024-12-30 13:22:17 +08:00
committed by GitHub
parent bcb0aebdb6
commit 4afda49eff
11 changed files with 220 additions and 20 deletions

View File

@@ -4,12 +4,18 @@
<img src="assets/headerLight.svg" alt="BILIVE" />
</picture>
*7 x 24 小时无人监守录制、渲染弹幕、识别字幕、自动上传,启动项目,人人都是录播员。*
*7 x 24 小时无人监守录制、渲染弹幕、识别字幕、自动切片、自动上传,启动项目,人人都是录播员。*
[:page_facing_up: Documentation](https://timerring.github.io/bilive/) |
[:gear: Installation](#quick-start) |
[:thinking: Reporting Issues](https://github.com/timerring/bilive/issues/new/choose)
支持模型
<img src="assets/openai.svg" alt="OpenAI whisper" width="60" height="60" />
<img src="assets/zhipu-color.svg" alt="Zhipu GLM-4V-PLUS" width="60" height="60" />
<img src="assets/gemini-brand-color.svg" alt="Google Gemini 1.5 Pro" width="60" height="60" />
</div>
## 1. Introduction
@@ -29,6 +35,7 @@
- **自动渲染弹幕**自动转换xml为ass弹幕文件并且渲染到视频中形成**有弹幕版视频**并自动上传。
- **硬件要求极低**无需GPU只需最基础的单核CPU搭配最低的运存即可完成录制弹幕渲染上传等等全部过程无最低配置要求10年前的电脑或服务器依然可以使用
- **( :tada: NEW)自动渲染字幕**(如需使用本功能,则需保证有 Nvidia 显卡):采用 OpenAI 的开源模型 [`whisper`](https://github.com/openai/whisper),自动识别视频内语音并转换为字幕渲染至视频中。
- **( :tada: NEW)自动切片上传**:根据弹幕密度计算寻找高能片段并切片,结合多模态视频理解大模型 [`GLM-4V-PLUS`](https://bigmodel.cn/dev/api/normal-model/glm-4) 自动生成有意思的切片标题及内容,并且自动上传。
项目架构流程如下:
@@ -46,8 +53,13 @@ graph TD
ifDanmaku -->|有弹幕| DanmakuFactory[DanmakuFactory]
ifDanmaku -->|无弹幕| ffmpeg1[ffmpeg]
DanmakuFactory[DanmakuFactory] --根据分辨率转换弹幕--> ffmpeg1[ffmpeg]
ffmpeg1[ffmpeg] --渲染弹幕及字幕 --> Video[视频文件]
Video[视频文件] --计算弹幕密度并切片--> GLM[多模态视频理解模型]
GLM[多模态视频理解模型] --生成切片信息--> slice[视频切片]
end
ffmpeg1[ffmpeg] --渲染弹幕及字幕 --> uploadQueue[(上传队列)]
slice[视频切片] --> uploadQueue[(上传队列)]
Video[视频文件] --> uploadQueue[(上传队列)]
User((用户))--upload-->startUpload(启动视频上传进程)
startUpload(启动视频上传进程) <--扫描队列并上传视频--> uploadQueue[(上传队列)]
@@ -110,8 +122,9 @@ pip install -r requirements.txt
./setPath.sh && source ~/.bashrc
```
#### 3. 配置 whisper 模型
#### 3. 配置 whisper 模型及 GLM-4V-PLUS 模型
##### 3.1 whisper 模型
项目默认采用 [`small`](https://openaipublic.azureedge.net/main/whisper/models/9ecf779972d90ba49c06d968637d720dd632c55bbf19d441fb42bf17a411e794/small.pt) 模型,请点击下载所需文件,并放置在 `src/subtitle/models` 文件夹中。
> [!TIP]
@@ -119,6 +132,11 @@ pip install -r requirements.txt
> + 更多模型请参考 [whisper 参数模型](https://timerring.github.io/bilive/models.html) 部分。
> + 更换模型方法请参考 [更换模型方法](https://timerring.github.io/bilive/models.html#更换模型方法) 部分。
##### 3.2 GLM-4V-PLUS 模型
> 此功能默认关闭,如果需要打开请将 `src/config.py` 文件中的 `AUTO_SLICE` 参数设置为 `True`
在配置文件 `src/config.py` 中,`SLICE_DURATION` 以秒为单位设置切片时长(不建议超过 1 分钟),在项目的自动切片功能需要使用到智谱的 [`GLM-4V-PLUS`](https://bigmodel.cn/dev/api/normal-model/glm-4) 模型,请自行[注册账号](https://www.bigmodel.cn/invite?icode=shBtZUfNE6FfdMH1R6NybGczbXFgPRGIalpycrEwJ28%3D)并申请 API Key填写到 `src/config.py` 文件中对应的 `Your_API_KEY` 中。
#### 4. biliup-rs 登录
@@ -176,7 +194,7 @@ logs # 日志文件夹
```
### Installation(无 GPU 版本)
无 GPU 版本过程基本同上,可以跳过步骤 3需要注意在执行步骤 5 **之前**完成以下设置将确保完全用 CPU 渲染视频弹幕。
无 GPU 版本过程基本同上,可以跳过步骤 3 配置 whisper 的部分,需要注意在执行步骤 5 **之前**完成以下设置将确保完全用 CPU 渲染视频弹幕。
1. 请将 `src/config.py` 文件中的 `GPU_EXIST` 参数设置为 `False`。(若不置为 `False` 且则会使用 CPU 推理,不推荐,可自行根据硬件条件进行尝试。)
2.`MODEL_TYPE` 调整为 `merge` 或者 `append`

View File

@@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 64 24" xmlns="http://www.w3.org/2000/svg"><title>Gemini</title><defs><radialGradient cx="67.977%" cy="18.976%" fx="67.977%" fy="18.976%" gradientTransform="scale(-.3667 -1) rotate(-20.122 -1.657 7.14)" id="lobe-icons-gemini-brand-fill" r="192.358%"><stop offset="0%" stop-color="#1C69FF"></stop><stop offset="100%" stop-color="#94BCFE"></stop></radialGradient></defs><path d="M16.759 14.825c0 2.037-.605 3.66-1.815 4.868-1.359 1.439-3.146 2.158-5.36 2.158-2.12 0-3.915-.733-5.383-2.2C2.734 18.187 2 16.38 2 14.236c0-2.145.734-3.95 2.201-5.417C5.67 7.352 7.463 6.62 9.583 6.62c1.074 0 2.086.19 3.037.57.952.38 1.733.917 2.345 1.609l-1.346 1.344c-.448-.543-1.03-.967-1.743-1.273a5.763 5.763 0 00-2.293-.458c-1.59 0-2.935.55-4.036 1.65-1.087 1.113-1.63 2.504-1.63 4.174 0 1.67.543 3.061 1.63 4.175 1.1 1.1 2.446 1.65 4.036 1.65 1.454 0 2.664-.408 3.629-1.223.964-.814 1.522-1.934 1.671-3.36h-5.3v-1.751h7.074c.068.38.102.747.102 1.1m5.886-3.563c1.496 0 2.687.483 3.572 1.45.886.967 1.329 2.32 1.329 4.062l-.021.206h-7.928c.028.987.357 1.783.989 2.386a3.164 3.164 0 002.265.905c1.208 0 2.155-.603 2.841-1.81l1.689.823a5.03 5.03 0 01-1.884 1.995c-.803.48-1.713.72-2.729.72-1.482 0-2.704-.507-3.665-1.522-.96-1.015-1.441-2.297-1.441-3.847 0-1.536.467-2.814 1.4-3.836.934-1.022 2.128-1.532 3.583-1.532m-.041 1.727c-.714 0-1.328.22-1.843.659-.515.438-.855 1.028-1.02 1.769h5.787a2.508 2.508 0 00-.855-1.738c-.515-.46-1.204-.69-2.07-.69m8.049 8.65h-1.89V11.59h1.807v1.395h.083c.287-.492.728-.902 1.324-1.23.595-.328 1.187-.492 1.775-.492.74 0 1.39.17 1.95.512.562.342.972.814 1.232 1.415.835-1.285 1.991-1.927 3.47-1.927 1.163 0 2.06.355 2.689 1.066.63.71.944 1.723.944 3.035v6.275h-1.889v-5.988c0-.943-.17-1.623-.513-2.04-.342-.417-.917-.626-1.724-.626-.726 0-1.334.308-1.827.923-.493.615-.74 1.34-.74 2.174v5.557h-1.888v-5.988c0-.943-.17-1.623-.513-2.04-.342-.417-.917-.626-1.724-.626-.726 0-1.335.308-1.827.923-.493.615-.74 1.34-.74 2.174v5.557zM46.749 6.767c.37 0 .685.13.946.39.26.26.39.575.39.945s-.13.685-.39.945c-.26.26-.576.39-.946.39s-.685-.13-.946-.39c-.26-.26-.39-.575-.39-.945s.13-.685.39-.945c.26-.26.576-.39.946-.39zM42.825 0a5.08 5.08 0 004.263 4.259 5.08 5.08 0 00-4.263 4.259 5.08 5.08 0 00-4.263-4.26A5.08 5.08 0 0042.825 0zm5.176 11.574V21.64h-2.198V11.574h2.198zM62 8.103c0 .37-.13.685-.39.945-.261.26-.576.39-.946.39s-.686-.13-.946-.39c-.26-.26-.391-.575-.391-.945s.13-.685.39-.945c.261-.26.576-.39.946-.39s.686.13.946.39c.26.26.391.575.391.945m-.085 3.471V21.64h-2.197V11.574h2.197zm-12.57.017h1.806v1.394h.082c.287-.492.729-.902 1.324-1.23a3.797 3.797 0 011.858-.492c1.231 0 2.179.352 2.843 1.056.664.704.995 1.705.995 3.004v6.316h-1.888v-6.193c-.041-1.64-.87-2.46-2.484-2.46-.753 0-1.382.303-1.889.912-.506.608-.76 1.336-.76 2.184v5.557h-1.888V11.591z" fill="url(#lobe-icons-gemini-brand-fill)" fill-rule="nonzero"></path></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

1
assets/openai.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenAI</title><path d="M21.55 10.004a5.416 5.416 0 00-.478-4.501c-1.217-2.09-3.662-3.166-6.05-2.66A5.59 5.59 0 0010.831 1C8.39.995 6.224 2.546 5.473 4.838A5.553 5.553 0 001.76 7.496a5.487 5.487 0 00.691 6.5 5.416 5.416 0 00.477 4.502c1.217 2.09 3.662 3.165 6.05 2.66A5.586 5.586 0 0013.168 23c2.443.006 4.61-1.546 5.361-3.84a5.553 5.553 0 003.715-2.66 5.488 5.488 0 00-.693-6.497v.001zm-8.381 11.558a4.199 4.199 0 01-2.675-.954c.034-.018.093-.05.132-.074l4.44-2.53a.71.71 0 00.364-.623v-6.176l1.877 1.069c.02.01.033.029.036.05v5.115c-.003 2.274-1.87 4.118-4.174 4.123zM4.192 17.78a4.059 4.059 0 01-.498-2.763c.032.02.09.055.131.078l4.44 2.53c.225.13.504.13.73 0l5.42-3.088v2.138a.068.068 0 01-.027.057L9.9 19.288c-1.999 1.136-4.552.46-5.707-1.51h-.001zM3.023 8.216A4.15 4.15 0 015.198 6.41l-.002.151v5.06a.711.711 0 00.364.624l5.42 3.087-1.876 1.07a.067.067 0 01-.063.005l-4.489-2.559c-1.995-1.14-2.679-3.658-1.53-5.63h.001zm15.417 3.54l-5.42-3.088L14.896 7.6a.067.067 0 01.063-.006l4.489 2.557c1.998 1.14 2.683 3.662 1.529 5.633a4.163 4.163 0 01-2.174 1.807V12.38a.71.71 0 00-.363-.623zm1.867-2.773a6.04 6.04 0 00-.132-.078l-4.44-2.53a.731.731 0 00-.729 0l-5.42 3.088V7.325a.068.068 0 01.027-.057L14.1 4.713c2-1.137 4.555-.46 5.707 1.513.487.833.664 1.809.499 2.757h.001zm-11.741 3.81l-1.877-1.068a.065.065 0 01-.036-.051V6.559c.001-2.277 1.873-4.122 4.181-4.12.976 0 1.92.338 2.671.954-.034.018-.092.05-.131.073l-4.44 2.53a.71.71 0 00-.365.623l-.003 6.173v.002zm1.02-2.168L12 9.25l2.414 1.375v2.75L12 14.75l-2.415-1.375v-2.75z"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
assets/zhipu-color.svg Normal file
View File

@@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Zhipu</title><path d="M11.991 23.503a.24.24 0 00-.244.248.24.24 0 00.244.249.24.24 0 00.245-.249.24.24 0 00-.22-.247l-.025-.001zM9.671 5.365a1.697 1.697 0 011.099 2.132l-.071.172-.016.04-.018.054c-.07.16-.104.32-.104.498-.035.71.47 1.279 1.186 1.314h.366c1.309.053 2.338 1.173 2.286 2.523-.052 1.332-1.152 2.38-2.478 2.327h-.174c-.715.018-1.274.64-1.239 1.368 0 .124.018.23.053.337.209.373.54.658.96.8.75.23 1.517-.125 1.9-.782l.018-.035c.402-.64 1.17-.96 1.92-.711.854.284 1.378 1.226 1.099 2.167a1.661 1.661 0 01-2.077 1.102 1.711 1.711 0 01-.907-.711l-.017-.035c-.2-.323-.463-.58-.851-.711l-.056-.018a1.646 1.646 0 00-1.954.746 1.66 1.66 0 01-1.065.764 1.677 1.677 0 01-1.989-1.279c-.209-.906.332-1.83 1.257-2.043a1.51 1.51 0 01.296-.035h.018c.68-.071 1.151-.622 1.116-1.333a1.307 1.307 0 00-.227-.693 2.515 2.515 0 01-.366-1.403 2.39 2.39 0 01.366-1.208c.14-.195.21-.444.227-.693.018-.71-.506-1.261-1.186-1.332l-.07-.018a1.43 1.43 0 01-.299-.07l-.05-.019a1.7 1.7 0 01-1.047-2.114 1.68 1.68 0 012.094-1.101zm-5.575 10.11c.26-.264.639-.367.994-.27.355.096.633.379.728.74.095.362-.007.748-.267 1.013-.402.41-1.053.41-1.455 0a1.062 1.062 0 010-1.482zm14.845-.294c.359-.09.738.024.992.297.254.274.344.665.237 1.025-.107.36-.396.634-.756.718-.551.128-1.1-.22-1.23-.781a1.05 1.05 0 01.757-1.26zm-.064-4.39c.314.32.49.753.49 1.206 0 .452-.176.886-.49 1.206-.315.32-.74.5-1.185.5-.444 0-.87-.18-1.184-.5a1.727 1.727 0 010-2.412 1.654 1.654 0 012.369 0zm-11.243.163c.364.484.447 1.128.218 1.691a1.665 1.665 0 01-2.188.923c-.855-.36-1.26-1.358-.907-2.228a1.68 1.68 0 011.33-1.038c.593-.08 1.183.169 1.547.652zm11.545-4.221c.368 0 .708.2.892.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.892.524c-.568 0-1.03-.47-1.03-1.048 0-.579.462-1.048 1.03-1.048zm-14.358 0c.368 0 .707.2.891.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.891.524c-.569 0-1.03-.47-1.03-1.048 0-.579.461-1.048 1.03-1.048zm10.031-1.475c.925 0 1.675.764 1.675 1.706s-.75 1.705-1.675 1.705-1.674-.763-1.674-1.705c0-.942.75-1.706 1.674-1.706zm-2.626-.684c.362-.082.653-.356.761-.718a1.062 1.062 0 00-.238-1.028 1.017 1.017 0 00-.996-.294c-.547.14-.881.7-.752 1.257.13.558.675.907 1.225.783zm0 16.876c.359-.087.644-.36.75-.72a1.062 1.062 0 00-.237-1.019 1.018 1.018 0 00-.985-.301 1.037 1.037 0 00-.762.717c-.108.361-.017.754.239 1.028.245.263.606.377.953.305l.043-.01zM17.19 3.5a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64a.631.631 0 00-.628.64c0 .355.28.64.628.64zm-10.38 0a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64a.631.631 0 00-.628.64c0 .355.279.64.628.64zm-5.182 7.852a.631.631 0 00-.628.64c0 .354.28.639.628.639a.63.63 0 00.627-.606l.001-.034a.62.62 0 00-.628-.64zm5.182 9.13a.631.631 0 00-.628.64c0 .355.279.64.628.64a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm10.38.018a.631.631 0 00-.628.64c0 .355.28.64.628.64a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64zm5.182-9.148a.631.631 0 00-.628.64c0 .354.279.639.628.639a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm-.384-4.992a.24.24 0 00.244-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249c0 .142.122.249.244.249zM11.991.497a.24.24 0 00.245-.248A.24.24 0 0011.99 0a.24.24 0 00-.244.249c0 .133.108.236.223.247l.021.001zM2.011 6.36a.24.24 0 00.245-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249.24.24 0 00.244.249zm0 11.263a.24.24 0 00-.243.248.24.24 0 00.244.249.24.24 0 00.244-.249.252.252 0 00-.244-.248zm19.995-.018a.24.24 0 00-.245.248.24.24 0 00.245.25.24.24 0 00.244-.25.252.252 0 00-.244-.248z" fill="#3859FF" fill-rule="nonzero"></path></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,5 @@
# Copyright (c) 2024 bilive.
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

View File

@@ -0,0 +1,51 @@
# Copyright (c) 2024 bilive.
import re
from collections import defaultdict
from src.config import SLICE_DURATION
def parse_time(time_str):
"""Convert ASS time format to seconds with milliseconds."""
h, m, s = time_str.split(':')
s, ms = s.split('.')
return int(h) * 3600 + int(m) * 60 + int(s) + int(ms) / 100
def format_time(seconds):
"""Format seconds to hh:mm:ss.xx."""
h = int(seconds // 3600)
m = int((seconds % 3600) // 60)
s = int(seconds % 60)
ms = int((seconds - int(seconds)) * 100)
return f"{h:02}:{m:02}:{s:02}.{ms:02}"
def extract_dialogues(file_path):
"""Extract dialogue start times from the ASS file."""
dialogues = []
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
if line.startswith('Dialogue:'):
parts = line.split(',')
start_time = parse_time(parts[1].strip())
dialogues.append(start_time)
return dialogues
def calculate_density(dialogues, window_size=SLICE_DURATION):
"""Calculate the maximum density of dialogues in a given window size."""
time_counts = defaultdict(int)
for time in dialogues:
time_counts[time] += 1
max_density = 0
max_start_time = 0
# Use a sliding window to calculate density
sorted_times = sorted(time_counts.keys())
for i in range(len(sorted_times)):
start_time = sorted_times[i]
end_time = start_time + window_size
current_density = sum(count for time, count in time_counts.items() if start_time <= time < end_time)
if current_density > max_density:
max_density = current_density
max_start_time = start_time
return max_start_time, max_density

View File

@@ -0,0 +1,61 @@
# Copyright (c) 2024 bilive.
import subprocess
from src.autoslice.calculate_density import extract_dialogues, calculate_density, format_time
from src.config import Your_API_KEY, SLICE_DURATION
import base64
from zhipuai import ZhipuAI
def zhipu_glm_4v_plus_generate_title(video_path, artist):
with open(video_path, 'rb') as video_file:
video_base = base64.b64encode(video_file.read()).decode('utf-8')
client = ZhipuAI(api_key=Your_API_KEY)
response = client.chat.completions.create(
model="glm-4v-plus",
messages=[
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url" : video_base
}
},
{
"type": "text",
"text": f"视频是{artist}的直播的切片,请根据该视频中的内容及弹幕信息,为这段视频起一个调皮并且吸引眼球的标题,注意标题中如果有“主播”请替换成{artist}"
}
]
}
]
)
return response.choices[0].message.content.replace("", "").replace("", "")
# https://stackoverflow.com/questions/64849478/cant-insert-stream-metadata-into-mp4
def inject_metadata(video_path, generate_title, output_path):
"""Slice the video using ffmpeg."""
command = [
'ffmpeg',
'-i', video_path,
'-metadata:g', f'generate={generate_title}',
'-c:v', 'copy',
'-c:a', 'copy',
output_path
]
subprocess.run(command)
def slice_video(video_path, start_time, output_path, duration=f'00:00:{SLICE_DURATION}'):
"""Slice the video using ffmpeg."""
command = [
'ffmpeg',
'-ss', format_time(start_time),
'-i', video_path,
'-t', duration,
'-map_metadata', '-1',
'-c:v', 'copy',
'-c:a', 'copy',
output_path
]
subprocess.run(command)

View File

@@ -3,10 +3,13 @@
import argparse
import os
import subprocess
from src.config import GPU_EXIST, SRC_DIR, MODEL_TYPE
from src.config import GPU_EXIST, SRC_DIR, MODEL_TYPE, AUTO_SLICE, SLICE_DURATION
from src.burn.generate_danmakus import get_resolution, process_danmakus
from src.burn.generate_subtitles import generate_subtitles
from src.burn.render_video import render_video
from src.autoslice.slice_video import slice_video, inject_metadata, zhipu_glm_4v_plus_generate_title
from src.autoslice.calculate_density import extract_dialogues, calculate_density, format_time
from src.upload.extract_video_info import get_video_info
import queue
import threading
import time
@@ -52,7 +55,20 @@ def render_video_only(video_path):
render_video(original_video_path, format_video_path, subtitle_font_size, subtitle_margin_v)
print("complete danamku burning and wait for uploading!", flush=True)
# # Delete relative files
if AUTO_SLICE:
title, artist, date = get_video_info(format_video_path)
slice_video_path = format_video_path[:-4] + '_slice.mp4'
dialogues = extract_dialogues(ass_path)
max_start_time, max_density = calculate_density(dialogues)
formatted_time = format_time(max_start_time)
print(f"The 30-second window with the highest density starts at {formatted_time} seconds with {max_density} danmakus.", flush=True)
slice_video(format_video_path, max_start_time, slice_video_path)
glm_title = zhipu_glm_4v_plus_generate_title(slice_video_path, artist)
slice_video_flv_path = slice_video_path[:-4] + '.flv'
inject_metadata(slice_video_path, glm_title, slice_video_flv_path)
os.remove(slice_video_path)
# Delete relative files
for remove_path in [original_video_path, xml_path, ass_path, srt_path, jsonl_path]:
if os.path.exists(remove_path):
os.remove(remove_path)
@@ -63,6 +79,9 @@ def render_video_only(video_path):
with open(f"{SRC_DIR}/upload/uploadVideoQueue.txt", "a") as file:
file.write(f"{format_video_path}\n")
if AUTO_SLICE:
print("complete slice video and wait for uploading!", flush=True)
file.write(f"{slice_video_flv_path}\n")
class VideoRenderQueue:
def __init__(self):

View File

@@ -10,7 +10,10 @@ GPU_EXIST=True
# Can be pipeline, append, merge
MODEL_TYPE = "pipeline"
Inference_Model = "small"
AUTO_SLICE = False
SLICE_DURATION = 30
# Apply for your own GLM-4v-Plus API key at https://www.bigmodel.cn/invite?icode=shBtZUfNE6FfdMH1R6NybGczbXFgPRGIalpycrEwJ28%3D
Your_API_KEY = ""
# ============================ Basic configuration ============================
SRC_DIR = str(Path(os.path.abspath(__file__)).parent)
BILIVE_DIR = str(Path(SRC_DIR).parent)

View File

@@ -6,6 +6,8 @@ import yaml
import codecs
from datetime import datetime
from src.upload.extract_video_info import generate_title, generate_desc, generate_tag, generate_source
import subprocess
import json
def generate_yaml_template(video_path):
source = generate_source(video_path)
@@ -31,6 +33,35 @@ def generate_yaml_template(video_path):
}
return yaml.dump(data, default_flow_style=False, sort_keys=False)
def generate_slice_yaml_template(video_path):
command = [
"ffprobe",
"-v", "quiet",
"-print_format", "json",
"-show_format",
video_path
]
output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode('utf-8')
parsed_output = json.loads(output)
title = parsed_output["format"]["tags"]["generate"]
data = {
"line": "bda2",
"limit": 5,
"streamers": {
video_path: {
"copyright": 1,
"source": "",
"tid": 138,
"cover": "",
"title": title,
"desc_format_id": 0,
"desc": "",
"dynamic": "",
"tag": "直播切片"
}
}
}
return yaml.dump(data, default_flow_style=False, sort_keys=False)
if __name__ == "__main__":
# read the queue and upload the video

View File

@@ -5,7 +5,7 @@ import os
import sys
from src.config import SRC_DIR, BILIVE_DIR
from datetime import datetime
from src.upload.generate_yaml import generate_yaml_template
from src.upload.generate_yaml import generate_yaml_template, generate_slice_yaml_template
from src.upload.extract_video_info import generate_title
import time
import fcntl
@@ -87,6 +87,15 @@ def read_append_and_delete_lines(file_path):
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} " + "deal with " + upload_video_path, flush=True)
# check if the live is already uploaded
if upload_video_path.endswith('.flv'):
# upload slice video
yaml_template = generate_slice_yaml_template(upload_video_path)
yaml_file_path = SRC_DIR + "/upload/upload.yaml"
with open(yaml_file_path, 'w', encoding='utf-8') as file:
file.write(yaml_template)
upload_video(upload_video_path, yaml_file_path)
return
else:
query = generate_title(upload_video_path)
result = subprocess.check_output(f"{SRC_DIR}/upload/biliup" + " -u " + f"{SRC_DIR}/upload/cookies.json" + " list", shell=True)
upload_list = result.decode("utf-8").splitlines()