@dan-uni/dan-any 0.4.7 → 0.4.9

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/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  `pb`指`protobuf`格式(grpc协议下的默认传输格式)
17
17
 
18
18
  - [x] DanUni(json,pb)
19
- - [x] bili(普通+高级弹幕,xml) `正向`
19
+ - [x] bili(普通+高级弹幕,xml) `双向`
20
20
  - [x] bili(普通+高级弹幕,pb) `正向`
21
21
  - [x] bili(指令弹幕,pb) `正向`
22
22
  - [x] dplayer
@@ -30,6 +30,8 @@
30
30
 
31
31
  - [dan-any-plugin-detalu](https://github.com/ani-uni/danuni/tree/master/packages/dan-any-plugin-detalu): 基于pakku.js的弹幕过滤器
32
32
 
33
+ ## 特殊字段提示
34
+
33
35
  ### ASS Raw 字段
34
36
 
35
37
  为便于由ASS格式还原,由本工具生成的ASS弹幕格式中,包含以下字段:`RawCompressType` `RawBaseType` `Raw`
@@ -38,7 +40,8 @@
38
40
 
39
41
  ## TODO
40
42
 
41
- - [ ] 反向转换bili弹幕格式
43
+ - [ ] 完善弹幕降级显示功能(使高级弹幕有损转换为普通弹幕)
44
+ - [ ] 完善使用文档
42
45
 
43
46
  ## License 许可证
44
47
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { XMLParser } from "fast-xml-parser";
1
+ import { XMLBuilder, XMLParser } from "fast-xml-parser";
2
2
  import hh_mm_ss from "hh-mm-ss";
3
3
  import jssha from "jssha";
4
4
  import { createCanvas } from "canvas";
@@ -41,7 +41,7 @@ __webpack_require__.d(platform_namespaceObject, {
41
41
  var id_gen_namespaceObject = {};
42
42
  __webpack_require__.r(id_gen_namespaceObject);
43
43
  __webpack_require__.d(id_gen_namespaceObject, {
44
- UniID: ()=>UniID,
44
+ UniID: ()=>id_gen_UniID,
45
45
  createDMID: ()=>createDMID
46
46
  });
47
47
  var dm_gen_namespaceObject = {};
@@ -4888,27 +4888,31 @@ const PlatformSources = [
4888
4888
  ...PlatformInfoSources,
4889
4889
  ...PlatformDanmakuSources
4890
4890
  ];
4891
- class UniID {
4891
+ class id_gen_UniID {
4892
4892
  id;
4893
4893
  domain;
4894
4894
  constructor(id, domain){
4895
4895
  this.id = id;
4896
4896
  this.domain = domain;
4897
4897
  }
4898
+ static fromString(str) {
4899
+ const [id, domain] = str.split('@');
4900
+ return new id_gen_UniID(id, domain);
4901
+ }
4898
4902
  toString() {
4899
4903
  return `${this.id}@${this.domain}`;
4900
4904
  }
4901
4905
  static fromNull(domain) {
4902
- return new UniID('runtime' === domain ? 'runtime' : 'anonymous', domain || 'danuni');
4906
+ return new id_gen_UniID('runtime' === domain ? 'runtime' : 'anonymous', domain || 'danuni');
4903
4907
  }
4904
4908
  static fromBili({ cid, mid, midHash }) {
4905
- if (cid) return new UniID(cid.toString(), platform_PlatformVideoSource.Bilibili);
4906
- if (mid) return new UniID(mid.toString(), platform_PlatformVideoSource.Bilibili);
4907
- if (midHash) return new UniID(midHash, platform_PlatformVideoSource.Bilibili);
4909
+ if (cid) return new id_gen_UniID(cid.toString(), platform_PlatformVideoSource.Bilibili);
4910
+ if (mid) return new id_gen_UniID(mid.toString(), platform_PlatformVideoSource.Bilibili);
4911
+ if (midHash) return new id_gen_UniID(midHash, platform_PlatformVideoSource.Bilibili);
4908
4912
  return this.fromNull(platform_PlatformVideoSource.Bilibili);
4909
4913
  }
4910
4914
  static fromUnknown(id, domain) {
4911
- if (id) return new UniID(id, domain);
4915
+ if (id) return new id_gen_UniID(id, domain);
4912
4916
  return this.fromNull(domain);
4913
4917
  }
4914
4918
  }
@@ -5030,7 +5034,7 @@ class UniDM {
5030
5034
  platform;
5031
5035
  extraStr;
5032
5036
  DMID;
5033
- constructor(SOID, progress = 0, mode = 0, fontsize = 25, color = 16777215, senderID = UniID.fromNull().toString(), content = '', ctime = new Date(), weight = 0, pool = 0, attr = [], platform, extraStr, DMID){
5037
+ constructor(SOID, progress = 0, mode = 0, fontsize = 25, color = 16777215, senderID = id_gen_UniID.fromNull().toString(), content = '', ctime = new Date(), weight = 0, pool = 0, attr = [], platform, extraStr, DMID){
5034
5038
  this.SOID = SOID;
5035
5039
  this.progress = progress;
5036
5040
  this.mode = mode;
@@ -5057,7 +5061,7 @@ class UniDM {
5057
5061
  if ('{}' === extraStr) this.extraStr = void 0;
5058
5062
  }
5059
5063
  static create(args) {
5060
- return args ? new UniDM(args.SOID || UniID.fromNull().toString(), args.progress, args.mode, args.fontsize, args.color, args.senderID, args.content, args.ctime, args.weight, args.pool, args.attr, args.platform, 'object' == typeof args.extra ? JSON.stringify(args.extra) : args.extra || args.extraStr, args.DMID) : new UniDM(UniID.fromNull().toString());
5064
+ return args ? new UniDM(args.SOID || id_gen_UniID.fromNull().toString(), args.progress, args.mode, args.fontsize, args.color, args.senderID, args.content, args.ctime, args.weight, args.pool, args.attr, args.platform, 'object' == typeof args.extra ? JSON.stringify(args.extra) : args.extra || args.extraStr, args.DMID) : new UniDM(id_gen_UniID.fromNull().toString());
5061
5065
  }
5062
5066
  get extra() {
5063
5067
  const extra = JSON.parse(this.extraStr || '{}');
@@ -5205,16 +5209,17 @@ class UniDM {
5205
5209
  }
5206
5210
  static fromBili(args, cid) {
5207
5211
  if (args.oid && !cid) cid = args.oid;
5208
- const SOID = `def::${UniID.fromBili({
5212
+ const SOID = `def::${id_gen_UniID.fromBili({
5209
5213
  cid
5210
- })}`, senderID = UniID.fromBili({
5214
+ })}`, senderID = id_gen_UniID.fromBili({
5211
5215
  midHash: args.midHash
5212
5216
  });
5213
5217
  let mode = 0;
5214
5218
  const pool = args.pool, extra = {
5215
5219
  bili: {
5216
5220
  mode: args.mode,
5217
- pool: args.pool
5221
+ pool: args.pool,
5222
+ dmid: args.id
5218
5223
  }
5219
5224
  };
5220
5225
  switch(args.mode){
@@ -5256,11 +5261,63 @@ class UniDM {
5256
5261
  extra: args.mode >= 7 ? JSON.stringify(extra, BigIntSerializer) : void 0
5257
5262
  });
5258
5263
  }
5264
+ toBiliXML() {
5265
+ const recMode = (mode, extra)=>{
5266
+ switch(mode){
5267
+ case 0:
5268
+ return 1;
5269
+ case 1:
5270
+ return 4;
5271
+ case 2:
5272
+ return 5;
5273
+ case 3:
5274
+ return 6;
5275
+ case 4:
5276
+ if (!extra) return 1;
5277
+ if (extra.adv) return 7;
5278
+ if (extra.code) return 8;
5279
+ else if (extra.bas) return 9;
5280
+ else return 1;
5281
+ default:
5282
+ return 1;
5283
+ }
5284
+ };
5285
+ const rMode = this.extra.bili?.mode || recMode(this.mode, this.extra?.bili);
5286
+ let content;
5287
+ switch(rMode){
5288
+ case 7:
5289
+ content = this.extra?.bili?.adv;
5290
+ break;
5291
+ case 8:
5292
+ content = this.extra?.bili?.code;
5293
+ break;
5294
+ case 9:
5295
+ content = this.extra?.bili?.bas;
5296
+ break;
5297
+ default:
5298
+ content = this.content;
5299
+ break;
5300
+ }
5301
+ return {
5302
+ '#text': content ?? this.content,
5303
+ '@_p': [
5304
+ this.progress,
5305
+ rMode,
5306
+ this.fontsize,
5307
+ this.color,
5308
+ this.ctime.getTime() / 1000,
5309
+ this.extra.bili?.pool || this.pool,
5310
+ this.senderID,
5311
+ this.extra.bili?.dmid || this.DMID || this.toDMID(),
5312
+ this.weight
5313
+ ].join(',')
5314
+ };
5315
+ }
5259
5316
  static fromBiliCommand(args, cid) {
5260
5317
  if (args.oid && !cid) cid = args.oid;
5261
- const SOID = UniID.fromBili({
5318
+ const SOID = id_gen_UniID.fromBili({
5262
5319
  cid
5263
- }), senderID = UniID.fromBili({
5320
+ }), senderID = id_gen_UniID.fromBili({
5264
5321
  mid: args.mid
5265
5322
  });
5266
5323
  return this.create({
@@ -5283,7 +5340,7 @@ class UniDM {
5283
5340
  });
5284
5341
  }
5285
5342
  static fromDplayer(args, playerID, domain) {
5286
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown(args.midHash, domain);
5343
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown(args.midHash, domain);
5287
5344
  return this.create({
5288
5345
  ...args,
5289
5346
  SOID: SOID.toString(),
@@ -5305,7 +5362,7 @@ class UniDM {
5305
5362
  };
5306
5363
  }
5307
5364
  static fromArtplayer(args, playerID, domain) {
5308
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown('', domain);
5365
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown('', domain);
5309
5366
  let extra = args.border ? {
5310
5367
  artplayer: {
5311
5368
  border: args.border,
@@ -5345,7 +5402,7 @@ class UniDM {
5345
5402
  };
5346
5403
  }
5347
5404
  static fromDDplay(args, episodeId, domain = platform_PlatformDanmakuOnlySource.DanDanPlay) {
5348
- const SOID = UniID.fromUnknown(`def::${episodeId}`, domain);
5405
+ const SOID = id_gen_UniID.fromUnknown(`def::${episodeId}`, domain);
5349
5406
  return this.create({
5350
5407
  ...args,
5351
5408
  SOID: SOID.toString(),
@@ -5725,6 +5782,35 @@ class UniPool {
5725
5782
  }, BigInt(oriData.i.chatid));
5726
5783
  }));
5727
5784
  }
5785
+ toBiliXML() {
5786
+ const genCID = (id)=>{
5787
+ const UniID = id_gen_UniID.fromString(id);
5788
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
5789
+ const cid = Number(UniID.id.replaceAll('def::', ''));
5790
+ if (cid) return cid;
5791
+ }
5792
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
5793
+ };
5794
+ const builder = new XMLBuilder({
5795
+ ignoreAttributes: false
5796
+ });
5797
+ return builder.build({
5798
+ '?xml': {
5799
+ '@_version': '1.0',
5800
+ '@_encoding': 'UTF-8'
5801
+ },
5802
+ i: {
5803
+ chatserver: 'chat.bilibili.com',
5804
+ chatid: genCID(this.dans[0].SOID),
5805
+ mission: 0,
5806
+ maxlimit: this.dans.length,
5807
+ state: 0,
5808
+ real_name: 0,
5809
+ source: 'k-v',
5810
+ d: this.dans.map((dan)=>dan.toBiliXML())
5811
+ }
5812
+ });
5813
+ }
5728
5814
  static fromBiliGrpc(bin) {
5729
5815
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
5730
5816
  return new UniPool(json.map((d)=>UniDM.fromBili({
@@ -6615,6 +6701,35 @@ class src_UniPool {
6615
6701
  }, BigInt(oriData.i.chatid));
6616
6702
  }));
6617
6703
  }
6704
+ toBiliXML() {
6705
+ const genCID = (id)=>{
6706
+ const UniID = id_gen_UniID.fromString(id);
6707
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
6708
+ const cid = Number(UniID.id.replaceAll('def::', ''));
6709
+ if (cid) return cid;
6710
+ }
6711
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
6712
+ };
6713
+ const builder = new XMLBuilder({
6714
+ ignoreAttributes: false
6715
+ });
6716
+ return builder.build({
6717
+ '?xml': {
6718
+ '@_version': '1.0',
6719
+ '@_encoding': 'UTF-8'
6720
+ },
6721
+ i: {
6722
+ chatserver: 'chat.bilibili.com',
6723
+ chatid: genCID(this.dans[0].SOID),
6724
+ mission: 0,
6725
+ maxlimit: this.dans.length,
6726
+ state: 0,
6727
+ real_name: 0,
6728
+ source: 'k-v',
6729
+ d: this.dans.map((dan)=>dan.toBiliXML())
6730
+ }
6731
+ });
6732
+ }
6618
6733
  static fromBiliGrpc(bin) {
6619
6734
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
6620
6735
  return new src_UniPool(json.map((d)=>UniDM.fromBili({
@@ -11767,7 +11767,7 @@
11767
11767
  var id_gen_namespaceObject = {};
11768
11768
  __webpack_require__.r(id_gen_namespaceObject);
11769
11769
  __webpack_require__.d(id_gen_namespaceObject, {
11770
- UniID: ()=>UniID,
11770
+ UniID: ()=>id_gen_UniID,
11771
11771
  createDMID: ()=>createDMID
11772
11772
  });
11773
11773
  var dm_gen_namespaceObject = {};
@@ -12857,6 +12857,287 @@
12857
12857
  return XmlNode.getMetaDataSymbol();
12858
12858
  }
12859
12859
  }
12860
+ const EOL = "\n";
12861
+ function toXml(jArray, options) {
12862
+ let indentation = "";
12863
+ if (options.format && options.indentBy.length > 0) indentation = EOL;
12864
+ return arrToStr(jArray, options, "", indentation);
12865
+ }
12866
+ function arrToStr(arr, options, jPath, indentation) {
12867
+ let xmlStr = "";
12868
+ let isPreviousElementTag = false;
12869
+ for(let i = 0; i < arr.length; i++){
12870
+ const tagObj = arr[i];
12871
+ const tagName = orderedJs2Xml_propName(tagObj);
12872
+ if (void 0 === tagName) continue;
12873
+ let newJPath = "";
12874
+ newJPath = 0 === jPath.length ? tagName : `${jPath}.${tagName}`;
12875
+ if (tagName === options.textNodeName) {
12876
+ let tagText = tagObj[tagName];
12877
+ if (!isStopNode(newJPath, options)) {
12878
+ tagText = options.tagValueProcessor(tagName, tagText);
12879
+ tagText = orderedJs2Xml_replaceEntitiesValue(tagText, options);
12880
+ }
12881
+ if (isPreviousElementTag) xmlStr += indentation;
12882
+ xmlStr += tagText;
12883
+ isPreviousElementTag = false;
12884
+ continue;
12885
+ }
12886
+ if (tagName === options.cdataPropName) {
12887
+ if (isPreviousElementTag) xmlStr += indentation;
12888
+ xmlStr += `<![CDATA[${tagObj[tagName][0][options.textNodeName]}]]>`;
12889
+ isPreviousElementTag = false;
12890
+ continue;
12891
+ }
12892
+ if (tagName === options.commentPropName) {
12893
+ xmlStr += indentation + `<!--${tagObj[tagName][0][options.textNodeName]}-->`;
12894
+ isPreviousElementTag = true;
12895
+ continue;
12896
+ } else if ("?" === tagName[0]) {
12897
+ const attStr = attr_to_str(tagObj[":@"], options);
12898
+ const tempInd = "?xml" === tagName ? "" : indentation;
12899
+ let piTextNodeName = tagObj[tagName][0][options.textNodeName];
12900
+ piTextNodeName = 0 !== piTextNodeName.length ? " " + piTextNodeName : "";
12901
+ xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`;
12902
+ isPreviousElementTag = true;
12903
+ continue;
12904
+ }
12905
+ let newIdentation = indentation;
12906
+ if ("" !== newIdentation) newIdentation += options.indentBy;
12907
+ const attStr = attr_to_str(tagObj[":@"], options);
12908
+ const tagStart = indentation + `<${tagName}${attStr}`;
12909
+ const tagValue = arrToStr(tagObj[tagName], options, newJPath, newIdentation);
12910
+ if (-1 !== options.unpairedTags.indexOf(tagName)) if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
12911
+ else xmlStr += tagStart + "/>";
12912
+ else if ((!tagValue || 0 === tagValue.length) && options.suppressEmptyNode) xmlStr += tagStart + "/>";
12913
+ else if (tagValue && tagValue.endsWith(">")) xmlStr += tagStart + `>${tagValue}${indentation}</${tagName}>`;
12914
+ else {
12915
+ xmlStr += tagStart + ">";
12916
+ if (tagValue && "" !== indentation && (tagValue.includes("/>") || tagValue.includes("</"))) xmlStr += indentation + options.indentBy + tagValue + indentation;
12917
+ else xmlStr += tagValue;
12918
+ xmlStr += `</${tagName}>`;
12919
+ }
12920
+ isPreviousElementTag = true;
12921
+ }
12922
+ return xmlStr;
12923
+ }
12924
+ function orderedJs2Xml_propName(obj) {
12925
+ const keys = Object.keys(obj);
12926
+ for(let i = 0; i < keys.length; i++){
12927
+ const key = keys[i];
12928
+ if (obj.hasOwnProperty(key)) {
12929
+ if (":@" !== key) return key;
12930
+ }
12931
+ }
12932
+ }
12933
+ function attr_to_str(attrMap, options) {
12934
+ let attrStr = "";
12935
+ if (attrMap && !options.ignoreAttributes) for(let attr in attrMap){
12936
+ if (!attrMap.hasOwnProperty(attr)) continue;
12937
+ let attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
12938
+ attrVal = orderedJs2Xml_replaceEntitiesValue(attrVal, options);
12939
+ if (true === attrVal && options.suppressBooleanAttributes) attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
12940
+ else attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
12941
+ }
12942
+ return attrStr;
12943
+ }
12944
+ function isStopNode(jPath, options) {
12945
+ jPath = jPath.substr(0, jPath.length - options.textNodeName.length - 1);
12946
+ let tagName = jPath.substr(jPath.lastIndexOf(".") + 1);
12947
+ for(let index in options.stopNodes)if (options.stopNodes[index] === jPath || options.stopNodes[index] === "*." + tagName) return true;
12948
+ return false;
12949
+ }
12950
+ function orderedJs2Xml_replaceEntitiesValue(textValue, options) {
12951
+ if (textValue && textValue.length > 0 && options.processEntities) for(let i = 0; i < options.entities.length; i++){
12952
+ const entity = options.entities[i];
12953
+ textValue = textValue.replace(entity.regex, entity.val);
12954
+ }
12955
+ return textValue;
12956
+ }
12957
+ const json2xml_defaultOptions = {
12958
+ attributeNamePrefix: '@_',
12959
+ attributesGroupName: false,
12960
+ textNodeName: '#text',
12961
+ ignoreAttributes: true,
12962
+ cdataPropName: false,
12963
+ format: false,
12964
+ indentBy: ' ',
12965
+ suppressEmptyNode: false,
12966
+ suppressUnpairedNode: true,
12967
+ suppressBooleanAttributes: true,
12968
+ tagValueProcessor: function(key, a) {
12969
+ return a;
12970
+ },
12971
+ attributeValueProcessor: function(attrName, a) {
12972
+ return a;
12973
+ },
12974
+ preserveOrder: false,
12975
+ commentPropName: false,
12976
+ unpairedTags: [],
12977
+ entities: [
12978
+ {
12979
+ regex: new RegExp("&", "g"),
12980
+ val: "&amp;"
12981
+ },
12982
+ {
12983
+ regex: new RegExp(">", "g"),
12984
+ val: "&gt;"
12985
+ },
12986
+ {
12987
+ regex: new RegExp("<", "g"),
12988
+ val: "&lt;"
12989
+ },
12990
+ {
12991
+ regex: new RegExp("\'", "g"),
12992
+ val: "&apos;"
12993
+ },
12994
+ {
12995
+ regex: new RegExp("\"", "g"),
12996
+ val: "&quot;"
12997
+ }
12998
+ ],
12999
+ processEntities: true,
13000
+ stopNodes: [],
13001
+ oneListGroup: false
13002
+ };
13003
+ function Builder(options) {
13004
+ this.options = Object.assign({}, json2xml_defaultOptions, options);
13005
+ if (true === this.options.ignoreAttributes || this.options.attributesGroupName) this.isAttribute = function() {
13006
+ return false;
13007
+ };
13008
+ else {
13009
+ this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
13010
+ this.attrPrefixLen = this.options.attributeNamePrefix.length;
13011
+ this.isAttribute = isAttribute;
13012
+ }
13013
+ this.processTextOrObjNode = processTextOrObjNode;
13014
+ if (this.options.format) {
13015
+ this.indentate = indentate;
13016
+ this.tagEndChar = '>\n';
13017
+ this.newLine = '\n';
13018
+ } else {
13019
+ this.indentate = function() {
13020
+ return '';
13021
+ };
13022
+ this.tagEndChar = '>';
13023
+ this.newLine = '';
13024
+ }
13025
+ }
13026
+ Builder.prototype.build = function(jObj) {
13027
+ if (this.options.preserveOrder) return toXml(jObj, this.options);
13028
+ if (Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1) jObj = {
13029
+ [this.options.arrayNodeName]: jObj
13030
+ };
13031
+ return this.j2x(jObj, 0, []).val;
13032
+ };
13033
+ Builder.prototype.j2x = function(jObj, level, ajPath) {
13034
+ let attrStr = '';
13035
+ let val = '';
13036
+ const jPath = ajPath.join('.');
13037
+ for(let key in jObj)if (Object.prototype.hasOwnProperty.call(jObj, key)) if (void 0 === jObj[key]) {
13038
+ if (this.isAttribute(key)) val += '';
13039
+ } else if (null === jObj[key]) if (this.isAttribute(key)) val += '';
13040
+ else if (key === this.options.cdataPropName) val += '';
13041
+ else if ('?' === key[0]) val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
13042
+ else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
13043
+ else if (jObj[key] instanceof Date) val += this.buildTextValNode(jObj[key], key, '', level);
13044
+ else if ('object' != typeof jObj[key]) {
13045
+ const attr = this.isAttribute(key);
13046
+ if (attr && !this.ignoreAttributesFn(attr, jPath)) attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
13047
+ else if (!attr) if (key === this.options.textNodeName) {
13048
+ let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
13049
+ val += this.replaceEntitiesValue(newval);
13050
+ } else val += this.buildTextValNode(jObj[key], key, '', level);
13051
+ } else if (Array.isArray(jObj[key])) {
13052
+ const arrLen = jObj[key].length;
13053
+ let listTagVal = "";
13054
+ let listTagAttr = "";
13055
+ for(let j = 0; j < arrLen; j++){
13056
+ const item = jObj[key][j];
13057
+ if (void 0 === item) ;
13058
+ else if (null === item) if ("?" === key[0]) val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
13059
+ else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
13060
+ else if ('object' == typeof item) if (this.options.oneListGroup) {
13061
+ const result = this.j2x(item, level + 1, ajPath.concat(key));
13062
+ listTagVal += result.val;
13063
+ if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) listTagAttr += result.attrStr;
13064
+ } else listTagVal += this.processTextOrObjNode(item, key, level, ajPath);
13065
+ else if (this.options.oneListGroup) {
13066
+ let textValue = this.options.tagValueProcessor(key, item);
13067
+ textValue = this.replaceEntitiesValue(textValue);
13068
+ listTagVal += textValue;
13069
+ } else listTagVal += this.buildTextValNode(item, key, '', level);
13070
+ }
13071
+ if (this.options.oneListGroup) listTagVal = this.buildObjectNode(listTagVal, key, listTagAttr, level);
13072
+ val += listTagVal;
13073
+ } else if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
13074
+ const Ks = Object.keys(jObj[key]);
13075
+ const L = Ks.length;
13076
+ for(let j = 0; j < L; j++)attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
13077
+ } else val += this.processTextOrObjNode(jObj[key], key, level, ajPath);
13078
+ return {
13079
+ attrStr: attrStr,
13080
+ val: val
13081
+ };
13082
+ };
13083
+ Builder.prototype.buildAttrPairStr = function(attrName, val) {
13084
+ val = this.options.attributeValueProcessor(attrName, '' + val);
13085
+ val = this.replaceEntitiesValue(val);
13086
+ if (this.options.suppressBooleanAttributes && "true" === val) return ' ' + attrName;
13087
+ return ' ' + attrName + '="' + val + '"';
13088
+ };
13089
+ function processTextOrObjNode(object, key, level, ajPath) {
13090
+ const result = this.j2x(object, level + 1, ajPath.concat(key));
13091
+ if (void 0 !== object[this.options.textNodeName] && 1 === Object.keys(object).length) return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level);
13092
+ return this.buildObjectNode(result.val, key, result.attrStr, level);
13093
+ }
13094
+ Builder.prototype.buildObjectNode = function(val, key, attrStr, level) {
13095
+ if ("" === val) if ("?" === key[0]) return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
13096
+ else return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
13097
+ {
13098
+ let tagEndExp = '</' + key + this.tagEndChar;
13099
+ let piClosingChar = "";
13100
+ if ("?" === key[0]) {
13101
+ piClosingChar = "?";
13102
+ tagEndExp = "";
13103
+ }
13104
+ if ((attrStr || '' === attrStr) && -1 === val.indexOf('<')) return this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp;
13105
+ if (false !== this.options.commentPropName && key === this.options.commentPropName && 0 === piClosingChar.length) return this.indentate(level) + `<!--${val}-->` + this.newLine;
13106
+ return this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar + val + this.indentate(level) + tagEndExp;
13107
+ }
13108
+ };
13109
+ Builder.prototype.closeTag = function(key) {
13110
+ let closeTag = "";
13111
+ if (-1 !== this.options.unpairedTags.indexOf(key)) {
13112
+ if (!this.options.suppressUnpairedNode) closeTag = "/";
13113
+ } else closeTag = this.options.suppressEmptyNode ? "/" : `></${key}`;
13114
+ return closeTag;
13115
+ };
13116
+ Builder.prototype.buildTextValNode = function(val, key, attrStr, level) {
13117
+ if (false !== this.options.cdataPropName && key === this.options.cdataPropName) return this.indentate(level) + `<![CDATA[${val}]]>` + this.newLine;
13118
+ {
13119
+ if (false !== this.options.commentPropName && key === this.options.commentPropName) return this.indentate(level) + `<!--${val}-->` + this.newLine;
13120
+ if ("?" === key[0]) return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
13121
+ let textValue = this.options.tagValueProcessor(key, val);
13122
+ textValue = this.replaceEntitiesValue(textValue);
13123
+ if ('' === textValue) return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
13124
+ return this.indentate(level) + '<' + key + attrStr + '>' + textValue + '</' + key + this.tagEndChar;
13125
+ }
13126
+ };
13127
+ Builder.prototype.replaceEntitiesValue = function(textValue) {
13128
+ if (textValue && textValue.length > 0 && this.options.processEntities) for(let i = 0; i < this.options.entities.length; i++){
13129
+ const entity = this.options.entities[i];
13130
+ textValue = textValue.replace(entity.regex, entity.val);
13131
+ }
13132
+ return textValue;
13133
+ };
13134
+ function indentate(level) {
13135
+ return this.options.indentBy.repeat(level);
13136
+ }
13137
+ function isAttribute(name) {
13138
+ if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) return name.substr(this.attrPrefixLen);
13139
+ return false;
13140
+ }
12860
13141
  var descriptors_ScalarType;
12861
13142
  (function(ScalarType) {
12862
13143
  ScalarType[ScalarType["DOUBLE"] = 1] = "DOUBLE";
@@ -18084,7 +18365,7 @@
18084
18365
  for(t[n >>> 5] |= 128 << 24 - n % 32, t[s] = 0 | h, t[s - 1] = h / sha_o | 0, i = 0; i < t.length; i += 16)r = sha_g(t.slice(i, i + 16), r);
18085
18366
  return r;
18086
18367
  }
18087
- let L = class extends sha_E {
18368
+ let sha_L = class extends sha_E {
18088
18369
  constructor(t, n, e){
18089
18370
  if ("SHA-1" !== t) throw new Error(sha_c);
18090
18371
  super(t, n, e);
@@ -18600,7 +18881,7 @@
18600
18881
  };
18601
18882
  class ht {
18602
18883
  constructor(t, n, e){
18603
- if ("SHA-1" == t) this.P = new L(t, n, e);
18884
+ if ("SHA-1" == t) this.P = new sha_L(t, n, e);
18604
18885
  else if ("SHA-224" == t || "SHA-256" == t) this.P = new sha_k(t, n, e);
18605
18886
  else if ("SHA-384" == t || "SHA-512" == t) this.P = new Q(t, n, e);
18606
18887
  else {
@@ -18652,27 +18933,31 @@
18652
18933
  ...PlatformInfoSources,
18653
18934
  ...PlatformDanmakuSources
18654
18935
  ];
18655
- class UniID {
18936
+ class id_gen_UniID {
18656
18937
  id;
18657
18938
  domain;
18658
18939
  constructor(id, domain){
18659
18940
  this.id = id;
18660
18941
  this.domain = domain;
18661
18942
  }
18943
+ static fromString(str) {
18944
+ const [id, domain] = str.split('@');
18945
+ return new id_gen_UniID(id, domain);
18946
+ }
18662
18947
  toString() {
18663
18948
  return `${this.id}@${this.domain}`;
18664
18949
  }
18665
18950
  static fromNull(domain) {
18666
- return new UniID('runtime' === domain ? 'runtime' : 'anonymous', domain || 'danuni');
18951
+ return new id_gen_UniID('runtime' === domain ? 'runtime' : 'anonymous', domain || 'danuni');
18667
18952
  }
18668
18953
  static fromBili({ cid, mid, midHash }) {
18669
- if (cid) return new UniID(cid.toString(), platform_PlatformVideoSource.Bilibili);
18670
- if (mid) return new UniID(mid.toString(), platform_PlatformVideoSource.Bilibili);
18671
- if (midHash) return new UniID(midHash, platform_PlatformVideoSource.Bilibili);
18954
+ if (cid) return new id_gen_UniID(cid.toString(), platform_PlatformVideoSource.Bilibili);
18955
+ if (mid) return new id_gen_UniID(mid.toString(), platform_PlatformVideoSource.Bilibili);
18956
+ if (midHash) return new id_gen_UniID(midHash, platform_PlatformVideoSource.Bilibili);
18672
18957
  return this.fromNull(platform_PlatformVideoSource.Bilibili);
18673
18958
  }
18674
18959
  static fromUnknown(id, domain) {
18675
- if (id) return new UniID(id, domain);
18960
+ if (id) return new id_gen_UniID(id, domain);
18676
18961
  return this.fromNull(domain);
18677
18962
  }
18678
18963
  }
@@ -18794,7 +19079,7 @@
18794
19079
  platform;
18795
19080
  extraStr;
18796
19081
  DMID;
18797
- constructor(SOID, progress = 0, mode = 0, fontsize = 25, color = 16777215, senderID = UniID.fromNull().toString(), content = '', ctime = new Date(), weight = 0, pool = 0, attr = [], platform, extraStr, DMID){
19082
+ constructor(SOID, progress = 0, mode = 0, fontsize = 25, color = 16777215, senderID = id_gen_UniID.fromNull().toString(), content = '', ctime = new Date(), weight = 0, pool = 0, attr = [], platform, extraStr, DMID){
18798
19083
  this.SOID = SOID;
18799
19084
  this.progress = progress;
18800
19085
  this.mode = mode;
@@ -18821,7 +19106,7 @@
18821
19106
  if ('{}' === extraStr) this.extraStr = void 0;
18822
19107
  }
18823
19108
  static create(args) {
18824
- return args ? new UniDM(args.SOID || UniID.fromNull().toString(), args.progress, args.mode, args.fontsize, args.color, args.senderID, args.content, args.ctime, args.weight, args.pool, args.attr, args.platform, 'object' == typeof args.extra ? JSON.stringify(args.extra) : args.extra || args.extraStr, args.DMID) : new UniDM(UniID.fromNull().toString());
19109
+ return args ? new UniDM(args.SOID || id_gen_UniID.fromNull().toString(), args.progress, args.mode, args.fontsize, args.color, args.senderID, args.content, args.ctime, args.weight, args.pool, args.attr, args.platform, 'object' == typeof args.extra ? JSON.stringify(args.extra) : args.extra || args.extraStr, args.DMID) : new UniDM(id_gen_UniID.fromNull().toString());
18825
19110
  }
18826
19111
  get extra() {
18827
19112
  const extra = JSON.parse(this.extraStr || '{}');
@@ -18969,16 +19254,17 @@
18969
19254
  }
18970
19255
  static fromBili(args, cid) {
18971
19256
  if (args.oid && !cid) cid = args.oid;
18972
- const SOID = `def::${UniID.fromBili({
19257
+ const SOID = `def::${id_gen_UniID.fromBili({
18973
19258
  cid
18974
- })}`, senderID = UniID.fromBili({
19259
+ })}`, senderID = id_gen_UniID.fromBili({
18975
19260
  midHash: args.midHash
18976
19261
  });
18977
19262
  let mode = 0;
18978
19263
  const pool = args.pool, extra = {
18979
19264
  bili: {
18980
19265
  mode: args.mode,
18981
- pool: args.pool
19266
+ pool: args.pool,
19267
+ dmid: args.id
18982
19268
  }
18983
19269
  };
18984
19270
  switch(args.mode){
@@ -19020,11 +19306,63 @@
19020
19306
  extra: args.mode >= 7 ? JSON.stringify(extra, BigIntSerializer) : void 0
19021
19307
  });
19022
19308
  }
19309
+ toBiliXML() {
19310
+ const recMode = (mode, extra)=>{
19311
+ switch(mode){
19312
+ case 0:
19313
+ return 1;
19314
+ case 1:
19315
+ return 4;
19316
+ case 2:
19317
+ return 5;
19318
+ case 3:
19319
+ return 6;
19320
+ case 4:
19321
+ if (!extra) return 1;
19322
+ if (extra.adv) return 7;
19323
+ if (extra.code) return 8;
19324
+ else if (extra.bas) return 9;
19325
+ else return 1;
19326
+ default:
19327
+ return 1;
19328
+ }
19329
+ };
19330
+ const rMode = this.extra.bili?.mode || recMode(this.mode, this.extra?.bili);
19331
+ let content;
19332
+ switch(rMode){
19333
+ case 7:
19334
+ content = this.extra?.bili?.adv;
19335
+ break;
19336
+ case 8:
19337
+ content = this.extra?.bili?.code;
19338
+ break;
19339
+ case 9:
19340
+ content = this.extra?.bili?.bas;
19341
+ break;
19342
+ default:
19343
+ content = this.content;
19344
+ break;
19345
+ }
19346
+ return {
19347
+ '#text': content ?? this.content,
19348
+ '@_p': [
19349
+ this.progress,
19350
+ rMode,
19351
+ this.fontsize,
19352
+ this.color,
19353
+ this.ctime.getTime() / 1000,
19354
+ this.extra.bili?.pool || this.pool,
19355
+ this.senderID,
19356
+ this.extra.bili?.dmid || this.DMID || this.toDMID(),
19357
+ this.weight
19358
+ ].join(',')
19359
+ };
19360
+ }
19023
19361
  static fromBiliCommand(args, cid) {
19024
19362
  if (args.oid && !cid) cid = args.oid;
19025
- const SOID = UniID.fromBili({
19363
+ const SOID = id_gen_UniID.fromBili({
19026
19364
  cid
19027
- }), senderID = UniID.fromBili({
19365
+ }), senderID = id_gen_UniID.fromBili({
19028
19366
  mid: args.mid
19029
19367
  });
19030
19368
  return this.create({
@@ -19047,7 +19385,7 @@
19047
19385
  });
19048
19386
  }
19049
19387
  static fromDplayer(args, playerID, domain) {
19050
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown(args.midHash, domain);
19388
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown(args.midHash, domain);
19051
19389
  return this.create({
19052
19390
  ...args,
19053
19391
  SOID: SOID.toString(),
@@ -19069,7 +19407,7 @@
19069
19407
  };
19070
19408
  }
19071
19409
  static fromArtplayer(args, playerID, domain) {
19072
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown('', domain);
19410
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown('', domain);
19073
19411
  let extra = args.border ? {
19074
19412
  artplayer: {
19075
19413
  border: args.border,
@@ -19109,7 +19447,7 @@
19109
19447
  };
19110
19448
  }
19111
19449
  static fromDDplay(args, episodeId, domain = platform_PlatformDanmakuOnlySource.DanDanPlay) {
19112
- const SOID = UniID.fromUnknown(`def::${episodeId}`, domain);
19450
+ const SOID = id_gen_UniID.fromUnknown(`def::${episodeId}`, domain);
19113
19451
  return this.create({
19114
19452
  ...args,
19115
19453
  SOID: SOID.toString(),
@@ -19134,6 +19472,7 @@
19134
19472
  };
19135
19473
  }
19136
19474
  }
19475
+ var Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
19137
19476
  class UniPool {
19138
19477
  dans;
19139
19478
  options;
@@ -19489,6 +19828,35 @@
19489
19828
  }, BigInt(oriData.i.chatid));
19490
19829
  }));
19491
19830
  }
19831
+ toBiliXML() {
19832
+ const genCID = (id)=>{
19833
+ const UniID = id_gen_UniID.fromString(id);
19834
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
19835
+ const cid = Number(UniID.id.replaceAll('def::', ''));
19836
+ if (cid) return cid;
19837
+ }
19838
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
19839
+ };
19840
+ const builder = new Builder({
19841
+ ignoreAttributes: false
19842
+ });
19843
+ return builder.build({
19844
+ '?xml': {
19845
+ '@_version': '1.0',
19846
+ '@_encoding': 'UTF-8'
19847
+ },
19848
+ i: {
19849
+ chatserver: 'chat.bilibili.com',
19850
+ chatid: genCID(this.dans[0].SOID),
19851
+ mission: 0,
19852
+ maxlimit: this.dans.length,
19853
+ state: 0,
19854
+ real_name: 0,
19855
+ source: 'k-v',
19856
+ d: this.dans.map((dan)=>dan.toBiliXML())
19857
+ }
19858
+ });
19859
+ }
19492
19860
  static fromBiliGrpc(bin) {
19493
19861
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
19494
19862
  return new UniPool(json.map((d)=>UniDM.fromBili({
@@ -19884,7 +20252,7 @@
19884
20252
  };
19885
20253
  var lib = __webpack_require__("../../node_modules/.pnpm/browserify-zlib@0.2.0/node_modules/browserify-zlib/lib/index.js");
19886
20254
  var base16384_lib = __webpack_require__("../../node_modules/.pnpm/base16384@1.0.0/node_modules/base16384/lib/index.js");
19887
- var Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
20255
+ var raw_Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
19888
20256
  const compressTypes = [
19889
20257
  'brotli',
19890
20258
  'gzip'
@@ -19903,7 +20271,7 @@
19903
20271
  config,
19904
20272
  context
19905
20273
  }, rawText = JSON.stringify(raw1);
19906
- let compress = Buffer.from('');
20274
+ let compress = raw_Buffer.from('');
19907
20275
  compress = 'brotli' === compressType ? (0, lib.brotliCompressSync)(rawText) : (0, lib.gzipSync)(rawText);
19908
20276
  return `;RawCompressType: ${compressType}\n;RawBaseType: ${baseType}\n;Raw: ${'base64' === baseType ? compress.toString('base64') : fromUint16Array(base16384_lib.encode(compress))}`;
19909
20277
  }
@@ -19914,8 +20282,8 @@
19914
20282
  let compressType = lineCompressType.replace(';RawCompressType: ', '').trim(), baseType = lineBaseType.replace(';RawBaseType: ', '').trim();
19915
20283
  if (!compressTypes.includes(compressType)) compressType = 'gzip';
19916
20284
  if (!baseTypes.includes(baseType)) baseType = 'base64';
19917
- const text = lineRaw.replace(';Raw: ', '').trim(), buffer = 'base64' === baseType ? Buffer.from(text, 'base64') : Buffer.from(base16384_lib.decode(Buffer.from(text, 'utf-8').toString('utf-8')));
19918
- let decompress = Buffer.from('');
20285
+ const text = lineRaw.replace(';Raw: ', '').trim(), buffer = 'base64' === baseType ? raw_Buffer.from(text, 'base64') : raw_Buffer.from(base16384_lib.decode(raw_Buffer.from(text, 'utf-8').toString('utf-8')));
20286
+ let decompress = raw_Buffer.from('');
19919
20287
  decompress = 'brotli' === compressType ? (0, lib.brotliDecompressSync)(buffer) : (0, lib.gunzipSync)(buffer);
19920
20288
  try {
19921
20289
  return JSON.parse(decompress.toString('utf-8'));
@@ -20028,6 +20396,7 @@
20028
20396
  if (!raw) return UniPool.create();
20029
20397
  return DanmakuList2UniPool(raw.list);
20030
20398
  }
20399
+ var src_Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
20031
20400
  class src_UniPool {
20032
20401
  dans;
20033
20402
  options;
@@ -20383,6 +20752,35 @@
20383
20752
  }, BigInt(oriData.i.chatid));
20384
20753
  }));
20385
20754
  }
20755
+ toBiliXML() {
20756
+ const genCID = (id)=>{
20757
+ const UniID = id_gen_UniID.fromString(id);
20758
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
20759
+ const cid = Number(UniID.id.replaceAll('def::', ''));
20760
+ if (cid) return cid;
20761
+ }
20762
+ return Number.parseInt(src_Buffer.from(id).toString('hex'), 16);
20763
+ };
20764
+ const builder = new Builder({
20765
+ ignoreAttributes: false
20766
+ });
20767
+ return builder.build({
20768
+ '?xml': {
20769
+ '@_version': '1.0',
20770
+ '@_encoding': 'UTF-8'
20771
+ },
20772
+ i: {
20773
+ chatserver: 'chat.bilibili.com',
20774
+ chatid: genCID(this.dans[0].SOID),
20775
+ mission: 0,
20776
+ maxlimit: this.dans.length,
20777
+ state: 0,
20778
+ real_name: 0,
20779
+ source: 'k-v',
20780
+ d: this.dans.map((dan)=>dan.toBiliXML())
20781
+ }
20782
+ });
20783
+ }
20386
20784
  static fromBiliGrpc(bin) {
20387
20785
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
20388
20786
  return new src_UniPool(json.map((d)=>UniDM.fromBili({
@@ -130,6 +130,7 @@ export declare class UniPool {
130
130
  */
131
131
  toPb(): Uint8Array<ArrayBufferLike>;
132
132
  static fromBiliXML(xml: string): UniPool;
133
+ toBiliXML(): string;
133
134
  static fromBiliGrpc(bin: Uint8Array | ArrayBuffer): UniPool;
134
135
  /**
135
136
  * @param bin 符合`DmWebViewReplySchema`(bili视频meta)的protobuf二进制
@@ -86,6 +86,7 @@ interface ExtraArtplayer {
86
86
  interface ExtraBili {
87
87
  mode?: number;
88
88
  pool?: number;
89
+ dmid?: bigint;
89
90
  adv?: string;
90
91
  code?: string;
91
92
  bas?: string;
@@ -324,6 +325,10 @@ export declare class UniDM {
324
325
  static transCtime(oriCtime: ctime, tsUnit?: 'ms' | 's'): Date;
325
326
  static transMode(oriMode: number, fmt: 'bili' | 'dplayer' | 'artplayer' | 'ddplay'): Modes;
326
327
  static fromBili(args: DMBili, cid?: bigint): UniDM;
328
+ toBiliXML(): {
329
+ '#text': string;
330
+ '@_p': string;
331
+ };
327
332
  static fromBiliCommand(args: DMBiliCommand, cid?: bigint): UniDM;
328
333
  static fromDplayer(args: DMDplayer, playerID: string, domain: string): UniDM;
329
334
  toDplayer(): DMDplayer;
@@ -32,6 +32,7 @@ export declare class UniID {
32
32
  * ### 非DanUni弹幕服务建议使用预设,或自行填写域名
33
33
  */
34
34
  domain: PlatformSource | string);
35
+ static fromString(str: string): UniID;
35
36
  toString(): string;
36
37
  static fromNull(domain?: PlatformSource | 'runtime' | string): UniID;
37
38
  static fromBili({ cid, mid, midHash, }: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dan-uni/dan-any",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "A danmaku transformer lib, supporting danmaku from different platforms.",
5
5
  "keywords": [
6
6
  "bangumi",
package/src/index.test.ts CHANGED
@@ -28,12 +28,13 @@ const xml = `<i>
28
28
  <d p="13.499,1,25,16777215,1686301548,3,2848bf1c,1335553202649003264">不喜欢</d>
29
29
  </i>`
30
30
  describe('转化自', () => {
31
- it('bili(xml)', () => {
31
+ it('bili(xml)[双向]', () => {
32
32
  const pool = UniPool.fromBiliXML(xml)
33
33
  console.info(xml)
34
34
  console.info(pool)
35
+ console.info(pool.toBiliXML())
35
36
  })
36
- it('bili(json)', () => {
37
+ it('artplayer(json)', () => {
37
38
  const json = [
38
39
  {
39
40
  text: '', // 弹幕文本
@@ -48,7 +49,7 @@ describe('转化自', () => {
48
49
  console.info(json)
49
50
  console.info(pool)
50
51
  })
51
- it('ass(双向)', () => {
52
+ it('ass[双向]', () => {
52
53
  const pool = UniPool.fromBiliXML(xml)
53
54
  const ass = pool.toASS()
54
55
  console.info(ass)
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { XMLParser } from 'fast-xml-parser'
1
+ import { XMLBuilder, XMLParser } from 'fast-xml-parser'
2
2
  import type { Options as AssGenOptions } from './ass-gen'
3
3
  import type { CommandDm as DM_JSON_BiliCommandGrpc } from './proto/gen/bili/dm_pb'
4
4
 
@@ -20,6 +20,7 @@ import { DanmakuReplySchema } from './proto/gen/danuni_pb'
20
20
 
21
21
  import { UniDM } from './utils/dm-gen'
22
22
  import * as UniDMTools from './utils/dm-gen'
23
+ import { UniID as ID } from './utils/id-gen'
23
24
  import * as UniIDTools from './utils/id-gen'
24
25
  import * as platform from './utils/platform'
25
26
 
@@ -463,6 +464,33 @@ export class UniPool {
463
464
  }),
464
465
  )
465
466
  }
467
+ toBiliXML(): string {
468
+ const genCID = (id: string) => {
469
+ const UniID = ID.fromString(id)
470
+ if (UniID.domain === platform.PlatformVideoSource.Bilibili) {
471
+ const cid = Number(UniID.id.replaceAll('def::', ''))
472
+ if (cid) return cid
473
+ }
474
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16)
475
+ }
476
+ const builder = new XMLBuilder({ ignoreAttributes: false })
477
+ return builder.build({
478
+ '?xml': {
479
+ '@_version': '1.0',
480
+ '@_encoding': 'UTF-8',
481
+ },
482
+ i: {
483
+ chatserver: 'chat.bilibili.com',
484
+ chatid: genCID(this.dans[0].SOID),
485
+ mission: 0,
486
+ maxlimit: this.dans.length,
487
+ state: 0,
488
+ real_name: 0,
489
+ source: 'k-v',
490
+ d: this.dans.map((dan) => dan.toBiliXML()),
491
+ },
492
+ })
493
+ }
466
494
  static fromBiliGrpc(bin: Uint8Array | ArrayBuffer) {
467
495
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)),
468
496
  json = data.elems
@@ -217,6 +217,7 @@ interface ExtraArtplayer {
217
217
  interface ExtraBili {
218
218
  mode?: number //原弹幕类型
219
219
  pool?: number //原弹幕池
220
+ dmid?: bigint //原弹幕ID
220
221
  adv?: string
221
222
  code?: string
222
223
  bas?: string
@@ -658,7 +659,9 @@ export class UniDM {
658
659
  senderID = ID.fromBili({ midHash: args.midHash })
659
660
  let mode = Modes.Normal
660
661
  const pool = args.pool, //暂时不做处理,兼容bili的pool格式
661
- extra: TExtra = { bili: { mode: args.mode, pool: args.pool } }
662
+ extra: TExtra = {
663
+ bili: { mode: args.mode, pool: args.pool, dmid: args.id },
664
+ }
662
665
  //重复 transMode ,但此处有关于extra的额外处理
663
666
  switch (args.mode) {
664
667
  case 4:
@@ -687,9 +690,6 @@ export class UniDM {
687
690
  mode = Modes.Normal
688
691
  break
689
692
  }
690
- // if (args.mode === 7) extra.bili.adv = args.content
691
- // else if (args.mode === 8) extra.bili.code = args.content
692
- // else if (args.mode === 9) extra.bili.bas = args.content
693
693
  return this.create({
694
694
  ...args,
695
695
  SOID: SOID.toString(),
@@ -711,6 +711,58 @@ export class UniDM {
711
711
  args.mode >= 7 ? JSON.stringify(extra, BigIntSerializer) : undefined,
712
712
  })
713
713
  }
714
+ toBiliXML() {
715
+ const recMode = (mode: Modes, extra?: ExtraBili) => {
716
+ switch (mode) {
717
+ case Modes.Normal:
718
+ return 1
719
+ case Modes.Bottom:
720
+ return 4
721
+ case Modes.Top:
722
+ return 5
723
+ case Modes.Reverse:
724
+ return 6
725
+ case Modes.Ext:
726
+ if (!extra) return 1
727
+ else if (extra.adv) return 7
728
+ else if (extra.code) return 8
729
+ else if (extra.bas) return 9
730
+ else return 1
731
+ default:
732
+ return 1
733
+ }
734
+ }
735
+ const rMode = this.extra.bili?.mode || recMode(this.mode, this.extra?.bili)
736
+ let content
737
+ switch (rMode) {
738
+ case 7:
739
+ content = this.extra?.bili?.adv
740
+ break
741
+ case 8:
742
+ content = this.extra?.bili?.code
743
+ break
744
+ case 9:
745
+ content = this.extra?.bili?.bas
746
+ break
747
+ default:
748
+ content = this.content
749
+ break
750
+ }
751
+ return {
752
+ '#text': content ?? this.content,
753
+ '@_p': [
754
+ this.progress,
755
+ rMode,
756
+ this.fontsize,
757
+ this.color,
758
+ this.ctime.getTime() / 1000,
759
+ this.extra.bili?.pool || this.pool, // 目前pool与bili兼容
760
+ this.senderID,
761
+ this.extra.bili?.dmid || this.DMID || this.toDMID(),
762
+ this.weight,
763
+ ].join(','),
764
+ }
765
+ }
714
766
  static fromBiliCommand(args: DMBiliCommand, cid?: bigint) {
715
767
  if (args.oid && !cid) cid = args.oid
716
768
  const SOID = ID.fromBili({ cid }),
@@ -23,6 +23,10 @@ export class UniID {
23
23
  */
24
24
  public domain: PlatformSource | string,
25
25
  ) {}
26
+ static fromString(str: string) {
27
+ const [id, domain] = str.split('@')
28
+ return new UniID(id, domain)
29
+ }
26
30
  toString() {
27
31
  return `${this.id}@${this.domain}`
28
32
  }