@dan-uni/dan-any 0.2.3 → 0.2.6

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.
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as __WEBPACK_EXTERNAL_MODULE_fast_xml_parser_1c5d6bda__ from "fast-xml-parser";
2
2
  import * as __WEBPACK_EXTERNAL_MODULE_canvas__ from "canvas";
3
+ import * as __WEBPACK_EXTERNAL_MODULE_hh_mm_ss_6ead5141__ from "hh-mm-ss";
3
4
  import * as __WEBPACK_EXTERNAL_MODULE_jssha__ from "jssha";
4
5
  import * as __WEBPACK_EXTERNAL_MODULE_node_zlib_a5bb16fc__ from "node:zlib";
5
6
  import * as __WEBPACK_EXTERNAL_MODULE_base16384__ from "base16384";
@@ -4908,11 +4909,25 @@ var dm_gen_ExtraDanUniChapterType = /*#__PURE__*/ function(ExtraDanUniChapterTyp
4908
4909
  ExtraDanUniChapterType["ED"] = "ed";
4909
4910
  ExtraDanUniChapterType["Preview"] = "prvw";
4910
4911
  ExtraDanUniChapterType["Cut"] = "cut";
4911
- ExtraDanUniChapterType["Duplicates"] = "dup";
4912
+ ExtraDanUniChapterType["Duplicate"] = "dup";
4912
4913
  ExtraDanUniChapterType["AdBiz"] = "biz";
4913
4914
  ExtraDanUniChapterType["AdUnpaid"] = "promo";
4914
4915
  return ExtraDanUniChapterType;
4915
4916
  }({});
4917
+ const ExtraDanUniChapterTypeDict = {
4918
+ chs: {
4919
+ ch: '其它片段',
4920
+ rev: '回顾',
4921
+ op: '片头',
4922
+ int: '中场',
4923
+ ed: '片尾',
4924
+ prvw: '预告',
4925
+ cut: '删减',
4926
+ dup: '补档',
4927
+ biz: '商业广告',
4928
+ promo: '推广'
4929
+ }
4930
+ };
4916
4931
  var dm_gen_ExtraDanUniChapterAction = /*#__PURE__*/ function(ExtraDanUniChapterAction) {
4917
4932
  ExtraDanUniChapterAction[ExtraDanUniChapterAction["Disabled"] = -1] = "Disabled";
4918
4933
  ExtraDanUniChapterAction[ExtraDanUniChapterAction["ShowOverlay"] = 0] = "ShowOverlay";
@@ -5038,8 +5053,42 @@ class UniDM {
5038
5053
  }
5039
5054
  return JSON.parse(JSON.stringify(dan));
5040
5055
  }
