main.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/env node
  2. "use strict";
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. const fs = require("fs");
  5. const path = require("path");
  6. const commandLineUsage = require("command-line-usage");
  7. const exampleConfig = require("../config.example.json");
  8. const command_1 = require("./command");
  9. const loggers_1 = require("./loggers");
  10. const koishi_1 = require("./koishi");
  11. const twitter_1 = require("./twitter");
  12. const logger = loggers_1.getLogger();
  13. const sections = [
  14. {
  15. header: 'GoCQHTTP Instagram Bot',
  16. content: 'The QQ Bot that forwards Instagram.',
  17. },
  18. {
  19. header: 'Synopsis',
  20. content: [
  21. '$ cq-instagram-bot {underline config.json}',
  22. '$ cq-instagram-bot {bold --help}',
  23. ],
  24. },
  25. {
  26. header: 'Documentation',
  27. content: [
  28. 'Project home: {underline https://github.com/CL-Jeremy/mirai-twitter-bot}',
  29. 'Example config: {underline https://git.io/JJ0jN}',
  30. ],
  31. },
  32. ];
  33. const usage = commandLineUsage(sections);
  34. const args = process.argv.slice(2);
  35. if (args.length === 0 || args[0] === 'help' || args[0] === '-h' || args[0] === '--help') {
  36. console.log(usage);
  37. process.exit(0);
  38. }
  39. const configPath = args[0];
  40. let config;
  41. try {
  42. config = JSON.parse(fs.readFileSync(path.resolve(configPath), 'utf8'));
  43. }
  44. catch (e) {
  45. console.log('Failed to parse config file: ', configPath);
  46. console.log(usage);
  47. process.exit(1);
  48. }
  49. const requiredFields = [
  50. 'ig_username', 'ig_password',
  51. 'cq_bot_qq', ...(config.mode || exampleConfig.mode) === 0 ? ['playwright_ws_spec_endpoint'] : [],
  52. ];
  53. const warningFields = [
  54. 'cq_ws_host', 'cq_ws_port', 'cq_access_token',
  55. ];
  56. const optionalFields = [
  57. 'lockfile', 'inactive_hours', 'work_interval', 'webshot_delay', 'loglevel', 'mode', 'resume_on_start', 'ig_socks_proxy',
  58. ].concat(warningFields);
  59. if (requiredFields.some((value) => config[value] === undefined)) {
  60. console.log(`${requiredFields.join(', ')} are required`);
  61. process.exit(1);
  62. }
  63. optionalFields.forEach(key => {
  64. if (config[key] === undefined || typeof (config[key]) !== typeof (exampleConfig[key])) {
  65. if (warningFields.includes(key))
  66. logger.warn(`${key} is undefined, use ${exampleConfig[key] || 'empty string'} as default`);
  67. config[key] = exampleConfig[key];
  68. }
  69. });
  70. ['ig_session_lockfile', ...(config.mode || exampleConfig.mode) === 0 ? ['webshot_cookies_lockfile'] : []].forEach(key => {
  71. if (!config[key]) {
  72. logger.warn(`${key} is undefined, use <username>.${key.replace('_lockfile', '.lock')} as default`);
  73. config[key] = `${config.ig_username}.${key.replace('_lockfile', '.lock')}`;
  74. }
  75. });
  76. const k = 'ig_2fa_code_receiver_port';
  77. if (!config[k] || config[k] < 2048 || config[k] > 65536) {
  78. logger.warn(`invalid value of config.${k}, use ${exampleConfig[k]} as default`);
  79. config[k] = exampleConfig[k];
  80. }
  81. loggers_1.setLogLevels(config.loglevel);
  82. let lock;
  83. if (fs.existsSync(path.resolve(config.lockfile))) {
  84. try {
  85. lock = JSON.parse(fs.readFileSync(path.resolve(config.lockfile), 'utf8'));
  86. }
  87. catch (err) {
  88. logger.error(`Failed to parse lockfile ${config.lockfile}: `, err);
  89. lock = {
  90. workon: 0,
  91. feed: [],
  92. threads: {},
  93. };
  94. }
  95. fs.access(path.resolve(config.lockfile), fs.constants.W_OK, err => {
  96. if (err) {
  97. logger.fatal(`cannot write lockfile ${path.resolve(config.lockfile)}, permission denied`);
  98. process.exit(1);
  99. }
  100. });
  101. }
  102. else {
  103. lock = {
  104. workon: 0,
  105. feed: [],
  106. threads: {},
  107. };
  108. try {
  109. fs.writeFileSync(path.resolve(config.lockfile), JSON.stringify(lock));
  110. }
  111. catch (err) {
  112. logger.fatal(`cannot write lockfile ${path.resolve(config.lockfile)}, permission denied`);
  113. process.exit(1);
  114. }
  115. }
  116. if (!config.resume_on_start) {
  117. Object.keys(lock.threads).forEach(key => {
  118. lock.threads[key].offset = '-1';
  119. });
  120. }
  121. const qq = new koishi_1.default({
  122. access_token: config.cq_access_token,
  123. host: config.cq_ws_host,
  124. port: config.cq_ws_port,
  125. bot_id: config.cq_bot_qq,
  126. list: (c, a, cb) => command_1.list(c, a, cb, lock),
  127. sub: (c, a, cb) => command_1.sub(c, a, cb, lock, config.lockfile),
  128. unsub: (c, a, cb) => command_1.unsub(c, a, cb, lock, config.lockfile),
  129. });
  130. const worker = new twitter_1.default({
  131. sessionLockfile: config.ig_session_lockfile,
  132. credentials: [config.ig_username, config.ig_password],
  133. codeServicePort: config.ig_2fa_code_receiver_port,
  134. proxyUrl: config.ig_socks_proxy,
  135. lock,
  136. lockfile: config.lockfile,
  137. inactiveHours: config.inactive_hours,
  138. workInterval: config.work_interval,
  139. bot: qq,
  140. webshotDelay: config.webshot_delay,
  141. webshotCookiesLockfile: config.webshot_cookies_lockfile,
  142. mode: config.mode,
  143. wsUrl: config.playwright_ws_spec_endpoint,
  144. });
  145. worker.session.init().then(worker.launch);
  146. qq.connect();