@dan-uni/dan-any 0.4.7 → 0.4.8

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
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,9 +5209,9 @@ 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;
@@ -5256,11 +5260,63 @@ class UniDM {
5256
5260
  extra: args.mode >= 7 ? JSON.stringify(extra, BigIntSerializer) : void 0
5257
5261
  });
5258
5262
  }
5263
+ toBiliXML() {
5264
+ const recMode = (mode, extra)=>{
5265
+ switch(mode){
5266
+ case 0:
5267
+ return 1;
5268
+ case 1:
5269
+ return 4;
5270
+ case 2:
5271
+ return 5;
5272
+ case 3:
5273
+ return 6;
5274
+ case 4:
5275
+ if (!extra) return 1;
5276
+ if (extra.adv) return 7;
5277
+ if (extra.code) return 8;
5278
+ else if (extra.bas) return 9;
5279
+ else return 1;
5280
+ default:
5281
+ return 1;
5282
+ }
5283
+ };
5284
+ const rMode = recMode(this.mode, this.extra?.bili);
5285
+ let content;
5286
+ switch(rMode){
5287
+ case 7:
5288
+ content = this.extra?.bili?.adv;
5289
+ break;
5290
+ case 8:
5291
+ content = this.extra?.bili?.code;
5292
+ break;
5293
+ case 9:
5294
+ content = this.extra?.bili?.bas;
5295
+ break;
5296
+ default:
5297
+ content = this.content;
5298
+ break;
5299
+ }
5300
+ return {
5301
+ '#text': content ?? this.content,
5302
+ '@_p': [
5303
+ this.progress,
5304
+ rMode,
5305
+ this.fontsize,
5306
+ this.color,
5307
+ this.ctime.getTime() / 1000,
5308
+ this.pool,
5309
+ this.senderID,
5310
+ this.DMID || this.toDMID(),
5311
+ this.weight
5312
+ ].join(',')
5313
+ };
5314
+ }
5259
5315
  static fromBiliCommand(args, cid) {
5260
5316
  if (args.oid && !cid) cid = args.oid;
5261
- const SOID = UniID.fromBili({
5317
+ const SOID = id_gen_UniID.fromBili({
5262
5318
  cid
5263
- }), senderID = UniID.fromBili({
5319
+ }), senderID = id_gen_UniID.fromBili({
5264
5320
  mid: args.mid
5265
5321
  });
5266
5322
  return this.create({
@@ -5283,7 +5339,7 @@ class UniDM {
5283
5339
  });
5284
5340
  }
5285
5341
  static fromDplayer(args, playerID, domain) {
5286
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown(args.midHash, domain);
5342
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown(args.midHash, domain);
5287
5343
  return this.create({
5288
5344
  ...args,
5289
5345
  SOID: SOID.toString(),
@@ -5305,7 +5361,7 @@ class UniDM {
5305
5361
  };
5306
5362
  }
5307
5363
  static fromArtplayer(args, playerID, domain) {
5308
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown('', domain);
5364
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown('', domain);
5309
5365
  let extra = args.border ? {
5310
5366
  artplayer: {
5311
5367
  border: args.border,
@@ -5345,7 +5401,7 @@ class UniDM {
5345
5401
  };
5346
5402
  }
5347
5403
  static fromDDplay(args, episodeId, domain = platform_PlatformDanmakuOnlySource.DanDanPlay) {
5348
- const SOID = UniID.fromUnknown(`def::${episodeId}`, domain);
5404
+ const SOID = id_gen_UniID.fromUnknown(`def::${episodeId}`, domain);
5349
5405
  return this.create({
5350
5406
  ...args,
5351
5407
  SOID: SOID.toString(),
@@ -5725,6 +5781,35 @@ class UniPool {
5725
5781
  }, BigInt(oriData.i.chatid));
5726
5782
  }));
5727
5783
  }
5784
+ toBiliXML() {
5785
+ const genCID = (id)=>{
5786
+ const UniID = id_gen_UniID.fromString(id);
5787
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
5788
+ const cid = Number(UniID.id.replaceAll('def::', ''));
5789
+ if (cid) return cid;
5790
+ }
5791
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
5792
+ };
5793
+ const builder = new XMLBuilder({
5794
+ ignoreAttributes: false
5795
+ });
5796
+ return builder.build({
5797
+ '?xml': {
5798
+ '@_version': '1.0',
5799
+ '@_encoding': 'UTF-8'
5800
+ },
5801
+ i: {
5802
+ chatserver: 'chat.bilibili.com',
5803
+ chatid: genCID(this.dans[0].SOID),
5804
+ mission: 0,
5805
+ maxlimit: this.dans.length,
5806
+ state: 0,
5807
+ real_name: 0,
5808
+ source: 'k-v',
5809
+ d: this.dans.map((dan)=>dan.toBiliXML())
5810
+ }
5811
+ });
5812
+ }
5728
5813
  static fromBiliGrpc(bin) {
5729
5814
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
5730
5815
  return new UniPool(json.map((d)=>UniDM.fromBili({
@@ -6615,6 +6700,35 @@ class src_UniPool {
6615
6700
  }, BigInt(oriData.i.chatid));
6616
6701
  }));
6617
6702
  }
6703
+ toBiliXML() {
6704
+ const genCID = (id)=>{
6705
+ const UniID = id_gen_UniID.fromString(id);
6706
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
6707
+ const cid = Number(UniID.id.replaceAll('def::', ''));
6708
+ if (cid) return cid;
6709
+ }
6710
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
6711
+ };
6712
+ const builder = new XMLBuilder({
6713
+ ignoreAttributes: false
6714
+ });
6715
+ return builder.build({
6716
+ '?xml': {
6717
+ '@_version': '1.0',
6718
+ '@_encoding': 'UTF-8'
6719
+ },
6720
+ i: {
6721
+ chatserver: 'chat.bilibili.com',
6722
+ chatid: genCID(this.dans[0].SOID),
6723
+ mission: 0,
6724
+ maxlimit: this.dans.length,
6725
+ state: 0,
6726
+ real_name: 0,
6727
+ source: 'k-v',
6728
+ d: this.dans.map((dan)=>dan.toBiliXML())
6729
+ }
6730
+ });
6731
+ }
6618
6732
  static fromBiliGrpc(bin) {
6619
6733
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
6620
6734
  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,9 +19254,9 @@
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;
@@ -19020,11 +19305,63 @@
19020
19305
  extra: args.mode >= 7 ? JSON.stringify(extra, BigIntSerializer) : void 0
19021
19306
  });
19022
19307
  }
19308
+ toBiliXML() {
19309
+ const recMode = (mode, extra)=>{
19310
+ switch(mode){
19311
+ case 0:
19312
+ return 1;
19313
+ case 1:
19314
+ return 4;
19315
+ case 2:
19316
+ return 5;
19317
+ case 3:
19318
+ return 6;
19319
+ case 4:
19320
+ if (!extra) return 1;
19321
+ if (extra.adv) return 7;
19322
+ if (extra.code) return 8;
19323
+ else if (extra.bas) return 9;
19324
+ else return 1;
19325
+ default:
19326
+ return 1;
19327
+ }
19328
+ };
19329
+ const rMode = recMode(this.mode, this.extra?.bili);
19330
+ let content;
19331
+ switch(rMode){
19332
+ case 7:
19333
+ content = this.extra?.bili?.adv;
19334
+ break;
19335
+ case 8:
19336
+ content = this.extra?.bili?.code;
19337
+ break;
19338
+ case 9:
19339
+ content = this.extra?.bili?.bas;
19340
+ break;
19341
+ default:
19342
+ content = this.content;
19343
+ break;
19344
+ }
19345
+ return {
19346
+ '#text': content ?? this.content,
19347
+ '@_p': [
19348
+ this.progress,
19349
+ rMode,
19350
+ this.fontsize,
19351
+ this.color,
19352
+ this.ctime.getTime() / 1000,
19353
+ this.pool,
19354
+ this.senderID,
19355
+ this.DMID || this.toDMID(),
19356
+ this.weight
19357
+ ].join(',')
19358
+ };
19359
+ }
19023
19360
  static fromBiliCommand(args, cid) {
19024
19361
  if (args.oid && !cid) cid = args.oid;
19025
- const SOID = UniID.fromBili({
19362
+ const SOID = id_gen_UniID.fromBili({
19026
19363
  cid
19027
- }), senderID = UniID.fromBili({
19364
+ }), senderID = id_gen_UniID.fromBili({
19028
19365
  mid: args.mid
19029
19366
  });
19030
19367
  return this.create({
@@ -19047,7 +19384,7 @@
19047
19384
  });
19048
19385
  }
19049
19386
  static fromDplayer(args, playerID, domain) {
19050
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown(args.midHash, domain);
19387
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown(args.midHash, domain);
19051
19388
  return this.create({
19052
19389
  ...args,
19053
19390
  SOID: SOID.toString(),
@@ -19069,7 +19406,7 @@
19069
19406
  };
19070
19407
  }
19071
19408
  static fromArtplayer(args, playerID, domain) {
19072
- const SOID = UniID.fromUnknown(playerID, domain), senderID = UniID.fromUnknown('', domain);
19409
+ const SOID = id_gen_UniID.fromUnknown(playerID, domain), senderID = id_gen_UniID.fromUnknown('', domain);
19073
19410
  let extra = args.border ? {
19074
19411
  artplayer: {
19075
19412
  border: args.border,
@@ -19109,7 +19446,7 @@
19109
19446
  };
19110
19447
  }
19111
19448
  static fromDDplay(args, episodeId, domain = platform_PlatformDanmakuOnlySource.DanDanPlay) {
19112
- const SOID = UniID.fromUnknown(`def::${episodeId}`, domain);
19449
+ const SOID = id_gen_UniID.fromUnknown(`def::${episodeId}`, domain);
19113
19450
  return this.create({
19114
19451
  ...args,
19115
19452
  SOID: SOID.toString(),
@@ -19134,6 +19471,7 @@
19134
19471
  };
19135
19472
  }
19136
19473
  }
19474
+ var Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
19137
19475
  class UniPool {
19138
19476
  dans;
19139
19477
  options;
@@ -19489,6 +19827,35 @@
19489
19827
  }, BigInt(oriData.i.chatid));
19490
19828
  }));
19491
19829
  }
