command.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.view = exports.unsubAll = 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 utils_1 = require("./utils");
  10. const logger = (0, loggers_1.getLogger)('command');
  11. function parseCmd(message) {
  12. message = message.trim();
  13. message = message.replace('\\\\', '\\0x5c');
  14. message = message.replace('\\\"', '\\0x22');
  15. message = message.replace('\\\'', '\\0x27');
  16. const strs = message.match(/'[\s\S]*?'|(?:\S+=)?"[\s\S]*?"|\S+/mg);
  17. const cmd = (strs === null || strs === void 0 ? void 0 : strs.length) ? strs[0].length ? strs[0].substring(0, 1) === '/' ? strs[0].substring(1) : '' : '' : '';
  18. const args = (strs !== null && strs !== void 0 ? strs : []).slice(1).map(arg => {
  19. arg = arg.replace(/^(\S+=)?["']+(?!.*=)|["']+$/g, '$1');
  20. arg = arg.replace('\\0x27', '\\\'');
  21. arg = arg.replace('\\0x22', '\\\"');
  22. arg = arg.replace('\\0x5c', '\\\\');
  23. return arg;
  24. });
  25. return {
  26. cmd,
  27. args,
  28. };
  29. }
  30. exports.parseCmd = parseCmd;
  31. function linkFinder(userName, chat, lock) {
  32. const normalizedLink = (0, twitter_1.linkBuilder)({ userName });
  33. const link = Object.keys(lock.threads).find(realLink => normalizedLink === realLink.replace(/\/@/, '/').toLowerCase());
  34. if (!link)
  35. return [null, -1];
  36. const index = lock.threads[link].subscribers.findIndex(({ chatID, chatType }) => chat.chatID === chatID && chat.chatType === chatType);
  37. return [link, index];
  38. }
  39. function sub(chat, args, reply, lock, lockfile) {
  40. if (chat.chatType === "temp") {
  41. return reply('请先添加机器人为好友。');
  42. }
  43. if (args.length === 0) {
  44. return reply('找不到要订阅的链接。');
  45. }
  46. const matched = (0, twitter_1.parseLink)(args[0]);
  47. if (!matched) {
  48. return reply(`订阅链接格式错误:
  49. 示例:
  50. https://www.instagram.com/tomoyo_kurosawa_/
  51. https://www.instagram.com/p/B6GHRSmgV-7/
  52. https://www.instagram.com/tomoyo_kurosawa_/p/B6GHRSmgV-7/`);
  53. }
  54. let offset = '0';
  55. const subscribeTo = (link, config = {}) => {
  56. const { id, msg = `已为此聊天订阅 ${link}` } = config;
  57. if (id) {
  58. lock.feed.push(link);
  59. lock.threads[link] = {
  60. id,
  61. offset,
  62. subscribers: [],
  63. updatedAt: '',
  64. };
  65. }
  66. lock.threads[link].subscribers.push(chat);
  67. logger.warn(`chat ${JSON.stringify(chat)} has subscribed ${link}`);
  68. fs.writeFileSync(path.resolve(lockfile), JSON.stringify(lock));
  69. reply(msg);
  70. };
  71. const tryFindSub = (userName) => {
  72. const [realLink, index] = linkFinder(userName, chat, lock);
  73. if (index > -1) {
  74. reply('此聊天已订阅此链接。');
  75. return true;
  76. }
  77. if (realLink) {
  78. subscribeTo(realLink);
  79. return true;
  80. }
  81. return false;
  82. };
  83. const newSub = (userName) => {
  84. const link = (0, twitter_1.linkBuilder)(matched);
  85. let msg;
  86. if (offset !== '0') {
  87. msg = `已为此聊天订阅 ${link} 并回溯到 ${args[0].replace(/\?.*/, '')}(含)之后的第一条动态`;
  88. }
  89. return subscribeTo(link, { id: Number(userName.split(':')[1]), msg });
  90. };
  91. if (matched.postUrlSegment) {
  92. offset = utils_1.BigNumOps.plus((0, twitter_1.urlSegmentToId)(matched.postUrlSegment), '-1');
  93. (0, twitter_1.getPostOwner)(matched.postUrlSegment).then(userName => {
  94. matched.userName = userName.split(':')[0];
  95. if (!tryFindSub(matched.userName))
  96. newSub(userName);
  97. }).catch((parsedErr) => {
  98. reply(parsedErr.message);
  99. });
  100. }
  101. else if (!tryFindSub(matched.userName)) {
  102. twitter_1.ScreenNameNormalizer.normalizeLive(matched.userName).then(userName => {
  103. if (!userName)
  104. return reply(`找不到用户 ${matched.userName.replace(/^@?(.*)$/, '@$1')}。`);
  105. else
  106. newSub(userName);
  107. });
  108. }
  109. }
  110. exports.sub = sub;
  111. function unsubAll(chat, args, reply, lock, lockfile) {
  112. if (chat.chatType === "temp") {
  113. return reply('请先添加机器人为好友。');
  114. }
  115. Object.entries(lock.threads).forEach(([link, { subscribers }]) => {
  116. const index = subscribers.indexOf(chat);
  117. if (index === -1)
  118. return;
  119. subscribers.splice(index, 1);
  120. fs.writeFileSync(path.resolve(lockfile), JSON.stringify(lock));
  121. logger.warn(`chat ${JSON.stringify(chat)} has unsubscribed ${link}`);
  122. });
  123. return reply(`已为此聊天退订所有 Instagram 链接。`);
  124. }
  125. exports.unsubAll = unsubAll;
  126. function unsub(chat, args, reply, lock, lockfile) {
  127. var _a;
  128. if (chat.chatType === "temp") {
  129. return reply('请先添加机器人为好友。');
  130. }
  131. if (args.length === 0) {
  132. return reply('找不到要退订的链接。');
  133. }
  134. const match = (_a = (0, twitter_1.parseLink)(args[0])) === null || _a === void 0 ? void 0 : _a.userName;
  135. if (!match) {
  136. return reply('链接格式有误。');
  137. }
  138. const [link, index] = linkFinder(match, chat, lock);
  139. if (index === -1)
  140. return list(chat, args, msg => reply('您没有订阅此链接。\n' + msg), lock);
  141. else {
  142. lock.threads[link].subscribers.splice(index, 1);
  143. fs.writeFileSync(path.resolve(lockfile), JSON.stringify(lock));
  144. logger.warn(`chat ${JSON.stringify(chat)} has unsubscribed ${link}`);
  145. return reply(`已为此聊天退订 ${link}`);
  146. }
  147. }
  148. exports.unsub = unsub;
  149. function list(chat, _, reply, lock) {
  150. if (chat.chatType === "temp") {
  151. return reply('请先添加机器人为好友。');
  152. }
  153. const links = [];
  154. Object.keys(lock.threads).forEach(key => {
  155. if (lock.threads[key].subscribers.find(({ chatID, chatType }) => chat.chatID === chatID && chat.chatType === chatType))
  156. links.push(`${key} ${(0, datetime_1.relativeDate)(lock.threads[key].updatedAt)}`);
  157. });
  158. return reply('此聊天中订阅的 Instagram 动态链接:\n' + links.join('\n'));
  159. }
  160. exports.list = list;
  161. function view(chat, args, reply) {
  162. var _a;
  163. if (args.length === 0) {
  164. return reply('找不到要查看的链接。');
  165. }
  166. const match = (_a = (0, twitter_1.parseLink)(args[0])) === null || _a === void 0 ? void 0 : _a.postUrlSegment;
  167. if (!match) {
  168. return reply('链接格式有误。');
  169. }
  170. try {
  171. (0, twitter_1.sendPost)(match, chat);
  172. }
  173. catch (e) {
  174. reply('机器人尚未加载完毕,请稍后重试。');
  175. }
  176. }
  177. exports.view = view;