bililive-cli 3.12.0 → 3.13.0
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.
|
@@ -11363,12 +11363,12 @@ const APP_DEFAULT_CONFIG = {
|
|
|
11363
11363
|
hotProgressColor: "#f9f5f3",
|
|
11364
11364
|
hotProgressFillColor: "#333333",
|
|
11365
11365
|
convert2Mp4: false,
|
|
11366
|
-
removeSourceAferrConvert2Mp4: true,
|
|
11367
11366
|
flvRepair: false,
|
|
11368
11367
|
syncId: undefined,
|
|
11369
11368
|
uploadHandleTime: ["00:00:00", "23:59:59"],
|
|
11370
11369
|
limitUploadTime: false,
|
|
11371
11370
|
uploadNoDanmu: false,
|
|
11371
|
+
uploadToSameMedia: false,
|
|
11372
11372
|
noDanmuVideoPreset: undefined,
|
|
11373
11373
|
limitVideoConvertTime: false,
|
|
11374
11374
|
videoHandleTime: ["00:00:00", "23:59:59"],
|
|
@@ -54494,7 +54494,7 @@ async function trash(paths, options) {
|
|
|
54494
54494
|
} else if (process$2.platform === 'win32') {
|
|
54495
54495
|
module = await Promise.resolve().then(function () { return require('./windows-OmnJ7a39.cjs'); });
|
|
54496
54496
|
} else {
|
|
54497
|
-
module = await Promise.resolve().then(function () { return require('./linux-
|
|
54497
|
+
module = await Promise.resolve().then(function () { return require('./linux-CXmRE85w.cjs'); });
|
|
54498
54498
|
}
|
|
54499
54499
|
|
|
54500
54500
|
return module.default(paths);
|
|
@@ -65707,8 +65707,9 @@ class Platform extends BaseRequest {
|
|
|
65707
65707
|
*/
|
|
65708
65708
|
async editMediaWebApi(videos, options, mode) {
|
|
65709
65709
|
this.auth.authLogin();
|
|
65710
|
+
const { sortByCid, ...mediaOptions } = options;
|
|
65710
65711
|
const archive = await this.getArchive({
|
|
65711
|
-
aid:
|
|
65712
|
+
aid: mediaOptions.aid,
|
|
65712
65713
|
});
|
|
65713
65714
|
const archiveData = archive.archive;
|
|
65714
65715
|
for (const key of [
|
|
@@ -65725,9 +65726,9 @@ class Platform extends BaseRequest {
|
|
|
65725
65726
|
videos: [],
|
|
65726
65727
|
...archiveData,
|
|
65727
65728
|
csrf: csrf,
|
|
65728
|
-
...
|
|
65729
|
+
...mediaOptions,
|
|
65729
65730
|
watermark: {
|
|
65730
|
-
state:
|
|
65731
|
+
state: mediaOptions.watermark?.state ?? archive.watermark.state,
|
|
65731
65732
|
},
|
|
65732
65733
|
};
|
|
65733
65734
|
this.checkOptions(data);
|
|
@@ -65740,10 +65741,10 @@ class Platform extends BaseRequest {
|
|
|
65740
65741
|
data.desc = this.convertDescV2ToDesc(data.desc_v2);
|
|
65741
65742
|
}
|
|
65742
65743
|
if (mode === "append") {
|
|
65743
|
-
data.videos = [...archive.videos, ...videos];
|
|
65744
|
+
data.videos = this.sortVideosByCid([...archive.videos, ...videos], sortByCid);
|
|
65744
65745
|
}
|
|
65745
65746
|
else if (mode === "replace") {
|
|
65746
|
-
data.videos = videos;
|
|
65747
|
+
data.videos = this.sortVideosByCid(videos, sortByCid);
|
|
65747
65748
|
}
|
|
65748
65749
|
else {
|
|
65749
65750
|
throw new Error("mode can only be append or replace");
|
|
@@ -65872,6 +65873,29 @@ class Platform extends BaseRequest {
|
|
|
65872
65873
|
// }
|
|
65873
65874
|
return true;
|
|
65874
65875
|
}
|
|
65876
|
+
sortVideosByCid(videos, cidOrder) {
|
|
65877
|
+
if (!cidOrder || cidOrder.length === 0) {
|
|
65878
|
+
return videos;
|
|
65879
|
+
}
|
|
65880
|
+
const orderMap = new Map();
|
|
65881
|
+
cidOrder.forEach((cid, index) => {
|
|
65882
|
+
if (!orderMap.has(cid)) {
|
|
65883
|
+
orderMap.set(cid, index);
|
|
65884
|
+
}
|
|
65885
|
+
});
|
|
65886
|
+
const matchedVideos = [];
|
|
65887
|
+
const unmatchedVideos = [];
|
|
65888
|
+
videos.forEach(video => {
|
|
65889
|
+
const order = orderMap.get(video.cid);
|
|
65890
|
+
if (order === undefined) {
|
|
65891
|
+
unmatchedVideos.push(video);
|
|
65892
|
+
return;
|
|
65893
|
+
}
|
|
65894
|
+
matchedVideos.push({ video, order });
|
|
65895
|
+
});
|
|
65896
|
+
matchedVideos.sort((left, right) => left.order - right.order);
|
|
65897
|
+
return [...matchedVideos.map(item => item.video), ...unmatchedVideos];
|
|
65898
|
+
}
|
|
65875
65899
|
/**
|
|
65876
65900
|
* 获取推荐标签
|
|
65877
65901
|
* subtype,title,description三个参数对结果影响较大
|
|
@@ -66923,7 +66947,10 @@ class Video extends BaseRequest {
|
|
|
66923
66947
|
const duration = detail.View?.duration;
|
|
66924
66948
|
if (!duration)
|
|
66925
66949
|
throw new Error("视频时长获取失败");
|
|
66926
|
-
const
|
|
66950
|
+
const part = detail.View?.pages?.find((p) => p.cid === params.cid);
|
|
66951
|
+
if (!part)
|
|
66952
|
+
throw new Error("未找到对应cid的视频分P");
|
|
66953
|
+
const totalSegment = Math.ceil(part.duration / 360);
|
|
66927
66954
|
const dmList = [];
|
|
66928
66955
|
// 从1开始
|
|
66929
66956
|
for (let i = 0; i < totalSegment; i++) {
|
|
@@ -179736,31 +179763,119 @@ async function drawSmoothLineChart(data, width, height) {
|
|
|
179736
179763
|
return canvas$1;
|
|
179737
179764
|
}
|
|
179738
179765
|
|
|
179766
|
+
const createEmptyXmlBuckets = () => ({
|
|
179767
|
+
danmu: [],
|
|
179768
|
+
sc: [],
|
|
179769
|
+
guard: [],
|
|
179770
|
+
gift: [],
|
|
179771
|
+
});
|
|
179772
|
+
const isXmlDanmuItemType = (value) => {
|
|
179773
|
+
return ["danmu", "sc", "guard", "gift"].includes(String(value));
|
|
179774
|
+
};
|
|
179775
|
+
const isValidXmlItemForType = (type, item) => {
|
|
179776
|
+
if (type === "danmu") {
|
|
179777
|
+
return typeof item["@_p"] === "string" && item["@_p"].length > 0;
|
|
179778
|
+
}
|
|
179779
|
+
return ((typeof item["@_ts"] === "string" && item["@_ts"].length > 0) ||
|
|
179780
|
+
typeof item["@_ts"] === "number");
|
|
179781
|
+
};
|
|
179782
|
+
const logInvalidTransformedItem = (reason, sourceType, item, targetType) => {
|
|
179783
|
+
logObj.error("filterFunction transform item dropped", {
|
|
179784
|
+
reason,
|
|
179785
|
+
sourceType,
|
|
179786
|
+
targetType,
|
|
179787
|
+
item,
|
|
179788
|
+
});
|
|
179789
|
+
};
|
|
179790
|
+
const createFilterFunction = (filterFunction) => {
|
|
179791
|
+
if (!filterFunction.includes("filter")) {
|
|
179792
|
+
return;
|
|
179793
|
+
}
|
|
179794
|
+
return new Function("type", "danmu", "logger", `
|
|
179795
|
+
${filterFunction}
|
|
179796
|
+
return filter(type, danmu, logger);`);
|
|
179797
|
+
};
|
|
179798
|
+
const createTransformFunction = (filterFunction) => {
|
|
179799
|
+
if (!filterFunction.includes("transform")) {
|
|
179800
|
+
return;
|
|
179801
|
+
}
|
|
179802
|
+
return new Function("type", "danmu", "logger", `
|
|
179803
|
+
${filterFunction}
|
|
179804
|
+
return transform(type, danmu, logger);`);
|
|
179805
|
+
};
|
|
179806
|
+
const transformXmlItem = (sourceType, item, transformFunc) => {
|
|
179807
|
+
const transformed = transformFunc(sourceType, item, logObj);
|
|
179808
|
+
if (transformed == null || transformed === false) {
|
|
179809
|
+
return null;
|
|
179810
|
+
}
|
|
179811
|
+
const candidate = transformed === true || transformed === undefined ? item : transformed;
|
|
179812
|
+
if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) {
|
|
179813
|
+
logInvalidTransformedItem("transform must return an object", sourceType, candidate);
|
|
179814
|
+
return null;
|
|
179815
|
+
}
|
|
179816
|
+
const nextType = "type" in candidate ? candidate.type : sourceType;
|
|
179817
|
+
if (!isXmlDanmuItemType(nextType)) {
|
|
179818
|
+
logInvalidTransformedItem("unsupported target type", sourceType, candidate, nextType);
|
|
179819
|
+
return null;
|
|
179820
|
+
}
|
|
179821
|
+
const normalizedItem = { ...candidate };
|
|
179822
|
+
delete normalizedItem.type;
|
|
179823
|
+
if (!isValidXmlItemForType(nextType, normalizedItem)) {
|
|
179824
|
+
logInvalidTransformedItem("missing required fields for target type", sourceType, candidate, nextType);
|
|
179825
|
+
return null;
|
|
179826
|
+
}
|
|
179827
|
+
return {
|
|
179828
|
+
type: nextType,
|
|
179829
|
+
item: normalizedItem,
|
|
179830
|
+
};
|
|
179831
|
+
};
|
|
179832
|
+
const processXmlItems = (events, filterFunction) => {
|
|
179833
|
+
const buckets = createEmptyXmlBuckets();
|
|
179834
|
+
const filterFunc = createFilterFunction(filterFunction);
|
|
179835
|
+
const transformFunc = createTransformFunction(filterFunction);
|
|
179836
|
+
for (const event of events) {
|
|
179837
|
+
if (filterFunc && !filterFunc(event.sourceType, event.item, logObj)) {
|
|
179838
|
+
continue;
|
|
179839
|
+
}
|
|
179840
|
+
if (!transformFunc) {
|
|
179841
|
+
buckets[event.sourceType].push(event.item);
|
|
179842
|
+
continue;
|
|
179843
|
+
}
|
|
179844
|
+
const transformedItem = transformXmlItem(event.sourceType, event.item, transformFunc);
|
|
179845
|
+
if (!transformedItem) {
|
|
179846
|
+
continue;
|
|
179847
|
+
}
|
|
179848
|
+
buckets[transformedItem.type].push(transformedItem.item);
|
|
179849
|
+
}
|
|
179850
|
+
return buckets;
|
|
179851
|
+
};
|
|
179852
|
+
const createXmlEvents = (items, sourceType) => {
|
|
179853
|
+
const result = [];
|
|
179854
|
+
for (const item of items) {
|
|
179855
|
+
result.push({
|
|
179856
|
+
sourceType,
|
|
179857
|
+
item,
|
|
179858
|
+
});
|
|
179859
|
+
}
|
|
179860
|
+
return result;
|
|
179861
|
+
};
|
|
179739
179862
|
/**
|
|
179740
|
-
*
|
|
179863
|
+
* 生成经过自定义处理后的xml文件
|
|
179741
179864
|
* @param input
|
|
179742
179865
|
* @param output
|
|
179743
|
-
* @param
|
|
179866
|
+
* @param options
|
|
179744
179867
|
* @returns
|
|
179745
179868
|
*/
|
|
179746
|
-
const
|
|
179747
|
-
const filterFunc = new Function("type", "danmu", "logger", `
|
|
179748
|
-
${filterFunction}
|
|
179749
|
-
return filter(type, danmu, logger);`);
|
|
179869
|
+
const genProcessedXml = async (input, output, filterFunction) => {
|
|
179750
179870
|
const { jObj, danmuku, sc, guard, gift } = await parseXmlFile(input, true);
|
|
179751
|
-
const
|
|
179752
|
-
|
|
179753
|
-
|
|
179754
|
-
|
|
179755
|
-
|
|
179756
|
-
|
|
179757
|
-
const
|
|
179758
|
-
|
|
179759
|
-
});
|
|
179760
|
-
const filteredGift = gift.filter((item) => {
|
|
179761
|
-
return filterFunc("gift", item, logObj);
|
|
179762
|
-
});
|
|
179763
|
-
const xmlData = generateMergedXmlContent(filteredDanmuku, filteredGift, filteredSc, filteredGuard, jObj.i?.metadata || {});
|
|
179871
|
+
const events = [
|
|
179872
|
+
...createXmlEvents(danmuku, "danmu"),
|
|
179873
|
+
...createXmlEvents(sc, "sc"),
|
|
179874
|
+
...createXmlEvents(guard, "guard"),
|
|
179875
|
+
...createXmlEvents(gift, "gift"),
|
|
179876
|
+
];
|
|
179877
|
+
const processedBuckets = processXmlItems(events, filterFunction);
|
|
179878
|
+
const xmlData = generateMergedXmlContent(processedBuckets.danmu, processedBuckets.gift, processedBuckets.sc, processedBuckets.guard, jObj.i?.metadata || {});
|
|
179764
179879
|
await fs$k.writeFile(output, xmlData);
|
|
179765
179880
|
return output;
|
|
179766
179881
|
};
|
|
@@ -179785,10 +179900,13 @@ const addConvertDanmu2AssTask = async (originInput, output, danmuOptions, option
|
|
|
179785
179900
|
opts = await customChangeFunc(originInput, opts);
|
|
179786
179901
|
}
|
|
179787
179902
|
let filteredOutput;
|
|
179788
|
-
|
|
179789
|
-
|
|
179903
|
+
const hasFilterFunction = Boolean((opts.filterFunction ?? "").trim()) && (opts.filterFunction ?? "").includes("filter");
|
|
179904
|
+
const hasTransformFunction = Boolean((opts.filterFunction ?? "").trim()) &&
|
|
179905
|
+
(opts.filterFunction ?? "").includes("transform");
|
|
179906
|
+
if (hasTransformFunction || hasFilterFunction) {
|
|
179907
|
+
// 如果存在自定义数据处理函数,则需要把处理后的xml保存到临时文件夹中
|
|
179790
179908
|
filteredOutput = path$y.join(tempDir, `${uuid$5()}.xml`);
|
|
179791
|
-
await
|
|
179909
|
+
await genProcessedXml(originInput, filteredOutput, opts.filterFunction);
|
|
179792
179910
|
}
|
|
179793
179911
|
if (opts.blacklist) {
|
|
179794
179912
|
const fileTxtPath = path$y.join(tempDir, `${uuid$5()}.txt`);
|
|
@@ -181468,8 +181586,10 @@ async function addMediaApi(uid, video, options) {
|
|
|
181468
181586
|
* 编辑视频接口
|
|
181469
181587
|
*/
|
|
181470
181588
|
async function editMediaApi(uid, aid, video, options) {
|
|
181471
|
-
const mediaOptions = {
|
|
181472
|
-
|
|
181589
|
+
const mediaOptions = {
|
|
181590
|
+
sortByCid: options.sortByCid,
|
|
181591
|
+
};
|
|
181592
|
+
// console.log("编辑视频", options);
|
|
181473
181593
|
// const globalConfig = container.resolve("globalConfig");
|
|
181474
181594
|
// const mediaOptions = formatOptions(options, path.join(globalConfig.userDataPath, "cover"));
|
|
181475
181595
|
const client = createClient(uid);
|
|
@@ -181808,6 +181928,7 @@ async function editMedia(aid, filePath, options, uid, extraOptions) {
|
|
|
181808
181928
|
uid,
|
|
181809
181929
|
mediaOptions: formattedOptions,
|
|
181810
181930
|
aid,
|
|
181931
|
+
sortParams: extraOptions?.sortParams,
|
|
181811
181932
|
}, {
|
|
181812
181933
|
onEnd: async () => {
|
|
181813
181934
|
// 审核检查
|
|
@@ -182159,6 +182280,8 @@ const biliApi = {
|
|
|
182159
182280
|
editVideoPartName,
|
|
182160
182281
|
queryVideoStatus,
|
|
182161
182282
|
getPlayUrl,
|
|
182283
|
+
readUser,
|
|
182284
|
+
writeUser,
|
|
182162
182285
|
};
|
|
182163
182286
|
|
|
182164
182287
|
/**
|
|
@@ -184110,11 +184233,14 @@ class BiliPartVideoTask extends AbstractTask {
|
|
|
184110
184233
|
logObj.error(`task ${this.taskId} error: ${error}`);
|
|
184111
184234
|
}
|
|
184112
184235
|
}
|
|
184113
|
-
this.completedPart =
|
|
184236
|
+
this.completedPart = {
|
|
184237
|
+
...data,
|
|
184238
|
+
filePath: this.command.filePath,
|
|
184239
|
+
};
|
|
184114
184240
|
this.endTime = Date.now();
|
|
184115
184241
|
// 重置进度追踪
|
|
184116
184242
|
this.speedCalculator.reset();
|
|
184117
|
-
callback.onEnd && callback.onEnd(
|
|
184243
|
+
callback.onEnd && callback.onEnd(this.completedPart);
|
|
184118
184244
|
this.emitter.emit("task-end", { taskId: this.taskId });
|
|
184119
184245
|
});
|
|
184120
184246
|
command.emitter.on("error", (err) => {
|
|
@@ -184161,6 +184287,7 @@ class BiliPartVideoTask extends AbstractTask {
|
|
|
184161
184287
|
cid: part.cid,
|
|
184162
184288
|
filename: part.filename,
|
|
184163
184289
|
title: this.command.title,
|
|
184290
|
+
filePath: this.command.filePath,
|
|
184164
184291
|
};
|
|
184165
184292
|
this.endTime = Date.now();
|
|
184166
184293
|
// 重置进度追踪
|
|
@@ -184365,7 +184492,7 @@ class BiliAddVideoTask extends BiliVideoTask {
|
|
|
184365
184492
|
this.progress = 100;
|
|
184366
184493
|
this.callback.onEnd && this.callback.onEnd(data);
|
|
184367
184494
|
this.output = String(data.aid);
|
|
184368
|
-
this.emitter.emit("task-end", { taskId: this.taskId });
|
|
184495
|
+
this.emitter.emit("task-end", { taskId: this.taskId, data: parts });
|
|
184369
184496
|
uploadPartService.removeByCids(parts.map((part) => part.cid));
|
|
184370
184497
|
exports.statisticsService.addOrUpdate({
|
|
184371
184498
|
where: { stat_key: this.lastUpdateTimeKey },
|
|
@@ -184391,10 +184518,12 @@ class BiliAddVideoTask extends BiliVideoTask {
|
|
|
184391
184518
|
class BiliEditVideoTask extends BiliVideoTask {
|
|
184392
184519
|
aid;
|
|
184393
184520
|
mediaOptions;
|
|
184521
|
+
sortParams;
|
|
184394
184522
|
constructor(options, callback) {
|
|
184395
184523
|
super(options, callback);
|
|
184396
184524
|
this.aid = options.aid;
|
|
184397
184525
|
this.mediaOptions = options.mediaOptions;
|
|
184526
|
+
this.sortParams = options.sortParams;
|
|
184398
184527
|
this.on("completed", () => {
|
|
184399
184528
|
this.submit();
|
|
184400
184529
|
});
|
|
@@ -184439,12 +184568,26 @@ class BiliEditVideoTask extends BiliVideoTask {
|
|
|
184439
184568
|
return;
|
|
184440
184569
|
}
|
|
184441
184570
|
try {
|
|
184442
|
-
const
|
|
184571
|
+
const sortByCid = [];
|
|
184572
|
+
if (this.sortParams && Array.isArray(this.sortParams)) {
|
|
184573
|
+
for (const param of this.sortParams) {
|
|
184574
|
+
if (param.cid) {
|
|
184575
|
+
sortByCid.push(param.cid);
|
|
184576
|
+
}
|
|
184577
|
+
else {
|
|
184578
|
+
const part = parts.find((p) => p.filePath === param.filePath);
|
|
184579
|
+
if (part) {
|
|
184580
|
+
sortByCid.push(part.cid);
|
|
184581
|
+
}
|
|
184582
|
+
}
|
|
184583
|
+
}
|
|
184584
|
+
}
|
|
184585
|
+
const data = await retryWithAxiosError(() => editMediaApi(this.uid, this.aid, parts, { ...this.mediaOptions, sortByCid: sortByCid }), 5);
|
|
184443
184586
|
this.status = "completed";
|
|
184444
184587
|
this.progress = 100;
|
|
184445
184588
|
this.callback.onEnd && this.callback.onEnd(data);
|
|
184446
184589
|
this.output = String(data.aid);
|
|
184447
|
-
this.emitter.emit("task-end", { taskId: this.taskId });
|
|
184590
|
+
this.emitter.emit("task-end", { taskId: this.taskId, data: parts });
|
|
184448
184591
|
uploadPartService.removeByCids(parts.map((part) => part.cid));
|
|
184449
184592
|
exports.statisticsService.addOrUpdate({
|
|
184450
184593
|
where: { stat_key: this.lastUpdateTimeKey },
|
|
@@ -185517,7 +185660,7 @@ function getValuesFromArrayLikeFlexSpaceBetween(array, columnCount) {
|
|
|
185517
185660
|
});
|
|
185518
185661
|
return columnValues;
|
|
185519
185662
|
}
|
|
185520
|
-
function ensureFolderExist
|
|
185663
|
+
function ensureFolderExist(fileOrFolderPath) {
|
|
185521
185664
|
const folder = path$y.dirname(fileOrFolderPath);
|
|
185522
185665
|
if (!fs$D.existsSync(folder)) {
|
|
185523
185666
|
fs$D.mkdirSync(folder, { recursive: true });
|
|
@@ -185926,7 +186069,7 @@ var utils$2 = {
|
|
|
185926
186069
|
replaceExtName,
|
|
185927
186070
|
singleton: singleton$1,
|
|
185928
186071
|
getValuesFromArrayLikeFlexSpaceBetween,
|
|
185929
|
-
ensureFolderExist
|
|
186072
|
+
ensureFolderExist,
|
|
185930
186073
|
assert: assert$m,
|
|
185931
186074
|
assertStringType,
|
|
185932
186075
|
assertNumberType,
|
|
@@ -186408,11 +186551,20 @@ class Segment extends EventEmitter$j {
|
|
|
186408
186551
|
});
|
|
186409
186552
|
}
|
|
186410
186553
|
}
|
|
186411
|
-
|
|
186554
|
+
let recordSavePath = this.getSavePath({
|
|
186412
186555
|
startTime: startTime,
|
|
186413
|
-
title: liveInfo?.title,
|
|
186556
|
+
title: liveInfo?.title ? liveInfo.title : undefined,
|
|
186414
186557
|
});
|
|
186415
|
-
|
|
186558
|
+
// 文件重复判断
|
|
186559
|
+
if (require$$0$6.existsSync(recordSavePath + "." + this.videoExt)) {
|
|
186560
|
+
recordSavePath = this.getSavePath({
|
|
186561
|
+
startTime: startTime,
|
|
186562
|
+
title: liveInfo?.title,
|
|
186563
|
+
extraMs: true,
|
|
186564
|
+
});
|
|
186565
|
+
}
|
|
186566
|
+
this.outputVideoFilePath = recordSavePath;
|
|
186567
|
+
ensureFolderExist(this.outputVideoFilePath);
|
|
186416
186568
|
if (!this.disableDanma) {
|
|
186417
186569
|
this.extraDataController = createRecordExtraDataController(`${this.outputVideoFilePath}.xml`);
|
|
186418
186570
|
}
|
|
@@ -186456,12 +186608,19 @@ class StreamManager extends EventEmitter$j {
|
|
|
186456
186608
|
callBack;
|
|
186457
186609
|
constructor(getSavePath, hasSegment, disableDanma, recorderType, videoFormat, callBack) {
|
|
186458
186610
|
super();
|
|
186459
|
-
const
|
|
186460
|
-
|
|
186611
|
+
const startTime = Date.now();
|
|
186612
|
+
let recordSavePath = getSavePath({ startTime });
|
|
186461
186613
|
this.videoFormat = videoFormat;
|
|
186462
186614
|
this.recorderType = recorderType;
|
|
186463
186615
|
this.hasSegment = hasSegment;
|
|
186464
186616
|
this.callBack = callBack;
|
|
186617
|
+
console.log("Initial recordSavePath:", recordSavePath);
|
|
186618
|
+
// 文件重复判断
|
|
186619
|
+
if (require$$0$6.existsSync(recordSavePath + "." + videoFormat)) {
|
|
186620
|
+
console.log("File already exists, generating new save path with extraMs");
|
|
186621
|
+
recordSavePath = getSavePath({ startTime, extraMs: true });
|
|
186622
|
+
}
|
|
186623
|
+
this.recordSavePath = recordSavePath;
|
|
186465
186624
|
if (hasSegment) {
|
|
186466
186625
|
this.segment = new Segment(getSavePath, disableDanma, this.videoExt);
|
|
186467
186626
|
this.segment.on("DebugLog", (data) => {
|
|
@@ -186475,6 +186634,7 @@ class StreamManager extends EventEmitter$j {
|
|
|
186475
186634
|
});
|
|
186476
186635
|
}
|
|
186477
186636
|
else {
|
|
186637
|
+
ensureFolderExist(recordSavePath);
|
|
186478
186638
|
const extraDataSavePath = `${recordSavePath}.xml`;
|
|
186479
186639
|
if (!disableDanma) {
|
|
186480
186640
|
this.extraDataController = createRecordExtraDataController(extraDataSavePath);
|
|
@@ -186932,6 +187092,9 @@ function genSavePathFromRule(manager, recorder, extData) {
|
|
|
186932
187092
|
channelId,
|
|
186933
187093
|
};
|
|
186934
187094
|
let savePathRule = manager.savePathRule;
|
|
187095
|
+
if (extData?.extraMs) {
|
|
187096
|
+
savePathRule += "_{ms}";
|
|
187097
|
+
}
|
|
186935
187098
|
try {
|
|
186936
187099
|
savePathRule = ejs.render(savePathRule, params);
|
|
186937
187100
|
}
|
|
@@ -187331,6 +187494,11 @@ class BililiveDownloader extends EventEmitter$j {
|
|
|
187331
187494
|
if (timeMatch) {
|
|
187332
187495
|
time = timeMatch[1];
|
|
187333
187496
|
}
|
|
187497
|
+
const spaceMath = line.match(/下载进度:\s*([\d.]+\s*MB)\s*/);
|
|
187498
|
+
if (spaceMath) {
|
|
187499
|
+
const space = spaceMath[1];
|
|
187500
|
+
time = time ? `${time} ${space}` : space;
|
|
187501
|
+
}
|
|
187334
187502
|
return {
|
|
187335
187503
|
time,
|
|
187336
187504
|
};
|
|
@@ -187590,7 +187758,7 @@ class FFmpegDownloader extends EventEmitter$j {
|
|
|
187590
187758
|
let time = null;
|
|
187591
187759
|
const timeMatch = line.match(/time=([0-9:.]+)/);
|
|
187592
187760
|
if (timeMatch) {
|
|
187593
|
-
time = timeMatch[1];
|
|
187761
|
+
time = timeMatch[1].split(".")[0];
|
|
187594
187762
|
}
|
|
187595
187763
|
return {
|
|
187596
187764
|
time,
|
|
@@ -187694,12 +187862,6 @@ function getBililivePath() {
|
|
|
187694
187862
|
return bililivePath;
|
|
187695
187863
|
}
|
|
187696
187864
|
|
|
187697
|
-
function ensureFolderExist$4(fileOrFolderPath) {
|
|
187698
|
-
const folder = path$y.dirname(fileOrFolderPath);
|
|
187699
|
-
if (!fs$D.existsSync(folder)) {
|
|
187700
|
-
fs$D.mkdirSync(folder, { recursive: true });
|
|
187701
|
-
}
|
|
187702
|
-
}
|
|
187703
187865
|
const uuid$1 = () => {
|
|
187704
187866
|
return crypto$c.randomUUID();
|
|
187705
187867
|
};
|
|
@@ -195043,6 +195205,7 @@ const checkLiveStatusAndRecord$4 = async function ({ getSavePath, banLiveId, isM
|
|
|
195043
195205
|
startTime: opts.startTime,
|
|
195044
195206
|
liveStartTime,
|
|
195045
195207
|
recordStartTime,
|
|
195208
|
+
extraMs: opts.extraMs,
|
|
195046
195209
|
}),
|
|
195047
195210
|
disableDanma: this.disableProvideCommentsWhenRecording,
|
|
195048
195211
|
videoFormat: this.videoFormat ?? "auto",
|
|
@@ -195052,20 +195215,6 @@ const checkLiveStatusAndRecord$4 = async function ({ getSavePath, banLiveId, isM
|
|
|
195052
195215
|
const info = await getInfo$4(this.channelId);
|
|
195053
195216
|
return info;
|
|
195054
195217
|
});
|
|
195055
|
-
const savePath = getSavePath({
|
|
195056
|
-
owner,
|
|
195057
|
-
title,
|
|
195058
|
-
startTime: Date.now(),
|
|
195059
|
-
liveStartTime,
|
|
195060
|
-
recordStartTime,
|
|
195061
|
-
});
|
|
195062
|
-
try {
|
|
195063
|
-
ensureFolderExist$4(savePath);
|
|
195064
|
-
}
|
|
195065
|
-
catch (err) {
|
|
195066
|
-
this.state = "idle";
|
|
195067
|
-
throw err;
|
|
195068
|
-
}
|
|
195069
195218
|
const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
|
|
195070
195219
|
this.emit("videoFileCreated", { filename, cover, rawFilename });
|
|
195071
195220
|
if (title && this?.liveInfo) {
|
|
@@ -195277,7 +195426,7 @@ const checkLiveStatusAndRecord$4 = async function ({ getSavePath, banLiveId, isM
|
|
|
195277
195426
|
recorderType: downloader.type,
|
|
195278
195427
|
url: stream.url,
|
|
195279
195428
|
downloaderArgs,
|
|
195280
|
-
savePath:
|
|
195429
|
+
savePath: downloader.videoFilePath,
|
|
195281
195430
|
stop,
|
|
195282
195431
|
cut,
|
|
195283
195432
|
};
|
|
@@ -196180,12 +196329,6 @@ const requester$2 = axios.create({
|
|
|
196180
196329
|
proxy: false,
|
|
196181
196330
|
});
|
|
196182
196331
|
|
|
196183
|
-
function ensureFolderExist$3(fileOrFolderPath) {
|
|
196184
|
-
const folder = path$y.dirname(fileOrFolderPath);
|
|
196185
|
-
if (!fs$D.existsSync(folder)) {
|
|
196186
|
-
fs$D.mkdirSync(folder, { recursive: true });
|
|
196187
|
-
}
|
|
196188
|
-
}
|
|
196189
196332
|
function assert$l(assertion, msg) {
|
|
196190
196333
|
if (!assertion) {
|
|
196191
196334
|
throw new Error(msg);
|
|
@@ -211223,6 +211366,7 @@ const checkLiveStatusAndRecord$3 = async function ({ getSavePath, banLiveId, isM
|
|
|
211223
211366
|
startTime: opts.startTime,
|
|
211224
211367
|
liveStartTime,
|
|
211225
211368
|
recordStartTime,
|
|
211369
|
+
extraMs: opts.extraMs,
|
|
211226
211370
|
}),
|
|
211227
211371
|
disableDanma: this.disableProvideCommentsWhenRecording,
|
|
211228
211372
|
videoFormat: this.videoFormat ?? "auto",
|
|
@@ -211234,20 +211378,6 @@ const checkLiveStatusAndRecord$3 = async function ({ getSavePath, banLiveId, isM
|
|
|
211234
211378
|
const info = await getInfo$3(this.channelId);
|
|
211235
211379
|
return info;
|
|
211236
211380
|
});
|
|
211237
|
-
const savePath = getSavePath({
|
|
211238
|
-
owner,
|
|
211239
|
-
title,
|
|
211240
|
-
startTime: Date.now(),
|
|
211241
|
-
liveStartTime,
|
|
211242
|
-
recordStartTime,
|
|
211243
|
-
});
|
|
211244
|
-
try {
|
|
211245
|
-
ensureFolderExist$3(savePath);
|
|
211246
|
-
}
|
|
211247
|
-
catch (err) {
|
|
211248
|
-
this.state = "idle";
|
|
211249
|
-
throw err;
|
|
211250
|
-
}
|
|
211251
211381
|
const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
|
|
211252
211382
|
this.emit("videoFileCreated", { filename, cover, rawFilename });
|
|
211253
211383
|
if (title && this?.liveInfo) {
|
|
@@ -211376,7 +211506,7 @@ const checkLiveStatusAndRecord$3 = async function ({ getSavePath, banLiveId, isM
|
|
|
211376
211506
|
recorderType: downloader.type,
|
|
211377
211507
|
url: stream.url,
|
|
211378
211508
|
downloaderArgs,
|
|
211379
|
-
savePath:
|
|
211509
|
+
savePath: downloader.videoFilePath,
|
|
211380
211510
|
stop,
|
|
211381
211511
|
cut,
|
|
211382
211512
|
};
|
|
@@ -211413,12 +211543,6 @@ const provider$3 = {
|
|
|
211413
211543
|
},
|
|
211414
211544
|
};
|
|
211415
211545
|
|
|
211416
|
-
function ensureFolderExist$2(fileOrFolderPath) {
|
|
211417
|
-
const folder = path$y.dirname(fileOrFolderPath);
|
|
211418
|
-
if (!fs$D.existsSync(folder)) {
|
|
211419
|
-
fs$D.mkdirSync(folder, { recursive: true });
|
|
211420
|
-
}
|
|
211421
|
-
}
|
|
211422
211546
|
function assert$j(assertion, msg) {
|
|
211423
211547
|
if (!assertion) {
|
|
211424
211548
|
throw new Error(msg);
|
|
@@ -212924,6 +213048,7 @@ const checkLiveStatusAndRecord$2 = async function ({ getSavePath, isManualStart,
|
|
|
212924
213048
|
startTime: opts.startTime,
|
|
212925
213049
|
liveStartTime: liveStartTime,
|
|
212926
213050
|
recordStartTime,
|
|
213051
|
+
extraMs: opts.extraMs,
|
|
212927
213052
|
}),
|
|
212928
213053
|
formatName: streamOptions.format_name,
|
|
212929
213054
|
disableDanma: this.disableProvideCommentsWhenRecording,
|
|
@@ -212936,20 +213061,6 @@ const checkLiveStatusAndRecord$2 = async function ({ getSavePath, isManualStart,
|
|
|
212936
213061
|
const info = await getInfo$2(this.channelId);
|
|
212937
213062
|
return info;
|
|
212938
213063
|
});
|
|
212939
|
-
const savePath = getSavePath({
|
|
212940
|
-
owner,
|
|
212941
|
-
title,
|
|
212942
|
-
startTime: Date.now(),
|
|
212943
|
-
liveStartTime: liveStartTime,
|
|
212944
|
-
recordStartTime,
|
|
212945
|
-
});
|
|
212946
|
-
try {
|
|
212947
|
-
ensureFolderExist$2(savePath);
|
|
212948
|
-
}
|
|
212949
|
-
catch (err) {
|
|
212950
|
-
this.state = "idle";
|
|
212951
|
-
throw err;
|
|
212952
|
-
}
|
|
212953
213064
|
const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
|
|
212954
213065
|
this.emit("videoFileCreated", { filename, cover, rawFilename });
|
|
212955
213066
|
if (title && this?.liveInfo) {
|
|
@@ -213052,7 +213163,7 @@ const checkLiveStatusAndRecord$2 = async function ({ getSavePath, isManualStart,
|
|
|
213052
213163
|
recorderType: downloader.type,
|
|
213053
213164
|
url: stream.url,
|
|
213054
213165
|
downloaderArgs,
|
|
213055
|
-
savePath:
|
|
213166
|
+
savePath: downloader.videoFilePath,
|
|
213056
213167
|
stop,
|
|
213057
213168
|
cut,
|
|
213058
213169
|
};
|
|
@@ -213109,12 +213220,6 @@ function singleton(fn) {
|
|
|
213109
213220
|
return promise;
|
|
213110
213221
|
};
|
|
213111
213222
|
}
|
|
213112
|
-
function ensureFolderExist$1(fileOrFolderPath) {
|
|
213113
|
-
const folder = path$y.dirname(fileOrFolderPath);
|
|
213114
|
-
if (!fs$D.existsSync(folder)) {
|
|
213115
|
-
fs$D.mkdirSync(folder, { recursive: true });
|
|
213116
|
-
}
|
|
213117
|
-
}
|
|
213118
213223
|
function assert$i(assertion, msg) {
|
|
213119
213224
|
if (!assertion) {
|
|
213120
213225
|
throw new Error(msg);
|
|
@@ -249016,6 +249121,7 @@ const checkLiveStatusAndRecord$1 = async function ({ getSavePath, banLiveId, isM
|
|
|
249016
249121
|
startTime: opts.startTime,
|
|
249017
249122
|
liveStartTime: liveStartTime,
|
|
249018
249123
|
recordStartTime,
|
|
249124
|
+
extraMs: opts.extraMs,
|
|
249019
249125
|
}),
|
|
249020
249126
|
disableDanma: this.disableProvideCommentsWhenRecording,
|
|
249021
249127
|
videoFormat: this.videoFormat ?? "auto",
|
|
@@ -249030,20 +249136,6 @@ const checkLiveStatusAndRecord$1 = async function ({ getSavePath, banLiveId, isM
|
|
|
249030
249136
|
});
|
|
249031
249137
|
return info;
|
|
249032
249138
|
});
|
|
249033
|
-
const savePath = getSavePath({
|
|
249034
|
-
owner,
|
|
249035
|
-
title,
|
|
249036
|
-
startTime: Date.now(),
|
|
249037
|
-
liveStartTime,
|
|
249038
|
-
recordStartTime,
|
|
249039
|
-
});
|
|
249040
|
-
try {
|
|
249041
|
-
ensureFolderExist$1(savePath);
|
|
249042
|
-
}
|
|
249043
|
-
catch (err) {
|
|
249044
|
-
this.state = "idle";
|
|
249045
|
-
throw err;
|
|
249046
|
-
}
|
|
249047
249139
|
const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
|
|
249048
249140
|
this.emit("videoFileCreated", { filename, cover, rawFilename });
|
|
249049
249141
|
if (title && this?.liveInfo) {
|
|
@@ -249280,7 +249372,7 @@ const checkLiveStatusAndRecord$1 = async function ({ getSavePath, banLiveId, isM
|
|
|
249280
249372
|
recorderType: downloader.type,
|
|
249281
249373
|
url: stream.url,
|
|
249282
249374
|
downloaderArgs,
|
|
249283
|
-
savePath:
|
|
249375
|
+
savePath: downloader.videoFilePath,
|
|
249284
249376
|
stop,
|
|
249285
249377
|
cut,
|
|
249286
249378
|
};
|
|
@@ -290180,13 +290272,6 @@ async function getStream(opts) {
|
|
|
290180
290272
|
};
|
|
290181
290273
|
}
|
|
290182
290274
|
|
|
290183
|
-
function ensureFolderExist(fileOrFolderPath) {
|
|
290184
|
-
const folder = path$y.dirname(fileOrFolderPath);
|
|
290185
|
-
if (!fs$D.existsSync(folder)) {
|
|
290186
|
-
fs$D.mkdirSync(folder, { recursive: true });
|
|
290187
|
-
}
|
|
290188
|
-
}
|
|
290189
|
-
|
|
290190
290275
|
function createRecorder(opts) {
|
|
290191
290276
|
// 内部实现时,应该只有 proxy 包裹的那一层会使用这个 recorder 标识符,不应该有直接通过
|
|
290192
290277
|
// 此标志来操作这个对象的地方,不然会跳过 proxy 的拦截。
|
|
@@ -290357,6 +290442,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
|
|
|
290357
290442
|
startTime: opts.startTime,
|
|
290358
290443
|
liveStartTime,
|
|
290359
290444
|
recordStartTime,
|
|
290445
|
+
extraMs: opts.extraMs,
|
|
290360
290446
|
}),
|
|
290361
290447
|
disableDanma: this.disableProvideCommentsWhenRecording,
|
|
290362
290448
|
videoFormat: this.videoFormat ?? "auto",
|
|
@@ -290365,20 +290451,6 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
|
|
|
290365
290451
|
const info = await getInfo(roomId);
|
|
290366
290452
|
return info;
|
|
290367
290453
|
});
|
|
290368
|
-
const savePath = getSavePath({
|
|
290369
|
-
owner,
|
|
290370
|
-
title,
|
|
290371
|
-
startTime: Date.now(),
|
|
290372
|
-
liveStartTime,
|
|
290373
|
-
recordStartTime,
|
|
290374
|
-
});
|
|
290375
|
-
try {
|
|
290376
|
-
ensureFolderExist(savePath);
|
|
290377
|
-
}
|
|
290378
|
-
catch (err) {
|
|
290379
|
-
this.state = "idle";
|
|
290380
|
-
throw err;
|
|
290381
|
-
}
|
|
290382
290454
|
const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
|
|
290383
290455
|
this.emit("videoFileCreated", { filename, cover, rawFilename });
|
|
290384
290456
|
if (title && this?.liveInfo) {
|
|
@@ -290445,7 +290517,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
|
|
|
290445
290517
|
recorderType: downloader.type,
|
|
290446
290518
|
url: stream.url,
|
|
290447
290519
|
downloaderArgs,
|
|
290448
|
-
savePath:
|
|
290520
|
+
savePath: downloader.videoFilePath,
|
|
290449
290521
|
stop,
|
|
290450
290522
|
cut,
|
|
290451
290523
|
};
|
|
@@ -290947,27 +291019,27 @@ async function createRecorderManager(appConfig) {
|
|
|
290947
291019
|
// 构建每个平台的检查配置
|
|
290948
291020
|
const providerCheckConfig = {
|
|
290949
291021
|
[provider$2.id]: {
|
|
290950
|
-
autoCheckInterval: config?.recorder?.bilibili.checkInterval ?? autoCheckInterval,
|
|
291022
|
+
autoCheckInterval: (config?.recorder?.bilibili.checkInterval ?? autoCheckInterval) * 1000,
|
|
290951
291023
|
maxThreadCount: config?.recorder?.bilibili.maxThreadCount ?? maxThreadCount,
|
|
290952
291024
|
waitTime: config?.recorder?.bilibili.waitTime ?? waitTime,
|
|
290953
291025
|
},
|
|
290954
291026
|
[provider$4.id]: {
|
|
290955
|
-
autoCheckInterval: config?.recorder?.douyu.checkInterval ?? autoCheckInterval,
|
|
291027
|
+
autoCheckInterval: (config?.recorder?.douyu.checkInterval ?? autoCheckInterval) * 1000,
|
|
290956
291028
|
maxThreadCount: config?.recorder?.douyu.maxThreadCount ?? maxThreadCount,
|
|
290957
291029
|
waitTime: config?.recorder?.douyu.waitTime ?? waitTime,
|
|
290958
291030
|
},
|
|
290959
291031
|
[provider$3.id]: {
|
|
290960
|
-
autoCheckInterval: config?.recorder?.huya.checkInterval ?? autoCheckInterval,
|
|
291032
|
+
autoCheckInterval: (config?.recorder?.huya.checkInterval ?? autoCheckInterval) * 1000,
|
|
290961
291033
|
maxThreadCount: config?.recorder?.huya.maxThreadCount ?? maxThreadCount,
|
|
290962
291034
|
waitTime: config?.recorder?.huya.waitTime ?? waitTime,
|
|
290963
291035
|
},
|
|
290964
291036
|
[provider$1.id]: {
|
|
290965
|
-
autoCheckInterval: config?.recorder?.douyin.checkInterval ?? autoCheckInterval,
|
|
291037
|
+
autoCheckInterval: (config?.recorder?.douyin.checkInterval ?? autoCheckInterval) * 1000,
|
|
290966
291038
|
maxThreadCount: config?.recorder?.douyin.maxThreadCount ?? maxThreadCount,
|
|
290967
291039
|
waitTime: config?.recorder?.douyin.waitTime ?? waitTime,
|
|
290968
291040
|
},
|
|
290969
291041
|
[provider.id]: {
|
|
290970
|
-
autoCheckInterval: config?.recorder?.xhs.checkInterval ?? autoCheckInterval,
|
|
291042
|
+
autoCheckInterval: (config?.recorder?.xhs.checkInterval ?? autoCheckInterval) * 1000,
|
|
290971
291043
|
maxThreadCount: config?.recorder?.xhs.maxThreadCount ?? maxThreadCount,
|
|
290972
291044
|
waitTime: config?.recorder?.xhs.waitTime ?? waitTime,
|
|
290973
291045
|
},
|