command.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.view = exports.unsub = exports.list = exports.sub = exports.parseCmd = void 0;
  4. const fs = require("fs");
  5. const path = require("path");
  6. const datetime_1 = require("./datetime");
  7. const loggers_1 = require("./loggers");
  8. const twitter_1 = require("./twitter");
  9. const logger = loggers_1.getLogger('command');
  10. function parseCmd(message) {
  11. message = message.trim();
  12. message = message.replace('\\\\', '\\0x5c');
  13. message = message.replace('\\\"', '\\0x22');
  14. message = message.replace('\\\'', '\\0x27');
  15. const strs = message.match(/'[\s\S]*?'|(?:\S+=)?"[\s\S]*?"|\S+/mg);
  16. const cmd = (strs === null || strs === void 0 ? void 0 : strs.length) ? strs[0].length ? strs[0].substring(0, 1) === '/' ? strs[0].substring(1) : '' : '' : '';
  17. const args = (strs !== null && strs !== void 0 ? strs : []).slice(1).map(arg => {
  18. arg = arg.replace(/^(\S+=)?["']+(?!.*=)|["']+$/g, '$1');
  19. arg = arg.replace('\\0x27', '\\\'');
  20. arg = arg.replace('\\0x22', '\\\"');
  21. arg = arg.replace('\\0x5c', '\\\\');
  22. return arg;
  23. });
  24. return {
  25. cmd,
  26. args,
  27. };
  28. }
  29. exports.parseCmd = parseCmd;
  30. function parseLink(link) {
  31. const match = /twitter.com\/([^\/?#]+)/.exec(link) ||
  32. /^([^\/?#]+)$/.exec(link);
  33. if (match)
  34. return [match[1]];
  35. return;
  36. }
  37. function linkBuilder(userName, more = '') {
  38. if (!userName)
  39. return;
  40. return `https://twitter.com/${userName}${more}`;
  41. }
  42. function linkFinder(checkedMatch, chat, lock) {
  43. var _a;
  44. const normalizedLink = linkBuilder(twitter_1.ScreenNameNormalizer.normalize(checkedMatch[0]), (_a = checkedMatch[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase());
  45. const link = Object.keys(lock.threads).find(realLink => normalizedLink === realLink.replace(/\/@/, '/').toLowerCase());
  46. if (!link)
  47. return [null, -1];
  48. const index = lock.threads[link].subscribers.findIndex(({ chatID, chatType }) => chat.chatID === chatID && chat.chatType === chatType);
  49. return [link, index];
  50. }
  51. function sub(chat, args, reply, lock, lockfile) {
  52. if (chat.chatType === "temp") {
  53. return reply('请先添加机器人为好友。');
  54. }
  55. if (args.length === 0) {
  56. return reply('找不到要订阅推特限时动态的链接。');
  57. }
  58. const match = parseLink(args[0]);
  59. if (!match) {
  60. return reply(`订阅链接格式错误:
  61. 示例:https://twitter.com/sunflower930316`);
  62. }
  63. const subscribeTo = (link, config = {}) => {
  64. const { addNew = false, msg = `已为此聊天订阅 ${link} 的推特限时动态` } = config;
  65. if (addNew) {
  66. lock.feed.push(link);
  67. lock.threads[link] = {
  68. permaFeed: twitter_1.ScreenNameNormalizer.permaFeeds[link],
  69. offset: '0',
  70. subscribers: [],
  71. updatedAt: '',
  72. };
  73. }
  74. lock.threads[link].subscribers.push(chat);
  75. logger.warn(`chat ${JSON.stringify(chat)} has subscribed fleets for ${link}`);
  76. fs.writeFileSync(path.resolve(lockfile), JSON.stringify(lock));
  77. reply(msg);
  78. };
  79. const [realLink, index] = linkFinder(match, chat, lock);
  80. if (index > -1)
  81. return reply('此聊天已订阅此链接。');
  82. if (realLink)
  83. return subscribeTo(realLink);
  84. const [rawUserName, more] = match;
  85. twitter_1.ScreenNameNormalizer.normalizeLive(rawUserName).then(userName => {
  86. if (!userName)
  87. return reply(`找不到用户 ${rawUserName.replace(/^@?(.*)$/, '@$1')}。`);
  88. subscribeTo(linkBuilder(userName, more), { addNew: true });
  89. });
  90. }
  91. exports.sub = sub;
  92. function unsub(chat, args, reply, lock, lockfile) {
  93. if (chat.chatType === "temp") {
  94. return reply('请先添加机器人为好友。');
  95. }
  96. if (args.length === 0) {
  97. return reply('找不到要退订推特限时动态的链接。');
  98. }
  99. const match = parseLink(args[0]);
  100. if (!match) {
  101. return reply('链接格式有误。');
  102. }
  103. const [link, index] = linkFinder(match, chat, lock);
  104. if (index === -1)
  105. return list(chat, args, msg => reply('您没有订阅此链接的推特限时动态。\n' + msg), lock);
  106. else {
  107. lock.threads[link].subscribers.splice(index, 1);
  108. fs.writeFileSync(path.resolve(lockfile), JSON.stringify(lock));
  109. logger.warn(`chat ${JSON.stringify(chat)} has unsubscribed ${link}`);
  110. return reply(`已为此聊天退订 ${link} 的推特限时动态`);
  111. }
  112. }
  113. exports.unsub = unsub;
  114. function list(chat, _, reply, lock) {
  115. if (chat.chatType === "temp") {
  116. return reply('请先添加机器人为好友。');
  117. }
  118. const links = [];
  119. Object.keys(lock.threads).forEach(key => {
  120. if (lock.threads[key].subscribers.find(({ chatID, chatType }) => chat.chatID === chatID && chat.chatType === chatType))
  121. links.push(`${key} ${datetime_1.relativeDate(lock.threads[key].updatedAt)}`);
  122. });
  123. return reply('此聊天中订阅推特限时动态的链接:\n' + links.join('\n'));
  124. }
  125. exports.list = list;
  126. function view(chat, args, reply) {
  127. if (args.length === 0) {
  128. return reply('找不到要查看的链接。');
  129. }
  130. const checkedMatch = parseLink(args[0]);
  131. if (!checkedMatch) {
  132. return reply(`订阅链接格式错误:
  133. 示例:https://twitter.com/sunflower930316`);
  134. }
  135. try {
  136. twitter_1.sendAllFleets(checkedMatch[0], chat);
  137. }
  138. catch (e) {
  139. reply('推特机器人尚未加载完毕,请稍后重试。');
  140. }
  141. }
  142. exports.view = view;