BilibiliDown项目实现开机自启周期下载功能的技术解析
痛点场景:B站视频自动化批量下载的迫切需求
作为B站(哔哩哔哩)深度用户,你是否遇到过这样的困扰:
- 关注的UP主更新频繁,手动一个个下载耗时费力
- 收藏夹里积累了数百个视频,想要批量下载却无从下手
- 希望定时自动下载新内容,但缺乏合适的工具支持
- 需要长期稳定运行,支持开机自启和周期任务调度
BilibiliDown项目的开机自启周期下载功能正是为解决这些痛点而生。本文将深入解析这一功能的技术实现细节,帮助你全面掌握自动化视频下载的核心机制。
功能架构总览
BilibiliDown的周期下载功能采用分层架构设计,核心组件包括:
核心配置参数详解
1. 自启动配置
# 程序启动时自动开始周期下载
bilibili.download.batch.plan.runOnStartup = false
# 默认的一键下载配置文件
bilibili.download.batch.config.name = batchDownload.config
# 时间计划配置格式
bilibili.download.batch.plan = 06:00~02:00=>r(300,480); 02:00~06:00=>~06:00+r(0,360)
2. 时间计划语法解析
BilibiliDown采用灵活的时间计划配置语法:
| 配置格式 | 含义 | 示例 |
|---|---|---|
HH:mm~HH:mm=>r(t1,t2) | 时间段内随机等待t1-t2秒 | 06:00~02:00=>r(300,480) |
HH:mm~HH:mm=>~HH:mm | 等待到指定时刻 | 02:00~04:00=>~06:00 |
HH:mm~HH:mm=>~HH:mm+r(t1,t2) | 等到时刻后随机等待 | 02:00~04:00=>~06:00+r(0,360) |
核心技术实现解析
1. 周期任务调度引擎
BatchDownloadRbyRThread类是周期下载功能的核心:
public class BatchDownloadRbyRThread extends BatchDownloadThread {
private static ConcurrentHashMap<ClipInfo, TaskInfo> currentTaskList;
private static long batchDownloadBeginTime;
private static long batchDownloadEndTime;
public void run() {
while (true) {
// 1. 检查当前无活跃下载任务
if(Global.downloadTab.activeTask == 0) {
// 2. 清理下载面板避免内存溢出
for(DownloadInfoPanel dp : Global.downloadTaskList.keySet()) {
dp.removeTask(true);
}
// 3. 定时刷新Cookie(每天一次)
if (currentTime - lastCookieRefreshTime > MILLI_SECONDS_OF_ONE_DAY) {
CookieRefreshThread thCR = CookieRefreshThread.newInstance();
thCR.start();
thCR.join();
}
}
// 4. 执行批量下载
runBatchDownloadOnce();
// 5. 根据计划计算休眠时间
sleep(timeToSleep(plans, System.currentTimeMillis()));
}
}
}
2. 时间计划解析算法
时间计算采用高效的区间匹配算法:
public long timeToSleep(String[] plans, long currentTime) {
Random random = new Random();
String today = sdfToday.format(currentTime);
for(String plan: plans) {
String[] params = plan.split("=>");
String[] timePeriod = params[0].split("~");
// 时间区间计算
long lTime = sdf.parse(today + " " + timePeriod[0].trim()).getTime();
long rTime = sdf.parse(today + " " + timePeriod[1].trim()).getTime();
if(rTime <= lTime) rTime += MILLI_SECONDS_OF_ONE_DAY;
// 区间匹配
if(currentTime >= lTime && currentTime <= rTime) {
long rollTime = 0L, toTimeDelta = 0L;
// 解析随机时间 r(t1,t2)
Matcher rm = rollTimePattern.matcher(params[1]);
if(rm.find()) {
int rLeft = Integer.parseInt(rm.group(1)) * 1000;
int rRight = Integer.parseInt(rm.group(2)) * 1000;
rollTime = rLeft + random.nextInt(rRight - rLeft);
}
// 解析指定时刻 ~HH:mm
Matcher tm = toTimePattern.matcher(params[1]);
if(tm.find()) {
long toTime = sdf.parse(today + " " + tm.group(1)).getTime();
if(toTime < currentTime) toTime += MILLI_SECONDS_OF_ONE_DAY;
toTimeDelta = toTime - currentTime;
}
return toTimeDelta + rollTime;
}
}
throw new IllegalArgumentException("时间配置错误");
}
3. 任务状态管理机制
采用ConcurrentHashMap进行线程安全的任务状态跟踪:
public static void taskSucceed(ClipInfo clip, String fileName, String fileSize, String qn) {
if (currentTaskList != null) {
TaskInfo task = currentTaskList.get(clip);
if (task != null) {
task.setFileName(fileName);
task.setFileSize(fileSize);
task.setQn(qn);
task.setStatus("success");
}
}
}
public static void taskFail(ClipInfo clip, String status) {
if (currentTaskList != null) {
TaskInfo task = currentTaskList.get(clip);
if (task != null) {
task.setStatus(status);
}
}
}
开机自启实现方案
Windows系统自启
:: 创建注册表启动项
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "BilibiliDown" /t REG_SZ /d "\"C:\Program Files\BilibiliDown\BilibiliDown.exe\" -Dbilibili.download.batch.plan.runOnStartup=true" /f
Linux系统自启
# 创建systemd服务
sudo tee /etc/systemd/system/bilibilidown.service > /dev/null <<EOF
[Unit]
Description=BilibiliDown Auto Download Service
After=network.target
[Service]
Type=simple
User=$USER
ExecStart=/usr/bin/java -jar /opt/BilibiliDown/INeedBiliAV.jar -Dbilibili.download.batch.plan.runOnStartup=true
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable bilibilidown.service
macOS系统自启
# 创建LaunchAgent
cat > ~/Library/LaunchAgents/top.nicelee.bilibilidown.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>top.nicelee.bilibilidown</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/java</string>
<string>-jar</string>
<string>/Applications/BilibiliDown/INeedBiliAV.jar</string>
<string>-Dbilibili.download.batch.plan.runOnStartup=true</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
EOF
配置文件示例与最佳实践
完整的一键下载配置文件
创建config/batchDownload.config:
# 批量下载配置示例
# 支持多种URL类型混合配置
# 单个视频
https://www.bilibili.com/video/BV1g5411V7x6
# UP主所有视频
https://space.bilibili.com/123456/video
# 收藏夹
https://space.bilibili.com/123456/favlist?fid=789012
# 稍后再看
https://www.bilibili.com/list/watchlater
# 条件筛选:只下载2024年以后的1080P视频
condition.date = 20240101-
condition.quality = 80
# 重命名规则
naming.pattern = (:listName listName-)avTitle-pDisplay-clipTitle-qn
优化的时间计划配置
# 工作日白天频繁下载,夜间减少频率
bilibili.download.batch.plan = \
06:00~22:00=>r(300,600); \ # 白天每5-10分钟检查一次
22:00~06:00=>r(1800,3600); \ # 夜间每30-60分钟检查一次
00:00~00:00=>r(300,300) # 默认配置
高级功能与扩展
1. 结果推送通知
支持多种推送方式:
| 推送类型 | 配置示例 | 特点 |
|---|---|---|
| 控制台打印 | bilibili.download.push.type=Print | 默认方式,输出到日志 |
| 邮件通知 | bilibili.download.push.type=Mail | 需要配置SMTP服务器 |
| 自定义推送 | 实现IPush接口 | 支持Webhook等自定义方式 |
2. 内存优化策略
// 定期清理下载任务避免内存泄漏
for(DownloadInfoPanel dp : Global.downloadTaskList.keySet()) {
dp.removeTask(true);
}
// 使用弱引用管理大对象
private static WeakReference<ConcurrentHashMap<ClipInfo, TaskInfo>> currentTaskListRef;
3. 异常处理与重试机制
// 网络异常自动重试
if (maxFailRetry > 0) {
for (int retry = 0; retry < maxFailRetry; retry++) {
try {
downloadTask();
break;
} catch (IOException e) {
if (retry == maxFailRetry - 1) throw e;
Thread.sleep(5000 * (retry + 1));
}
}
}
// Cookie失效自动刷新
if (isCookieExpired()) {
refreshCookie();
reloadDownloadUrl = true;
}
性能优化建议
1. 资源占用控制
# 控制并发下载数量
bilibili.download.poolSize = 3
# 减少内存占用
bilibili.pageSize = 5
bilibili.restrictTempMode = on
2. 网络请求优化
# 减少不必要的清晰度查询
bilibili.info.query.strategy = returnFixedValue
# 设置合理的请求间隔
bilibili.download.period.between.query = 1000
bilibili.download.period.between.download = 0
常见问题排查
1. 自启动失败排查
# 检查日志输出
tail -f ~/.BilibiliDown/logs/app.log
# 验证Java环境
java -version
# 检查文件权限
ls -la /opt/BilibiliDown/
2. 网络连接问题
# 配置网络中转服务
networkRelayHost = 127.0.0.1
networkRelayPort = 1080
# 跳过证书验证(不推荐)
bilibili.https.allowInsecure = false
3. 内存溢出处理
# 增加JVM内存限制
java -Xmx512m -Xms256m -jar INeedBiliAV.jar
# 定期清理临时文件
find /tmp -name "BilibiliDown_*" -mtime +7 -delete
总结与展望
BilibiliDown的开机自启周期下载功能通过精心设计的架构和算法,实现了:
- 灵活的时间调度:支持复杂的时间计划配置
- 稳定的长时间运行:完善的异常处理和资源管理
- 自动化运维:开机自启、定时任务、结果通知
- 资源友好:内存优化、网络请求控制
随着B站API的不断更新和用户需求的多样化,这一功能将继续演进,支持更智能的下载策略、更丰富的推送方式,以及更好的跨平台兼容性。
通过本文的技术解析,相信你已经对BilibiliDown的自动化下载功能有了深入的理解,能够更好地配置和使用这一强大工具,实现B站视频的高效批量下载。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



