bililive-cli 3.12.1 → 3.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ var path$7 = require('node:path');
4
4
  var require$$2$1 = require('node:http');
5
5
  var require$$1$2 = require('node:url');
6
6
  var a = require('node:https');
7
- var index = require('./index-BeyiZ-FP.cjs');
7
+ var index = require('./index-CgpPN0zA.cjs');
8
8
  var require$$0$4 = require('tty');
9
9
  var require$$1$3 = require('util');
10
10
  var require$$0$b = require('assert');
@@ -30477,8 +30477,9 @@ const errorMiddleware = async (ctx, next) => {
30477
30477
  await next();
30478
30478
  }
30479
30479
  catch (error) {
30480
+ const message = error instanceof Error ? error.message : String(error);
30480
30481
  ctx.status = 500;
30481
- ctx.body = error.message;
30482
+ ctx.body = message;
30482
30483
  ctx.app.emit("error", error, ctx);
30483
30484
  index.logObj.error(error);
30484
30485
  }
@@ -49131,6 +49132,50 @@ router$f.post("/set", async (ctx) => {
49131
49132
  exports.appConfig.set(data.key, data.value);
49132
49133
  ctx.body = "success";
49133
49134
  });
49135
+ router$f.post("/verifyBiliKey", async (ctx) => {
49136
+ try {
49137
+ const serverKey = process.env.BILILIVE_TOOLS_BILIKEY;
49138
+ const configured = typeof serverKey === "string" && serverKey.trim().length > 0;
49139
+ const requestBody = ctx.request.body;
49140
+ const rawInput = typeof requestBody?.key === "string" ? requestBody.key : "";
49141
+ const inputKey = rawInput.trim();
49142
+ let response;
49143
+ if (!configured) {
49144
+ response = {
49145
+ configured: false,
49146
+ valid: false,
49147
+ matched: false,
49148
+ reason: "missing",
49149
+ };
49150
+ }
49151
+ else if (inputKey === serverKey) {
49152
+ response = {
49153
+ configured: true,
49154
+ valid: true,
49155
+ matched: true,
49156
+ reason: "ok",
49157
+ };
49158
+ }
49159
+ else {
49160
+ response = {
49161
+ configured: true,
49162
+ valid: false,
49163
+ matched: false,
49164
+ reason: "mismatch",
49165
+ };
49166
+ }
49167
+ ctx.body = response;
49168
+ }
49169
+ catch {
49170
+ const response = {
49171
+ configured: false,
49172
+ valid: false,
49173
+ matched: false,
49174
+ reason: "error",
49175
+ };
49176
+ ctx.body = response;
49177
+ }
49178
+ });
49134
49179
  router$f.post("/resetBin", async (ctx) => {
49135
49180
  const data = ctx.request.body;
49136
49181
  const type = data.type;
@@ -56428,7 +56473,6 @@ router$d.get("/files", async (ctx) => {
56428
56473
  const allFiles = filterExts.length === 0 || filterExts.includes(".*");
56429
56474
  if (root == "/" && process.platform === "win32") {
56430
56475
  const drives = await getDriveLetters();
56431
- root = drives[0];
56432
56476
  ctx.body = {
56433
56477
  list: drives.map((drive) => ({ type: "directory", name: drive, path: `${drive}\\` })),
56434
56478
  parent: "",
@@ -56454,6 +56498,7 @@ router$d.get("/files", async (ctx) => {
56454
56498
  type: type,
56455
56499
  name: name,
56456
56500
  path: filePath,
56501
+ size: type === "file" ? fileStat.size : undefined,
56457
56502
  });
56458
56503
  }
56459
56504
  catch (error) {
@@ -57074,6 +57119,47 @@ router$c.post("/get_cookie", async (ctx) => {
57074
57119
  ctx.body = "获取失败,请重试";
57075
57120
  }
57076
57121
  });
57122
+ router$c.get("/export", async (ctx) => {
57123
+ const list = index.biliApi.readUserList();
57124
+ ctx.body = list;
57125
+ });
57126
+ router$c.post("/export_single", async (ctx) => {
57127
+ const { uid } = ctx.request.body;
57128
+ const user = index.biliApi.readUser(uid);
57129
+ if (!user) {
57130
+ ctx.status = 404;
57131
+ ctx.body = "用户不存在";
57132
+ return;
57133
+ }
57134
+ ctx.body = user;
57135
+ });
57136
+ router$c.post("/import", async (ctx) => {
57137
+ const { users } = ctx.request.body;
57138
+ if (!Array.isArray(users)) {
57139
+ ctx.status = 400;
57140
+ ctx.body = "参数错误";
57141
+ return;
57142
+ }
57143
+ for (const item of users) {
57144
+ if (!item?.mid || !item?.accessToken || !item?.refreshToken || !item?.cookie) {
57145
+ ctx.status = 400;
57146
+ ctx.body = "账号数据不完整";
57147
+ return;
57148
+ }
57149
+ await index.biliApi.writeUser(item);
57150
+ }
57151
+ ctx.status = 200;
57152
+ });
57153
+ router$c.post("/import_single", async (ctx) => {
57154
+ const { user } = ctx.request.body;
57155
+ if (!user?.mid || !user?.accessToken || !user?.refreshToken || !user?.cookie) {
57156
+ ctx.status = 400;
57157
+ ctx.body = "账号数据不完整";
57158
+ return;
57159
+ }
57160
+ await index.biliApi.writeUser(user);
57161
+ ctx.status = 200;
57162
+ });
57077
57163
 
57078
57164
  const router$b = new Router$1({
57079
57165
  prefix: "/preset",
@@ -76579,7 +76665,7 @@ const router$a = new Router$1({
76579
76665
  */
76580
76666
  router$a.get("/streamLogs", sse({
76581
76667
  maxClients: 5000,
76582
- pingInterval: 30000,
76668
+ pingInterval: 60 * 60 * 1000,
76583
76669
  }), async (ctx) => {
76584
76670
  const logFilePath = exports.config.logPath;
76585
76671
  // 初始化logSize为文件当前大小
@@ -78181,7 +78267,7 @@ async function parseVideo({ url, }) {
78181
78267
  }
78182
78268
  }
78183
78269
  async function downloadVideo(options) {
78184
- const filepath = path$7.join(options.savePath, options.filename);
78270
+ let filepath = path$7.join(options.savePath, options.filename);
78185
78271
  if (options.platform === "douyu") {
78186
78272
  if (!options?.extra?.decodeData) {
78187
78273
  throw new Error("decodeData is required for douyu download");
@@ -78241,6 +78327,7 @@ async function downloadVideo(options) {
78241
78327
  if (!options?.extra?.bvid) {
78242
78328
  throw new Error("bvid is required for bilibili download");
78243
78329
  }
78330
+ filepath = index.replaceExtName(filepath, ".mp4");
78244
78331
  await index.biliApi.download({
78245
78332
  bvid: options.extra.bvid,
78246
78333
  cid: Number(options.id),
@@ -78709,7 +78796,7 @@ async function uploadTest(params) {
78709
78796
  const tempDir = index.getTempPath();
78710
78797
  // 在临时文件新建一个文件,内容为"biliLive-tools"
78711
78798
  const tempFilePath = path$7.join(tempDir, "biliLive-tools-upload-test.txt");
78712
- await index.fs.writeFile(tempFilePath, "biliLive-tools");
78799
+ await index.fs.writeFile(tempFilePath, `biliLive-tools-${index.uuid()}`);
78713
78800
  return new Promise(async (resolve, reject) => {
78714
78801
  const task = await addSyncTask({
78715
78802
  input: tempFilePath,
@@ -79218,9 +79305,23 @@ class FileRefManager {
79218
79305
  */
79219
79306
  class ConfigManager {
79220
79307
  appConfig;
79308
+ static APP_CONFIG_CACHE_TTL = 30 * 1000;
79309
+ appConfigCache;
79221
79310
  constructor(appConfig) {
79222
79311
  this.appConfig = appConfig;
79223
79312
  }
79313
+ getAppConfigAll() {
79314
+ const now = Date.now();
79315
+ if (this.appConfigCache && this.appConfigCache.expiresAt > now) {
79316
+ return this.appConfigCache.value;
79317
+ }
79318
+ const value = this.appConfig.getAll();
79319
+ this.appConfigCache = {
79320
+ value,
79321
+ expiresAt: now + ConfigManager.APP_CONFIG_CACHE_TTL,
79322
+ };
79323
+ return value;
79324
+ }
79224
79325
  /**
79225
79326
  * 判断房间是否开启
79226
79327
  */
@@ -79245,7 +79346,7 @@ class ConfigManager {
79245
79346
  * @returns 房间配置对象
79246
79347
  */
79247
79348
  getConfig(roomId) {
79248
- const appConfigAll = this.appConfig.getAll();
79349
+ const appConfigAll = this.getAppConfigAll();
79249
79350
  const roomSetting = appConfigAll.webhook?.rooms?.[roomId];
79250
79351
  const danmu = this.getRoomSetting("danmu", roomSetting) ?? false;
79251
79352
  const mergePart = this.getRoomSetting("autoPartMerge", roomSetting) ?? false;
@@ -79271,9 +79372,7 @@ class ConfigManager {
79271
79372
  ];
79272
79373
  const syncId = this.getRoomSetting("syncId", roomSetting);
79273
79374
  const afterConvertAction = this.getRoomSetting("afterConvertAction", roomSetting) ?? [];
79274
- // TODO: 兼容废弃选项,过渡期后删除
79275
- const removeSourceAferrConvert2Mp4Before = this.getRoomSetting("removeSourceAferrConvert2Mp4", roomSetting);
79276
- const removeSourceAferrConvert2Mp4 = afterConvertAction.includes("removeAfterConvert2Mp4") || !!removeSourceAferrConvert2Mp4Before;
79375
+ const removeSourceAferrConvert2Mp4 = afterConvertAction.includes("removeAfterConvert2Mp4");
79277
79376
  const afterConvertRemoveVideoRaw = afterConvertAction.includes("removeVideo");
79278
79377
  const afterConvertRemoveXmlRaw = afterConvertAction.includes("removeXml");
79279
79378
  const afterConvertRemoveFlvRaw = afterConvertAction.includes("removeAfterFlvRepair");
@@ -79284,6 +79383,7 @@ class ConfigManager {
79284
79383
  "23:59:59",
79285
79384
  ];
79286
79385
  const uploadNoDanmu = this.getRoomSetting("uploadNoDanmu", roomSetting) ?? false;
79386
+ const uploadToSameMedia = this.getRoomSetting("uploadToSameMedia", roomSetting) ?? false;
79287
79387
  const noDanmuVideoPreset = this.getRoomSetting("noDanmuVideoPreset", roomSetting) || "default";
79288
79388
  // 如果没有开启断播续传,那么不需要合并part
79289
79389
  if (!mergePart)
@@ -79333,6 +79433,7 @@ class ConfigManager {
79333
79433
  limitUploadTime,
79334
79434
  uploadHandleTime,
79335
79435
  uploadNoDanmu,
79436
+ uploadToSameMedia,
79336
79437
  noDanmuVideoPreset,
79337
79438
  videoHandleTime: limitVideoConvertTime ? videoHandleTime : undefined,
79338
79439
  partTitleTemplate: this.getRoomSetting("partTitleTemplate", roomSetting) || "{{filename}}",
@@ -79353,7 +79454,7 @@ class ConfigManager {
79353
79454
  * @returns 配置值
79354
79455
  */
79355
79456
  getRoomSetting(key, roomSetting) {
79356
- const appConfigAll = this.appConfig.getAll();
79457
+ const appConfigAll = this.getAppConfigAll();
79357
79458
  if (roomSetting) {
79358
79459
  if (roomSetting.noGlobal?.includes(key)) {
79359
79460
  return roomSetting[key];
@@ -79373,7 +79474,7 @@ class ConfigManager {
79373
79474
  const { syncId } = this.getConfig(roomId);
79374
79475
  if (!syncId)
79375
79476
  return null;
79376
- const appConfig = this.appConfig.getAll();
79477
+ const appConfig = this.getAppConfigAll();
79377
79478
  const syncConfig = appConfig.sync?.syncConfigs?.find((cfg) => cfg.id === syncId);
79378
79479
  if (!syncConfig)
79379
79480
  return null;
@@ -80149,6 +80250,7 @@ class EventBufferManager extends EventEmitter$3.EventEmitter {
80149
80250
  }
80150
80251
  }
80151
80252
 
80253
+ const SAME_MEDIA_UPLOAD_ORDER = ["handled", "raw"];
80152
80254
  class WebhookHandler {
80153
80255
  liveManager = new LiveManager();
80154
80256
  ffmpegPreset;
@@ -80860,11 +80962,58 @@ class WebhookHandler {
80860
80962
  * 通用上传任务处理逻辑
80861
80963
  * @private
80862
80964
  */
80863
- async handleUploadTask(task, pathArray) {
80965
+ getRuntimePart(part) {
80966
+ return part;
80967
+ }
80968
+ setPartCid(part, type, cid) {
80969
+ if (!cid)
80970
+ return;
80971
+ const runtimePart = this.getRuntimePart(part);
80972
+ if (type === "handled") {
80973
+ runtimePart.handledCid = cid;
80974
+ }
80975
+ else {
80976
+ runtimePart.rawCid = cid;
80977
+ }
80978
+ }
80979
+ getPartCid(part, type) {
80980
+ const runtimePart = this.getRuntimePart(part);
80981
+ return type === "handled" ? runtimePart.handledCid : runtimePart.rawCid;
80982
+ }
80983
+ toPathArray(items) {
80984
+ return items.map((item) => ({
80985
+ path: item.path,
80986
+ title: item.title,
80987
+ }));
80988
+ }
80989
+ createUploadItems(filePaths, type) {
80990
+ return filePaths.map((item) => ({
80991
+ ...item,
80992
+ type,
80993
+ }));
80994
+ }
80995
+ writeUploadResultToParts(uploadedItems, data) {
80996
+ const itemQueue = new Map();
80997
+ for (const item of uploadedItems) {
80998
+ const queue = itemQueue.get(item.path) ?? [];
80999
+ queue.push(item);
81000
+ itemQueue.set(item.path, queue);
81001
+ }
81002
+ for (const result of data) {
81003
+ const queue = itemQueue.get(result.filePath);
81004
+ const item = queue?.shift();
81005
+ if (!item)
81006
+ continue;
81007
+ this.setPartCid(item.part, item.type, result.cid);
81008
+ }
81009
+ }
81010
+ async handleUploadTask(task, uploadedItems) {
80864
81011
  return new Promise((resolve, reject) => {
80865
- task.on("task-end", async () => {
81012
+ task.on("task-end", async (payload) => {
81013
+ const data = payload?.data ?? [];
81014
+ this.writeUploadResultToParts(uploadedItems, data);
80866
81015
  // 释放所有文件的引用
80867
- for (const { path } of pathArray) {
81016
+ for (const { path } of uploadedItems) {
80868
81017
  await this.fileRefManager.releaseRef(path);
80869
81018
  }
80870
81019
  resolve(task.output);
@@ -80893,25 +81042,31 @@ class WebhookHandler {
80893
81042
  }
80894
81043
  };
80895
81044
  }
80896
- addUploadTask = async (uid, pathArray, options, limitedUploadTime, afterUploadDeletAction) => {
81045
+ addUploadTask = async (uid, uploadedItems, options, limitedUploadTime, afterUploadDeletAction) => {
81046
+ const pathArray = this.toPathArray(uploadedItems);
80897
81047
  const checkCallback = this.setupDeleteAfterCheckLock(pathArray, afterUploadDeletAction);
81048
+ // console.log("upload", pathArray);
80898
81049
  const task = await index.biliApi.addMedia(pathArray, options, uid, {
80899
81050
  limitedUploadTime,
80900
81051
  afterUploadDeletAction: "none",
80901
81052
  forceCheck: afterUploadDeletAction === "deleteAfterCheck",
80902
81053
  checkCallback,
80903
81054
  });
80904
- return this.handleUploadTask(task, pathArray);
81055
+ return this.handleUploadTask(task, uploadedItems);
80905
81056
  };
80906
- addEditMediaTask = async (uid, aid, pathArray, uploadPreset, limitedUploadTime, afterUploadDeletAction) => {
81057
+ addEditMediaTask = async (uid, aid, uploadedItems, uploadPreset, limitedUploadTime, afterUploadDeletAction, sortParams) => {
81058
+ const pathArray = this.toPathArray(uploadedItems);
80907
81059
  const checkCallback = this.setupDeleteAfterCheckLock(pathArray, afterUploadDeletAction);
81060
+ // console.log("sortParams111111111", sortParams, pathArray);
81061
+ // 参数sortParams: array<{filePath:string;cid?:number}>,表示按照 filePath 对历史分P和当前上传文件统一排序
80908
81062
  const task = await index.biliApi.editMedia(aid, pathArray, uploadPreset, uid, {
80909
81063
  limitedUploadTime,
80910
81064
  afterUploadDeletAction: "none",
80911
81065
  forceCheck: afterUploadDeletAction === "deleteAfterCheck",
80912
81066
  checkCallback,
81067
+ sortParams,
80913
81068
  });
80914
- return this.handleUploadTask(task, pathArray);
81069
+ return this.handleUploadTask(task, uploadedItems);
80915
81070
  };
80916
81071
  /**
80917
81072
  * 构建上传文件列表
@@ -80945,6 +81100,110 @@ class WebhookHandler {
80945
81100
  }
80946
81101
  return { filePaths, cover };
80947
81102
  }
81103
+ isSameMediaUploadEnabled(config) {
81104
+ return config.uploadNoDanmu && config.uploadToSameMedia;
81105
+ }
81106
+ updateUploadStatusForItems(filePaths, status) {
81107
+ for (const item of filePaths) {
81108
+ item.part.updateUploadStatus(status, item.type === "raw");
81109
+ }
81110
+ }
81111
+ getSameMediaUploadCandidate(part, type, config) {
81112
+ if (type === "handled") {
81113
+ return {
81114
+ type,
81115
+ path: part.filePath,
81116
+ status: part.uploadStatus,
81117
+ canUpload: part.canUpload("handled"),
81118
+ enabled: true,
81119
+ };
81120
+ }
81121
+ return {
81122
+ type,
81123
+ path: part.rawFilePath,
81124
+ status: part.rawUploadStatus,
81125
+ canUpload: part.canUpload("raw"),
81126
+ enabled: config.uploadNoDanmu,
81127
+ };
81128
+ }
81129
+ buildSameMediaSortParams(live, config) {
81130
+ const sortParams = [];
81131
+ for (const type of SAME_MEDIA_UPLOAD_ORDER) {
81132
+ for (const part of live.parts) {
81133
+ const item = this.getSameMediaUploadCandidate(part, type, config);
81134
+ if (item.enabled === false || item.status === "error") {
81135
+ continue;
81136
+ }
81137
+ const cid = this.getPartCid(part, item.type);
81138
+ sortParams.push({
81139
+ filePath: item.path,
81140
+ cid,
81141
+ });
81142
+ if (item.status !== "uploaded" && !item.canUpload) {
81143
+ return sortParams;
81144
+ }
81145
+ }
81146
+ }
81147
+ return sortParams;
81148
+ }
81149
+ getUploadedItemCountForSameMedia(live, config) {
81150
+ let uploadedCount = 0;
81151
+ for (const part of live.parts) {
81152
+ if (part.uploadStatus === "uploaded") {
81153
+ uploadedCount++;
81154
+ }
81155
+ if (config.uploadNoDanmu && part.rawUploadStatus === "uploaded") {
81156
+ uploadedCount++;
81157
+ }
81158
+ }
81159
+ return uploadedCount;
81160
+ }
81161
+ buildSameMediaUploadFileList(live, config) {
81162
+ let cover;
81163
+ const filePaths = [];
81164
+ let currentIndex = this.getUploadedItemCountForSameMedia(live, config) + 1;
81165
+ for (const type of SAME_MEDIA_UPLOAD_ORDER) {
81166
+ for (const part of live.parts) {
81167
+ const item = this.getSameMediaUploadCandidate(part, type, config);
81168
+ if (item.enabled === false)
81169
+ continue;
81170
+ if (item.status === "uploaded" || item.status === "error")
81171
+ continue;
81172
+ if (!item.canUpload)
81173
+ continue;
81174
+ const filename = path$7.parse(item.path).name;
81175
+ const baseTitle = index.formatPartTitle({
81176
+ title: part.title,
81177
+ username: live.username,
81178
+ roomId: live.roomId,
81179
+ time: part?.startTime
81180
+ ? new Date(part.startTime).toISOString()
81181
+ : new Date().toISOString(),
81182
+ filename,
81183
+ index: currentIndex,
81184
+ }, config.partTitleTemplate ?? "{{filename}}");
81185
+ filePaths.push({
81186
+ part,
81187
+ path: item.path,
81188
+ title: baseTitle,
81189
+ type: item.type,
81190
+ });
81191
+ if (!cover) {
81192
+ cover = part.cover;
81193
+ }
81194
+ currentIndex++;
81195
+ }
81196
+ }
81197
+ return { filePaths, cover };
81198
+ }
81199
+ validateCombinedUploadConfig(filePaths, config) {
81200
+ if (!config.uid) {
81201
+ this.updateUploadStatusForItems(filePaths, "error");
81202
+ index.logObj.error("无须上传,uid未配置");
81203
+ return false;
81204
+ }
81205
+ return true;
81206
+ }
80948
81207
  /**
80949
81208
  * 验证上传配置
80950
81209
  * @private
@@ -80990,6 +81249,9 @@ class WebhookHandler {
80990
81249
  }
80991
81250
  return uploadPreset;
80992
81251
  }
81252
+ async prepareSharedUploadPreset(config, live, cover) {
81253
+ return this.prepareUploadPreset("handled", config, live, cover);
81254
+ }
80993
81255
  /**
80994
81256
  * 格式化上传视频标题
80995
81257
  * @private
@@ -81031,11 +81293,9 @@ class WebhookHandler {
81031
81293
  */
81032
81294
  async performContinueUpload(live, aid, filePaths, type, config, uploadPreset, limitedUploadTime) {
81033
81295
  index.logObj.info("续传", filePaths);
81296
+ const uploadedItems = this.createUploadItems(filePaths, type);
81034
81297
  live.batchUpdateUploadStatus(filePaths.map((item) => item.part), "uploading", type);
81035
- await this.addEditMediaTask(config.uid, aid, filePaths.map((item) => ({
81036
- path: item.path,
81037
- title: item.title,
81038
- })), uploadPreset, limitedUploadTime, config.afterUploadDeletAction);
81298
+ await this.addEditMediaTask(config.uid, aid, uploadedItems, uploadPreset, limitedUploadTime, config.afterUploadDeletAction);
81039
81299
  live.batchUpdateUploadStatus(filePaths.map((item) => item.part), "uploaded", type);
81040
81300
  }
81041
81301
  /**
@@ -81044,17 +81304,61 @@ class WebhookHandler {
81044
81304
  */
81045
81305
  async performNewUpload(live, filePaths, type, config, uploadPreset, limitedUploadTime) {
81046
81306
  const aidField = type === "handled" ? "aid" : "rawAid";
81307
+ const uploadedItems = this.createUploadItems(filePaths, type);
81047
81308
  live.batchUpdateUploadStatus(filePaths.map((item) => item.part), "uploading", type);
81048
81309
  // 格式化标题
81049
81310
  const videoTitle = this.formatUploadTitle(live, filePaths[0].part, type, uploadPreset, config);
81050
81311
  uploadPreset.title = videoTitle;
81051
- const aid = (await this.addUploadTask(config.uid, filePaths.map((item) => ({
81052
- path: item.path,
81053
- title: item.title,
81054
- })), uploadPreset, limitedUploadTime, config.afterUploadDeletAction));
81312
+ const aid = (await this.addUploadTask(config.uid, uploadedItems, uploadPreset, limitedUploadTime, config.afterUploadDeletAction));
81055
81313
  live[aidField] = Number(aid);
81056
81314
  live.batchUpdateUploadStatus(filePaths.map((item) => item.part), "uploaded", type);
81057
81315
  }
81316
+ async performContinueUploadForSameMedia(live, aid, filePaths, config, uploadPreset, limitedUploadTime) {
81317
+ // log.info("同稿件续传", filePaths);
81318
+ const sortParams = this.buildSameMediaSortParams(live, config);
81319
+ live.aid = aid;
81320
+ this.updateUploadStatusForItems(filePaths, "uploading");
81321
+ await this.addEditMediaTask(config.uid, aid, filePaths, uploadPreset, limitedUploadTime, config.afterUploadDeletAction, sortParams);
81322
+ this.updateUploadStatusForItems(filePaths, "uploaded");
81323
+ }
81324
+ async performNewUploadForSameMedia(live, filePaths, config, uploadPreset, limitedUploadTime) {
81325
+ this.updateUploadStatusForItems(filePaths, "uploading");
81326
+ const videoTitle = this.formatUploadTitle(live, filePaths[0].part, "handled", uploadPreset, config);
81327
+ uploadPreset.title = videoTitle;
81328
+ const aid = (await this.addUploadTask(config.uid, filePaths, uploadPreset, limitedUploadTime, config.afterUploadDeletAction));
81329
+ live.aid = Number(aid);
81330
+ this.updateUploadStatusForItems(filePaths, "uploaded");
81331
+ }
81332
+ async uploadVideoToSameMedia(live, config) {
81333
+ if (live.hasUploadingParts("handled") || live.hasUploadingParts("raw")) {
81334
+ return;
81335
+ }
81336
+ const { filePaths, cover } = this.buildSameMediaUploadFileList(live, config);
81337
+ // console.log("同稿件上传候选列表", filePaths);
81338
+ if (filePaths.length === 0) {
81339
+ return;
81340
+ }
81341
+ if (!this.validateCombinedUploadConfig(filePaths, config)) {
81342
+ return;
81343
+ }
81344
+ const uploadPreset = await this.prepareSharedUploadPreset(config, live, cover);
81345
+ const limitedUploadTime = config.limitUploadTime
81346
+ ? config.uploadHandleTime
81347
+ : [];
81348
+ const sharedAid = live.aid ?? live.rawAid;
81349
+ try {
81350
+ if (sharedAid) {
81351
+ await this.performContinueUploadForSameMedia(live, sharedAid, filePaths, config, uploadPreset, limitedUploadTime);
81352
+ }
81353
+ else {
81354
+ await this.performNewUploadForSameMedia(live, filePaths, config, uploadPreset, limitedUploadTime);
81355
+ }
81356
+ }
81357
+ catch (error) {
81358
+ index.logObj.error(error);
81359
+ this.updateUploadStatusForItems(filePaths, "error");
81360
+ }
81361
+ }
81058
81362
  /**
81059
81363
  * 上传单个类型的视频(弹幕版或原始版)
81060
81364
  * @private
@@ -81100,9 +81404,14 @@ class WebhookHandler {
81100
81404
  /**
81101
81405
  * 处理直播上传
81102
81406
  * @param live 直播数据
81103
- * @param type 上传类型:handled-弹幕版,raw-原始版,undefined-两者都上传
81407
+ * @param type 上传类型:handled-弹幕版,raw-原始版
81104
81408
  */
81105
81409
  handleLive = async (live, type) => {
81410
+ const config = this.configManager.getConfig(live.roomId);
81411
+ if (this.isSameMediaUploadEnabled(config)) {
81412
+ await this.uploadVideoToSameMedia(live, config);
81413
+ return;
81414
+ }
81106
81415
  if (type) {
81107
81416
  if (type === "handled") {
81108
81417
  await this.uploadVideoByType(live, "handled");
@@ -81156,7 +81465,7 @@ exports.handler = void 0;
81156
81465
  exports.appConfig = void 0;
81157
81466
  exports.container = void 0;
81158
81467
  const fileCache = createFileCache();
81159
- path$7.dirname(require$$1$2.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-XgWTq_HC.cjs', document.baseURI).href))));
81468
+ path$7.dirname(require$$1$2.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DG03bxlI.cjs', document.baseURI).href))));
81160
81469
  const authMiddleware = (passKey) => {
81161
81470
  return async (ctx, next) => {
81162
81471
  const authHeader = ctx.headers["authorization"] || ctx.request.query.auth;
package/lib/index.cjs CHANGED
@@ -3715,7 +3715,7 @@ const {
3715
3715
  Help,
3716
3716
  } = commander;
3717
3717
 
3718
- var version = "3.12.1";
3718
+ var version = "3.13.1";
3719
3719
 
3720
3720
  process.on("uncaughtException", function (error) {
3721
3721
  console.error(`${new Date().toISOString()} uncaughtException`, error);
@@ -3741,8 +3741,8 @@ program
3741
3741
  throw new Error(`${c.configFolder}参数不存在,请先重新运行 config gen 命令`);
3742
3742
  }
3743
3743
  // 下面两行顺序不能换(
3744
- const { init } = await Promise.resolve().then(function () { return require('./index-BeyiZ-FP.cjs'); }).then(function (n) { return n.index; });
3745
- const { serverStart } = await Promise.resolve().then(function () { return require('./index-XgWTq_HC.cjs'); });
3744
+ const { init } = await Promise.resolve().then(function () { return require('./index-CgpPN0zA.cjs'); }).then(function (n) { return n.index; });
3745
+ const { serverStart } = await Promise.resolve().then(function () { return require('./index-DG03bxlI.cjs'); });
3746
3746
  const globalConfig = {
3747
3747
  ffmpegPresetPath: path$1.join(c.configFolder, "ffmpeg_presets.json"),
3748
3748
  videoPresetPath: path$1.join(c.configFolder, "presets.json"),
@@ -4,7 +4,7 @@ var os$3 = require('node:os');
4
4
  var path$5 = require('node:path');
5
5
  var fs$3 = require('node:fs');
6
6
  var crypto = require('node:crypto');
7
- var index = require('./index-BeyiZ-FP.cjs');
7
+ var index = require('./index-CgpPN0zA.cjs');
8
8
  var require$$0$1 = require('fs');
9
9
  var require$$0 = require('path');
10
10
  var require$$0$2 = require('child_process');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bililive-cli",
3
- "version": "3.12.1",
3
+ "version": "3.13.1",
4
4
  "type": "module",
5
5
  "description": "biliLive-tools的cli程序",
6
6
  "main": "./lib/index.js",
@@ -39,9 +39,9 @@
39
39
  "commander": "^12.1.0",
40
40
  "rimraf": "^6.0.1",
41
41
  "tsx": "^4.19.2",
42
- "@biliLive-tools/http": "3.12.1",
43
- "@biliLive-tools/shared": "3.12.1",
44
- "@biliLive-tools/types": "3.12.1"
42
+ "@biliLive-tools/http": "3.13.1",
43
+ "@biliLive-tools/types": "3.13.1",
44
+ "@biliLive-tools/shared": "3.13.1"
45
45
  },
46
46
  "scripts": {
47
47
  "start": "tsx src/index.ts",