19830
+ toBiliXML() {
19831
+ const genCID = (id)=>{
19832
+ const UniID = id_gen_UniID.fromString(id);
19833
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
19834
+ const cid = Number(UniID.id.replaceAll('def::', ''));
19835
+ if (cid) return cid;
19836
+ }
19837
+ return Number.parseInt(Buffer.from(id).toString('hex'), 16);
19838
+ };
19839
+ const builder = new Builder({
19840
+ ignoreAttributes: false
19841
+ });
19842
+ return builder.build({
19843
+ '?xml': {
19844
+ '@_version': '1.0',
19845
+ '@_encoding': 'UTF-8'
19846
+ },
19847
+ i: {
19848
+ chatserver: 'chat.bilibili.com',
19849
+ chatid: genCID(this.dans[0].SOID),
19850
+ mission: 0,
19851
+ maxlimit: this.dans.length,
19852
+ state: 0,
19853
+ real_name: 0,
19854
+ source: 'k-v',
19855
+ d: this.dans.map((dan)=>dan.toBiliXML())
19856
+ }
19857
+ });
19858
+ }
19492
19859
  static fromBiliGrpc(bin) {
19493
19860
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
19494
19861
  return new UniPool(json.map((d)=>UniDM.fromBili({
@@ -19884,7 +20251,7 @@
19884
20251
  };
19885
20252
  var lib = __webpack_require__("../../node_modules/.pnpm/browserify-zlib@0.2.0/node_modules/browserify-zlib/lib/index.js");
19886
20253
  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"];
20254
+ var raw_Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
19888
20255
  const compressTypes = [
19889
20256
  'brotli',
19890
20257
  'gzip'
@@ -19903,7 +20270,7 @@
19903
20270
  config,
19904
20271
  context
19905
20272
  }, rawText = JSON.stringify(raw1);
19906
- let compress = Buffer.from('');
20273
+ let compress = raw_Buffer.from('');
19907
20274
  compress = 'brotli' === compressType ? (0, lib.brotliCompressSync)(rawText) : (0, lib.gzipSync)(rawText);
19908
20275
  return `;RawCompressType: ${compressType}\n;RawBaseType: ${baseType}\n;Raw: ${'base64' === baseType ? compress.toString('base64') : fromUint16Array(base16384_lib.encode(compress))}`;
19909
20276
  }
@@ -19914,8 +20281,8 @@
19914
20281
  let compressType = lineCompressType.replace(';RawCompressType: ', '').trim(), baseType = lineBaseType.replace(';RawBaseType: ', '').trim();
19915
20282
  if (!compressTypes.includes(compressType)) compressType = 'gzip';
19916
20283
  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('');
20284
+ 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')));
20285
+ let decompress = raw_Buffer.from('');
19919
20286
  decompress = 'brotli' === compressType ? (0, lib.brotliDecompressSync)(buffer) : (0, lib.gunzipSync)(buffer);
19920
20287
  try {
19921
20288
  return JSON.parse(decompress.toString('utf-8'));
@@ -20028,6 +20395,7 @@
20028
20395
  if (!raw) return UniPool.create();
20029
20396
  return DanmakuList2UniPool(raw.list);
20030
20397
  }
20398
+ var src_Buffer = __webpack_require__("../../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.js")["Buffer"];
20031
20399
  class src_UniPool {
20032
20400
  dans;
20033
20401
  options;
@@ -20383,6 +20751,35 @@
20383
20751
  }, BigInt(oriData.i.chatid));
20384
20752
  }));
