twitter.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const fs = require("fs");
  4. const log4js = require("log4js");
  5. const path = require("path");
  6. const Twitter = require("twitter");
  7. const webshot_1 = require("./webshot");
  8. const logger = log4js.getLogger('twitter');
  9. logger.level = global.loglevel;
  10. class default_1 {
  11. constructor(opt) {
  12. this.work = () => {
  13. const lock = this.lock;
  14. if (this.workInterval < 1)
  15. this.workInterval = 1;
  16. if (lock.feed.length === 0) {
  17. setTimeout(() => {
  18. this.work();
  19. }, this.workInterval * 1000);
  20. return;
  21. }
  22. if (lock.workon >= lock.feed.length)
  23. lock.workon = 0;
  24. if (!lock.threads[lock.feed[lock.workon]] ||
  25. !lock.threads[lock.feed[lock.workon]].subscribers ||
  26. lock.threads[lock.feed[lock.workon]].subscribers.length === 0) {
  27. logger.warn(`nobody subscribes thread ${lock.feed[lock.workon]}, removing from feed`);
  28. delete lock.threads[lock.feed[lock.workon]];
  29. lock.feed.splice(lock.workon, 1);
  30. fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
  31. this.work();
  32. return;
  33. }
  34. logger.debug(`pulling feed ${lock.feed[lock.workon]}`);
  35. const promise = new Promise(resolve => {
  36. let match = lock.feed[lock.workon].match(/https:\/\/twitter.com\/([^\/]+)\/lists\/([^\/]+)/);
  37. let config;
  38. let endpoint;
  39. if (match) {
  40. config = {
  41. owner_screen_name: match[1],
  42. slug: match[2],
  43. };
  44. endpoint = 'lists/statuses';
  45. }
  46. else {
  47. match = lock.feed[lock.workon].match(/https:\/\/twitter.com\/([^\/]+)/);
  48. if (match) {
  49. config = {
  50. screen_name: match[1],
  51. exclude_replies: false,
  52. };
  53. endpoint = 'statuses/user_timeline';
  54. }
  55. }
  56. if (endpoint) {
  57. const offset = lock.threads[lock.feed[lock.workon]].offset;
  58. if (offset > 0)
  59. config.since_id = offset;
  60. this.client.get(endpoint, config, (error, tweets, response) => {
  61. if (error) {
  62. if (error instanceof Array && error.length > 0 && error[0].code === 34) {
  63. logger.warn(`error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
  64. lock.threads[lock.feed[lock.workon]].subscribers.forEach(subscriber => {
  65. logger.info(`sending notfound message of ${lock.feed[lock.workon]} to ${JSON.stringify(subscriber)}`);
  66. this.bot.bot('send_msg', {
  67. message_type: subscriber.chatType,
  68. user_id: subscriber.chatID,
  69. group_id: subscriber.chatID,
  70. discuss_id: subscriber.chatID,
  71. message: `链接 ${lock.feed[lock.workon]} 指向的用户或列表不存在,请退订。`,
  72. });
  73. });
  74. }
  75. else {
  76. logger.error(`unhandled error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
  77. }
  78. resolve();
  79. }
  80. else
  81. resolve(tweets);
  82. });
  83. }
  84. });
  85. promise.then((tweets) => {
  86. logger.debug(`api returned ${JSON.stringify(tweets)} for feed ${lock.feed[lock.workon]}`);
  87. if (!tweets || tweets.length === 0) {
  88. lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
  89. return;
  90. }
  91. if (lock.threads[lock.feed[lock.workon]].offset === -1) {
  92. lock.threads[lock.feed[lock.workon]].offset = tweets[0].id_str;
  93. return;
  94. }
  95. if (lock.threads[lock.feed[lock.workon]].offset === 0)
  96. tweets.splice(1);
  97. return webshot_1.default(tweets, msg => {
  98. lock.threads[lock.feed[lock.workon]].subscribers.forEach(subscriber => {
  99. logger.info(`pushing data of thread ${lock.feed[lock.workon]} to ${JSON.stringify(subscriber)}`);
  100. this.bot.bot('send_msg', {
  101. message_type: subscriber.chatType,
  102. user_id: subscriber.chatID,
  103. group_id: subscriber.chatID,
  104. discuss_id: subscriber.chatID,
  105. message: msg,
  106. });
  107. });
  108. }, this.webshotDelay)
  109. .then(() => {
  110. lock.threads[lock.feed[lock.workon]].offset = tweets[0].id_str;
  111. lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
  112. });
  113. })
  114. .then(() => {
  115. lock.workon++;
  116. let timeout = this.workInterval * 1000 / lock.feed.length;
  117. if (timeout < 1000)
  118. timeout = 1000;
  119. fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
  120. setTimeout(() => {
  121. this.work();
  122. }, timeout);
  123. });
  124. };
  125. this.client = new Twitter({
  126. consumer_key: opt.consumer_key,
  127. consumer_secret: opt.consumer_secret,
  128. access_token_key: opt.access_token_key,
  129. access_token_secret: opt.access_token_secret,
  130. });
  131. this.lockfile = opt.lockfile;
  132. this.lock = opt.lock;
  133. this.workInterval = opt.workInterval;
  134. this.bot = opt.bot;
  135. this.webshotDelay = opt.webshotDelay;
  136. }
  137. }
  138. exports.default = default_1;