5041
- downgradeAdvcancedDan() {
5056
+ downgradeAdvcancedDan({ include, exclude, cleanExtra = false } = {
5057
+ include: [],
5058
+ exclude: []
5059
+ }) {
5042
5060
  if (!this.extra) return this;
5061
+ {
5062
+ if (!include) include = [];
5063
+ if (!exclude) exclude = [];
5064
+ const check = (k)=>include?.includes(k) || !exclude?.includes(k);
5065
+ const clone = UniDM.create(this);
5066
+ clone.mode = 2;
5067
+ if (check('danuni') && clone.extra.danuni) {
5068
+ const danuni = clone.extra.danuni;
5069
+ if (danuni.merge) {
5070
+ const merge = danuni.merge;
5071
+ clone.content = `${this.content} x${merge.count}`;
5072
+ } else if (danuni.chapter) {
5073
+ const chapter = danuni.chapter;
5074
+ if ("cut" === chapter.type) clone.content = `[提示]${clone.platform}源${ExtraDanUniChapterTypeDict.chs[chapter.type]}了${chapter.duration}秒`;
5075
+ else if ("dup" === chapter.type) clone.content = `[提示(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${clone.platform}源-${chapter.duration}秒`;
5076
+ else clone.content = `[空降(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${__WEBPACK_EXTERNAL_MODULE_hh_mm_ss_6ead5141__["default"].fromS(clone.progress + chapter.duration)}`;
5077
+ }
5078
+ } else if (check('bili') && clone.extra.bili) {
5079
+ const bili = clone.extra.bili;
5080
+ if (7 === bili.mode && bili.adv) clone.content = `[B站高级弹幕]${JSON.parse(bili.adv)[4] || ''}`;
5081
+ else if (bili.command) {
5082
+ const command = bili.command;
5083
+ clone.content = `[B站指令弹幕]${command.content}`;
5084
+ clone.fontsize = 36;
5085
+ }
5086
+ }
5087
+ clone.senderID = 'compat@bot';
5088
+ clone.attr.push('Compatible');
5089
+ if (cleanExtra) clone.extraStr = void 0;
5090
+ return clone;
5091
+ }
5043
5092
  }
5044
5093
  static transCtime(oriCtime, tsUnit) {
5045
5094
  function isMsTs(ts) {
@@ -5803,10 +5852,10 @@ class UniPool {
5803
5852
  minify() {
5804
5853
  return this.dans.map((d)=>d.minify());
5805
5854
  }
5806
- convert2(format) {
5855
+ convert2(format, continue_on_error = false) {
5807
5856
  switch(format){
5808
5857
  case 'danuni.json':
5809
- return JSON.stringify(this.dans);
5858
+ return this.dans;
5810
5859
  case 'danuni.bin':
5811
5860
  return this.toPb();
5812
5861
  case 'dplayer.json':
@@ -5818,7 +5867,11 @@ class UniPool {
5818
5867
  case 'common.ass':
5819
5868
  return this.toASS();
5820
5869
  default:
5821
- throw new Error('unknown format or unsupported now!');
5870
+ {
5871
+ const message = '(err) Unknown format or unsupported now!';
5872
+ if (continue_on_error) return message;
5873
+ throw new Error(message);
5874
+ }
5822
5875
  }
5823
5876
  }
5824
5877
  static fromPb(bin) {
@@ -5880,6 +5880,104 @@
5880
5880
  var bind = __webpack_require__("../../node_modules/.pnpm/function-bind@1.1.2/node_modules/function-bind/index.js");
5881
5881
  module1.exports = bind.call(call, $hasOwn);
5882
5882
  },
5883
+ "../../node_modules/.pnpm/hh-mm-ss@1.2.0/node_modules/hh-mm-ss/index.js": function(module1, __unused_webpack_exports, __webpack_require__) {
5884
+ "use strict";
5885
+ module1.exports = {
5886
+ fromMs,
5887
+ fromS,
5888
+ toMs,
5889
+ toS
5890
+ };
5891
+ const zeroFill = __webpack_require__("../../node_modules/.pnpm/zero-fill@2.2.4/node_modules/zero-fill/index.js");
5892
+ const HOUR = 3600000;
5893
+ const MINUTE = 60000;
5894
+ const SECOND = 1000;
5895
+ const TIME_FORMAT_ERRMSG = 'Time format error';
5896
+ function fromMs(ms, format = 'mm:ss') {
5897
+ if ('number' != typeof ms || Number.isNaN(ms)) throw new Error('NaN error');
5898
+ let absMs = Math.abs(ms);
5899
+ let negative = ms < 0;
5900
+ let hours = Math.floor(absMs / HOUR);
5901
+ let minutes = Math.floor(absMs % HOUR / MINUTE);
5902
+ let seconds = Math.floor(absMs % MINUTE / SECOND);
5903
+ let miliseconds = Math.floor(absMs % SECOND);
5904
+ return formatTime({
5905
+ negative,
5906
+ hours,
5907
+ minutes,
5908
+ seconds,
5909
+ miliseconds
5910
+ }, format);
5911
+ }
5912
+ function fromS(s, format = 'mm:ss') {
5913
+ if ('number' != typeof s || Number.isNaN(s)) throw new Error('NaN error');
5914
+ let ms = s * SECOND;
5915
+ return fromMs(ms, format);
5916
+ }
5917
+ function toMs(time, format = 'mm:ss') {
5918
+ let re;
5919
+ if ([
5920
+ 'mm:ss',
5921
+ 'mm:ss.sss',
5922
+ 'hh:mm:ss',
5923
+ 'hh:mm:ss.sss'
5924
+ ].includes(format)) re = /^(-)?(?:(\d\d+):)?(\d\d):(\d\d)(\.\d+)?$/;
5925
+ else if ('hh:mm' === format) re = /^(-)?(\d\d):(\d\d)(?::(\d\d)(?:(\.\d+))?)?$/;
5926
+ else throw new Error(TIME_FORMAT_ERRMSG);
5927
+ let result = re.exec(time);
5928
+ if (!result) throw new Error();
5929
+ let negative = '-' === result[1];
5930
+ let hours = 0 | result[2];
5931
+ let minutes = 0 | result[3];
5932
+ let seconds = 0 | result[4];
5933
+ let miliseconds = Math.floor(1000 * result[5] | 0);
5934
+ if (minutes > 60 || seconds > 60) throw new Error();
5935
+ return (negative ? -1 : 1) * (hours * HOUR + minutes * MINUTE + seconds * SECOND + miliseconds);
5936
+ }
5937
+ function toS(time, format = 'mm:ss') {
5938
+ let ms = toMs(time, format);
5939
+ return Math.floor(ms / SECOND);
5940
+ }
5941
+ function formatTime(time, format) {
5942
+ let showMs;
5943
+ let showSc;
5944
+ let showHr;
5945
+ switch(format.toLowerCase()){
5946
+ case 'hh:mm:ss.sss':
5947
+ showMs = true;
5948
+ showSc = true;
5949
+ showHr = true;
5950
+ break;
5951
+ case 'hh:mm:ss':
5952
+ showMs = !!time.miliseconds;
5953
+ showSc = true;
5954
+ showHr = true;
5955
+ break;
5956
+ case 'hh:mm':
5957
+ showMs = !!time.miliseconds;
5958
+ showSc = showMs || !!time.seconds;
5959
+ showHr = true;
5960
+ break;
5961
+ case 'mm:ss':
5962
+ showMs = !!time.miliseconds;
5963
+ showSc = true;
5964
+ showHr = !!time.hours;
5965
+ break;
5966
+ case 'mm:ss.sss':
5967
+ showMs = true;
5968
+ showSc = true;
5969
+ showHr = !!time.hours;
5970
+ break;
5971
+ default:
5972
+ throw new Error(TIME_FORMAT_ERRMSG);
5973
+ }
5974
+ let hh = zeroFill(2, time.hours);
5975
+ let mm = zeroFill(2, time.minutes);
5976
+ let ss = zeroFill(2, time.seconds);
5977
+ let sss = zeroFill(3, time.miliseconds);
5978
+ return (time.negative ? '-' : '') + (showHr ? showMs ? `${hh}:${mm}:${ss}.${sss}` : showSc ? `${hh}:${mm}:${ss}` : `${hh}:${mm}` : showMs ? `${mm}:${ss}.${sss}` : `${mm}:${ss}`);
5979
+ }
5980
+ },
5883
5981
  "../../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js": function(__unused_webpack_module, exports1) {
5884
5982
  /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ exports1.read = function(buffer, offset, isLE, mLen, nBytes) {
5885
5983
  var e, m;
@@ -12991,6 +13089,17 @@
12991
13089
  return tryTypedArrays(value);
12992
13090
  };
12993
13091
  },
13092
+ "../../node_modules/.pnpm/zero-fill@2.2.4/node_modules/zero-fill/index.js": function(module1) {
13093
+ /*! zero-fill. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */ module1.exports = function zeroFill(width, number, pad) {
13094
+ if (void 0 === number) return function(number, pad) {
13095
+ return zeroFill(width, number, pad);
13096
+ };
13097
+ if (void 0 === pad) pad = '0';
13098
+ width -= number.toString().length;
13099
+ if (width > 0) return new Array(width + (/\./.test(number) ? 2 : 1)).join(pad) + number;
13100
+ return number + '';
13101
+ };
13102
+ },
12994
13103
  "?3f8a": function() {},
12995
13104
  "?a053": function() {},
12996
13105
  "../../node_modules/.pnpm/available-typed-arrays@1.0.7/node_modules/available-typed-arrays/index.js": function(module1, __unused_webpack_exports, __webpack_require__) {
@@ -13014,6 +13123,19 @@
13014
13123
  __webpack_modules__[moduleId](module1, module1.exports, __webpack_require__);
13015
13124
  return module1.exports;
13016
13125
  }
13126
+ (()=>{
13127
+ __webpack_require__.n = function(module1) {
13128
+ var getter = module1 && module1.__esModule ? function() {
13129
+ return module1['default'];
13130
+ } : function() {
13131
+ return module1;
13132
+ };
13133
+ __webpack_require__.d(getter, {
13134
+ a: getter
13135
+ });
13136
+ return getter;
13137
+ };
13138
+ })();
13017
13139
  (()=>{
13018
13140
  __webpack_require__.d = function(exports1, definition) {
13019
13141
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
@@ -17845,6 +17967,8 @@
17845
17967
  NORMAL: 1,
17846
17968
  LARGE: 2
17847
17969
  };
17970
+ var hh_mm_ss = __webpack_require__("../../node_modules/.pnpm/hh-mm-ss@1.2.0/node_modules/hh-mm-ss/index.js");
17971
+ var hh_mm_ss_default = /*#__PURE__*/ __webpack_require__.n(hh_mm_ss);
17848
17972
  const sha_t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", sha_n = "ARRAYBUFFER not supported by this environment", sha_e = "UINT8ARRAY not supported by this environment";
17849
17973
  function sha_r(t, n, e, r) {
17850
17974
  let i, s, o;
@@ -18898,11 +19022,25 @@
18898
19022
  ExtraDanUniChapterType["ED"] = "ed";
18899
19023
  ExtraDanUniChapterType["Preview"] = "prvw";
18900
19024
  ExtraDanUniChapterType["Cut"] = "cut";
18901
- ExtraDanUniChapterType["Duplicates"] = "dup";
19025
+ ExtraDanUniChapterType["Duplicate"] = "dup";
18902
19026
  ExtraDanUniChapterType["AdBiz"] = "biz";
18903
19027
  ExtraDanUniChapterType["AdUnpaid"] = "promo";
18904
19028
  return ExtraDanUniChapterType;
18905
19029
  }({});
19030
+ const ExtraDanUniChapterTypeDict = {
19031
+ chs: {
19032
+ ch: '其它片段',
19033
+ rev: '回顾',
19034
+ op: '片头',
19035
+ int: '中场',
19036
+ ed: '片尾',
19037
+ prvw: '预告',
19038
+ cut: '删减',
19039
+ dup: '补档',
19040
+ biz: '商业广告',
19041
+ promo: '推广'
19042
+ }
19043
+ };
18906
19044
  var dm_gen_ExtraDanUniChapterAction = /*#__PURE__*/ function(ExtraDanUniChapterAction) {
18907
19045
  ExtraDanUniChapterAction[ExtraDanUniChapterAction["Disabled"] = -1] = "Disabled";
18908
19046
  ExtraDanUniChapterAction[ExtraDanUniChapterAction["ShowOverlay"] = 0] = "ShowOverlay";
@@ -19028,8 +19166,42 @@
19028
19166
  }
19029
19167
  return JSON.parse(JSON.stringify(dan));
19030
19168
  }
19031
- downgradeAdvcancedDan() {
19169
+ downgradeAdvcancedDan({ include, exclude, cleanExtra = false } = {
19170
+ include: [],
19171
+ exclude: []
19172
+ }) {
19032
19173
  if (!this.extra) return this;
19174
+ {
19175
+ if (!include) include = [];
19176
+ if (!exclude) exclude = [];
19177
+ const check = (k)=>include?.includes(k) || !exclude?.includes(k);
19178
+ const clone = UniDM.create(this);
19179
+ clone.mode = 2;
19180
+ if (check('danuni') && clone.extra.danuni) {
19181
+ const danuni = clone.extra.danuni;
19182
+ if (danuni.merge) {
19183
+ const merge = danuni.merge;
19184
+ clone.content = `${this.content} x${merge.count}`;
19185
+ } else if (danuni.chapter) {
19186
+ const chapter = danuni.chapter;
19187
+ if ("cut" === chapter.type) clone.content = `[提示]${clone.platform}源${ExtraDanUniChapterTypeDict.chs[chapter.type]}了${chapter.duration}秒`;
19188
+ else if ("dup" === chapter.type) clone.content = `[提示(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${clone.platform}源-${chapter.duration}秒`;
19189
+ else clone.content = `[空降(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${hh_mm_ss_default().fromS(clone.progress + chapter.duration)}`;
19190
+ }
19191
+ } else if (check('bili') && clone.extra.bili) {
19192
+ const bili = clone.extra.bili;
19193
+ if (7 === bili.mode && bili.adv) clone.content = `[B站高级弹幕]${JSON.parse(bili.adv)[4] || ''}`;
19194
+ else if (bili.command) {
19195
+ const command = bili.command;
19196
+ clone.content = `[B站指令弹幕]${command.content}`;
19197
+ clone.fontsize = 36;
19198
+ }
19199
+ }
19200
+ clone.senderID = 'compat@bot';
19201
+ clone.attr.push('Compatible');
19202
+ if (cleanExtra) clone.extraStr = void 0;
19203
+ return clone;
19204
+ }
19033
19205
  }
19034
19206
  static transCtime(oriCtime, tsUnit) {
19035
19207
  function isMsTs(ts) {
@@ -19796,10 +19968,10 @@
19796
19968
  minify() {
19797
19969
  return this.dans.map((d)=>d.minify());
19798
19970
  }
19799
- convert2(format) {
19971
+ convert2(format, continue_on_error = false) {
19800
19972
  switch(format){
19801
19973
  case 'danuni.json':
19802
- return JSON.stringify(this.dans);
19974
+ return this.dans;
19803
19975
  case 'danuni.bin':
19804
19976
  return this.toPb();
19805
19977
  case 'dplayer.json':
@@ -19811,7 +19983,11 @@
19811
19983
  case 'common.ass':
19812
19984
  return this.toASS();
19813
19985
  default:
19814
- throw new Error('unknown format or unsupported now!');
19986
+ {
19987
+ const message = '(err) Unknown format or unsupported now!';
19988
+ if (continue_on_error) return message;
19989
+ throw new Error(message);
19990
+ }
19815
19991
  }
19816
19992
  }
19817
19993
  static fromPb(bin) {
@@ -14,4 +14,6 @@
14
14
 
15
15
  /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
16
16
 
17
- /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
17
+ /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
18
+
19
+ /*! zero-fill. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
@@ -63,7 +63,7 @@ export declare class UniPool {
63
63
  */
64
64
  merge(lifetime?: number): UniPool;
65
65
  minify(): (Partial<UniDMTools.UniDMObj> & Pick<UniDMTools.UniDMObj, "FCID">)[];
66
- convert2(format: DM_format): string | Uint8Array<ArrayBufferLike> | DM_JSON_Dplayer | DM_JSON_DDPlay | DM_JSON_Artplayer[];
66
+ convert2(format: DM_format, continue_on_error?: boolean): string | Uint8Array<ArrayBufferLike> | UniDM[] | DM_JSON_Dplayer | DM_JSON_DDPlay | DM_JSON_Artplayer[];
67
67
  static fromPb(bin: Uint8Array | ArrayBuffer): UniPool;
68
68
  /**
69
69
  * 转为 protobuf 二进制
@@ -1,6 +1,6 @@
1
1
  import type { DM_JSON_BiliCommandGrpc } from '..';
2
2
  import type { platfrom } from './id-gen';
3
- export type DMAttr = 'Protect' | 'FromLive' | 'HighLike' | 'Compatible' | 'Reported';
3
+ export type DMAttr = 'Protect' | 'FromLive' | 'HighLike' | 'Compatible' | 'Reported' | 'Hide';
4
4
  interface DMBili {
5
5
  id: bigint;
6
6
  progress: number;
@@ -83,8 +83,8 @@ interface ExtraArtplayer {
83
83
  border?: boolean;
84
84
  }
85
85
  interface ExtraBili {
86
- mode: number;
87
- pool: number;
86
+ mode?: number;
87
+ pool?: number;
88
88
  adv?: string;
89
89
  code?: string;
90
90
  bas?: string;
@@ -111,7 +111,7 @@ export declare enum ExtraDanUniChapterType {
111
111
  ED = "ed",//片尾
112
112
  Preview = "prvw",//预告
113
113
  Cut = "cut",//删减(删减版中提供删减说明,提供开始位置、长度)
114
- Duplicates = "dup",//补档(完整版中指明其它平台中删减位置)
114
+ Duplicate = "dup",//补档(完整版中指明其它平台中删减位置)
115
115
  AdBiz = "biz",//商业广告
116
116
  AdUnpaid = "promo"
117
117
  }
@@ -166,7 +166,7 @@ export declare class UniDM {
166
166
  */
167
167
  progress: number;
168
168
  /**
169
- * 类型 1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(pool必须为2)
169
+ * 弹幕类型
170
170
  */
171
171
  mode: Modes;
172
172
  /**
@@ -248,7 +248,7 @@ export declare class UniDM {
248
248
  */
249
249
  progress?: number,
250
250
  /**
251
- * 类型 1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(pool必须为2)
251
+ * 弹幕类型
252
252
  */
253
253
  mode?: Modes,
254
254
  /**
@@ -327,7 +327,11 @@ export declare class UniDM {
327
327
  toDMID(): string;
328
328
  isSameAs(dan: UniDM, _check2?: boolean): boolean;
329
329
  minify(): Partial<UniDMObj> & Pick<UniDMObj, "FCID">;
330
- downgradeAdvcancedDan(): this | undefined;
330
+ downgradeAdvcancedDan({ include, exclude, cleanExtra, }?: {
331
+ include?: (keyof Extra)[];
332
+ exclude?: (keyof Extra)[];
333
+ cleanExtra?: boolean;
334
+ }): UniDM;
331
335
  /**
332
336
  * 将各种类型的时间进行格式化
333
337
  * @param oriCtime
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-uni/dan-any",
3
- "version": "0.2.3",
3
+ "version": "0.2.6",
4
4
  "description": "A danmaku transformer lib, supporting danmaku from different platforms.",
5
5
  "keywords": [
6
6
  "bangumi",
@@ -34,12 +34,14 @@
34
34
  "base16384": "^1.0.0",
35
35
  "canvas": "^3.1.0",
36
36
  "fast-xml-parser": "^4.5.1",
37
+ "hh-mm-ss": "^1.2.0",
37
38
  "jssha": "^3.3.1"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@bufbuild/buf": "^1.50.0",
41
42
  "@bufbuild/protobuf": "^2.2.3",
42
43
  "@bufbuild/protoc-gen-es": "^2.2.3",
44
+ "@types/hh-mm-ss": "^1.2.3",
43
45
  "@types/pako": "^2.0.3",
44
46
  "protobufjs": "^7.4.0"
45
47
  }
package/src/index.ts CHANGED
@@ -219,10 +219,10 @@ export class UniPool {
219
219
  minify() {
220
220
  return this.dans.map((d) => d.minify())
221
221
  }
222
- convert2(format: DM_format) {
222
+ convert2(format: DM_format, continue_on_error = false) {
223
223
  switch (format) {
224
224
  case 'danuni.json':
225
- return JSON.stringify(this.dans)
225
+ return this.dans
226
226
  case 'danuni.bin':
227
227
  return this.toPb()
228
228
  // case 'bili.xml':
@@ -239,8 +239,11 @@ export class UniPool {
239
239
  return this.toDDplay()
240
240
  case 'common.ass':
241
241
  return this.toASS()
242
- default:
243
- throw new Error('unknown format or unsupported now!')
242
+ default: {
243
+ const message = '(err) Unknown format or unsupported now!'
244
+ if (continue_on_error) return message
245
+ else throw new Error(message)
246
+ }
244
247
  }
245
248
  }
246
249
  static fromPb(bin: Uint8Array | ArrayBuffer) {
@@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'
3
3
  import type { UniDMObj } from './dm-gen'
4
4
 
5
5
  import { UniDM, UniPool } from '..'
6
+ import { ExtraDanUniChapterType } from './dm-gen'
6
7
 
7
8
  const xml = `<i>
8
9
  <chatserver>chat.bilibili.com</chatserver>
@@ -18,6 +19,56 @@ const xml = `<i>
18
19
  <d p="13.499,1,25,16777215,1686301548,3,2848bf1c,1335553202649003264">不喜欢</d>
19
20
  </i>`
20
21
 
22
+ describe('弹幕降级', () => {
23
+ const dans = [
24
+ UniDM.create({
25
+ content: 'test',
26
+ extra: {
27
+ danuni: { merge: { count: 100, duration: 10, senders: [] } },
28
+ },
29
+ }),
30
+ UniDM.create({
31
+ platform: 'bili',
32
+ extra: {
33
+ danuni: { chapter: { type: ExtraDanUniChapterType.Cut, duration: 3 } },
34
+ },
35
+ }),
36
+ UniDM.create({
37
+ progress: 30,
38
+ extra: {
39
+ danuni: { chapter: { type: ExtraDanUniChapterType.OP, duration: 93 } },
40
+ },
41
+ }),
42
+ UniDM.create({
43
+ platform: 'bili',
44
+ extra: {
45
+ bili: {
46
+ mode: 7,
47
+ adv: '["0.355","0.27","0.8-0","0.6"," 真棒☺",0,0,"0.355",0,"500",0,0,"SimHei",1]',
48
+ },
49
+ },
50
+ }),
51
+ ]
52
+ it('danuni.merge', () => {
53
+ const d = dans[0].downgradeAdvcancedDan({ cleanExtra: true })
54
+ console.info(d)
55
+ expect(d.content).equal('test x100')
56
+ })
57
+ it('danuni.chapter', () => {
58
+ const d1 = dans[1].downgradeAdvcancedDan({ cleanExtra: true })
59
+ console.info(d1)
60
+ expect(d1.content).equal('[提示]bili源删减了3秒')
61
+ const d2 = dans[2].downgradeAdvcancedDan({ cleanExtra: true })
62
+ console.info(d2)
63
+ expect(d2.content).equal('[空降(片头)]02:03')
64
+ })
65
+ it('bili.adv', () => {
66
+ const d = dans[3].downgradeAdvcancedDan({ cleanExtra: true })
67
+ console.info(d)
68
+ expect(d.content).equal('[B站高级弹幕] 真棒☺')
69
+ })
70
+ })
71
+
21
72
  describe('其它', () => {
22
73
  const pool = UniPool.fromBiliXML(xml)
23
74
  it('比较(常规)', () => {
@@ -1,3 +1,4 @@
1
+ import TimeFormat from 'hh-mm-ss'
1
2
  import type { DM_JSON_BiliCommandGrpc } from '..'
2
3
  import type { platfrom } from './id-gen'
3
4
 
@@ -57,6 +58,7 @@ export type DMAttr =
57
58
  | 'HighLike'
58
59
  | 'Compatible'
59
60
  | 'Reported'
61
+ | 'Hide'
60
62
  const DMAttrUtils = {
61
63
  fromBin(bin: number = 0, format?: platfrom) {
62
64
  const array = toBits(bin),
@@ -208,8 +210,8 @@ interface ExtraArtplayer {
208
210
  border?: boolean
209
211
  }
210
212
  interface ExtraBili {
211
- mode: number //原弹幕类型
212
- pool: number //原弹幕池
213
+ mode?: number //原弹幕类型
214
+ pool?: number //原弹幕池
213
215
  adv?: string
214
216
  code?: string
215
217
  bas?: string
@@ -240,10 +242,24 @@ export enum ExtraDanUniChapterType {
240
242
  ED = 'ed', //片尾
241
243
  Preview = 'prvw', //预告
242
244
  Cut = 'cut', //删减(删减版中提供删减说明,提供开始位置、长度)
243
- Duplicates = 'dup', //补档(完整版中指明其它平台中删减位置)
245
+ Duplicate = 'dup', //补档(完整版中指明其它平台中删减位置)
244
246
  AdBiz = 'biz', //商业广告
245
247
  AdUnpaid = 'promo', //推广(无偿/公益)广告
246
248
  }
249
+ const ExtraDanUniChapterTypeDict = {
250
+ chs: {
251
+ ch: '其它片段',
252
+ rev: '回顾',
253
+ op: '片头',
254
+ int: '中场',
255
+ ed: '片尾',
256
+ prvw: '预告',
257
+ cut: '删减',
258
+ dup: '补档',
259
+ biz: '商业广告',
260
+ promo: '推广',
261
+ },
262
+ }
247
263
  export enum ExtraDanUniChapterAction {
248
264
  Disabled = -1,
249
265
  ShowOverlay,
@@ -309,7 +325,7 @@ export class UniDM {
309
325
  */
310
326
  public progress: number = 0,
311
327
  /**
312
- * 类型 1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(pool必须为2)
328
+ * 弹幕类型
313
329
  */
314
330
  public mode: Modes = Modes.Normal,
315
331
  /**
@@ -502,10 +518,54 @@ export class UniDM {
502
518
  }
503
519
  return JSON.parse(JSON.stringify(dan)) as UObj
504
520
  }
505
- downgradeAdvcancedDan() {
521
+ downgradeAdvcancedDan(
522
+ {
523
+ include,
524
+ exclude,
525
+ cleanExtra = false,
526
+ }: {
527
+ include?: (keyof Extra)[]
528
+ exclude?: (keyof Extra)[]
529
+ cleanExtra?: boolean
530
+ } = { include: [], exclude: [] },
531
+ ) {
506
532
  if (!this.extra) return this
507
533
  else {
534
+ if (!include) include = []
535
+ if (!exclude) exclude = []
536
+ const check = (k: keyof Extra) =>
537
+ include?.includes(k) || !exclude?.includes(k)
508
538
  // TODO 分别对 mode7/8/9 command artplayer等正常播放器无法绘制的弹幕做降级处理
539
+ const clone = UniDM.create(this)
540
+ clone.mode = Modes.Top
541
+ if (check('danuni') && clone.extra.danuni) {
542
+ const danuni = clone.extra.danuni
543
+ if (danuni.merge) {
544
+ const merge = danuni.merge
545
+ clone.content = `${this.content} x${merge.count}`
546
+ } else if (danuni.chapter) {
547
+ const chapter = danuni.chapter
548
+ if (chapter.type === ExtraDanUniChapterType.Cut)
549
+ clone.content = `[提示]${clone.platform}源${ExtraDanUniChapterTypeDict.chs[chapter.type]}了${chapter.duration}秒`
550
+ else if (chapter.type === ExtraDanUniChapterType.Duplicate)
551
+ clone.content = `[提示(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${clone.platform}源-${chapter.duration}秒`
552
+ else
553
+ clone.content = `[空降(${ExtraDanUniChapterTypeDict.chs[chapter.type]})]${TimeFormat.fromS(clone.progress + chapter.duration)}`
554
+ }
555
+ } else if (check('bili') && clone.extra.bili) {
556
+ const bili = clone.extra.bili
557
+ if (bili.mode === 7 && bili.adv) {
558
+ clone.content = `[B站高级弹幕]${JSON.parse(bili.adv)[4] || ''}`
559
+ } else if (bili.command) {
560
+ const command = bili.command
561
+ clone.content = `[B站指令弹幕]${command.content}`
562
+ clone.fontsize = 36
563
+ }
564
+ }
565
+ clone.senderID = 'compat@bot'
566
+ clone.attr.push('Compatible')
567
+ if (cleanExtra) clone.extraStr = undefined
568
+ return clone
509
569
  }
510
570
  }
511
571
  /**
@@ -547,6 +607,7 @@ export class UniDM {
547
607
  let mode = Modes.Normal
548
608
  switch (fmt) {
549
609
  case 'bili':
610
+ // 类型 1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(pool必须为2)
550
611
  switch (oriMode) {
551
612
  case 4:
552
613
  mode = Modes.Bottom