20385
20753
  }
20754
+ toBiliXML() {
20755
+ const genCID = (id)=>{
20756
+ const UniID = id_gen_UniID.fromString(id);
20757
+ if (UniID.domain === platform_PlatformVideoSource.Bilibili) {
20758
+ const cid = Number(UniID.id.replaceAll('def::', ''));
20759
+ if (cid) return cid;
20760
+ }
20761
+ return Number.parseInt(src_Buffer.from(id).toString('hex'), 16);
20762
+ };
20763
+ const builder = new Builder({
20764
+ ignoreAttributes: false
20765
+ });
20766
+ return builder.build({
20767
+ '?xml': {
20768
+ '@_version': '1.0',
20769
+ '@_encoding': 'UTF-8'
20770
+ },
20771
+ i: {
20772
+ chatserver: 'chat.bilibili.com',
20773
+ chatid: genCID(this.dans[0].SOID),
20774
+ mission: 0,
20775
+ maxlimit: this.dans.length,
20776
+ state: 0,
20777
+ real_name: 0,
20778
+ source: 'k-v',
20779
+ d: this.dans.map((dan)=>dan.toBiliXML())
20780
+ }
20781
+ });
20782
+ }
20386
20783
  static fromBiliGrpc(bin) {
20387
20784
  const data = fromBinary(DmSegMobileReplySchema, new Uint8Array(bin)), json = data.elems;
20388
20785
  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二进制
@@ -324,6 +324,10 @@ export declare class UniDM {
324
324
  static transCtime(oriCtime: ctime, tsUnit?: 'ms' | 's'): Date;
325
325
  static transMode(oriMode: number, fmt: 'bili' | 'dplayer' | 'artplayer' | 'ddplay'): Modes;
326
326
  static fromBili(args: DMBili, cid?: bigint): UniDM;
327
+ toBiliXML(): {
328
+ '#text': string;
329
+ '@_p': string;
330
+ };
327
331
  static fromBiliCommand(args: DMBiliCommand, cid?: bigint): UniDM;
328
332
  static fromDplayer(args: DMDplayer, playerID: string, domain: string): UniDM;
329
333
  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.8",
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
@@ -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 = 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.pool, // 目前pool与bili兼容
760
+ this.senderID,
761
+ 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
  }