Sfoglia il codice sorgente

:children_crossing: better link support

LI JIAHAO 6 anni fa
parent
commit
70d02c6282
7 ha cambiato i file con 124 aggiunte e 36 eliminazioni
  1. 20 7
      README.md
  2. 44 13
      dist/command.js
  3. 7 1
      dist/twitter.js
  4. 0 1
      dist/webshot.js
  5. 46 12
      src/command.ts
  6. 7 1
      src/twitter.ts
  7. 0 1
      src/webshot.ts

+ 20 - 7
README.md

@@ -17,10 +17,14 @@ npm i -g cqhttp-twitter-bot
 它们是什么?  
 观察它们的文档:[https://cqhttp.cc/](https://cqhttp.cc/) [https://cqp.cc/t/15124](https://cqp.cc/t/15124)
 
+因为需要发图所以必须用 **CQ Pro** 才行。CQ Pro 是收费的,一个月 10 块左右。  
+为什么要发图?  
+因为 twitter 有很多种,转推、回复、带图片的、带视频的。如果直接发文字的话体验很不好,估计也没人会需要吧。
+
 ## 食用
 
 ```bash
-$ cqhttp-twitter-bot config.json
+cqhttp-twitter-bot config.json
 ```
 
 ## 配置
@@ -48,15 +52,20 @@ $ cqhttp-twitter-bot config.json
 Bot 启动了以后就可以在 QQ 里用命令了。命令有:
 
 - /twitter - 列出当前会话的订阅
-- /twitter_subscribe [链接] - 订阅
-- /twitter_unsubscribe [链接] - 退订
+- /twitter_sub [链接] - 订阅
+- /twitter_unsub [链接] - 退订
 
-链接可以是一个个人的时间轴或者是列表, 例如
+链接可以是一个个人的时间轴或者是列表,支持下面几种格式
 
-个人:https://twitter.com/Saito_Shuka  
-列表:https://twitter.com/rikakomoe/lists/lovelive
+个人:
+  + https://twitter.com/Saito_Shuka
+  + https://mobile.twitter.com/Saito_Shuka
+  + Saito_Shuka
 
-必须是这个模式才行 qvq
+列表:
+  + https://twitter.com/rikakomoe/lists/lovelive
+  + https://mobile.twitter.com/rikakomoe/lists/lovelive
+  + rikakomoe/lovelive
 
 ## 其他说明
 
@@ -81,3 +90,7 @@ Bot 启动了以后就可以在 QQ 里用命令了。命令有:
 5. 列表中是没有回复的。实际上你看 Twitter 的列表本来也没有回复。个人的时间轴会显示
 回复。
 
+6. 转推是没有图片的。这个也是 API 的问题。这个人原创的 twitter 的话如果有图片
+会另外拉取一波图片附加在消息里。如果是视频的话则是封面图。
+
+7. 怎么查看翻译?QQ 点开图片,长按 -> 提取图中文字 -> 译

+ 44 - 13
dist/command.js

@@ -6,27 +6,54 @@ const path = require("path");
 const datetime_1 = require("./datetime");
 const logger = log4js.getLogger('command');
 logger.level = global.loglevel;
+function parseLink(link) {
+    let match = link.match(/twitter.com\/([^\/?#]+)\/lists\/([^\/?#]+)/);
+    if (match) {
+        link = `https://twitter.com/${match[1]}/lists/${match[2]}`;
+        return {
+            link,
+            match: [match[1], match[2]],
+        };
+    }
+    match = link.match(/twitter.com\/([^\/?#]+)/);
+    if (match) {
+        link = `https://twitter.com/${match[1]}`;
+        return {
+            link,
+            match: [match[1]],
+        };
+    }
+    match = link.match(/^([^\/?#]+)\/([^\/?#]+)$/);
+    if (match) {
+        link = `https://twitter.com/${match[1]}/lists/${match[2]}`;
+        return {
+            link,
+            match: [match[1], match[2]],
+        };
+    }
+    match = link.match(/^([^\/?#]+)$/);
+    if (match) {
+        link = `https://twitter.com/${match[1]}`;
+        return {
+            link,
+            match: [match[1]],
+        };
+    }
+    return undefined;
+}
 function sub(chat, args, lock, lockfile) {
     if (args.length === 0) {
         return '找不到要订阅的链接。';
     }
-    const link = args[0];
-    let flag = false;
-    let match = link.match(/https:\/\/twitter.com\/([^\/]+)\/lists\/([^\/]+)/);
-    if (match)
-        flag = true;
-    else {
-        match = link.match(/https:\/\/twitter.com\/([^\/]+)/);
-        if (match)
-            flag = true;
-    }
-    if (!flag) {
+    const match = parseLink(args[0]);
+    if (!match) {
         return `订阅链接格式错误:
 示例:
 https://twitter.com/Saito_Shuka
 https://twitter.com/rikakomoe/lists/lovelive`;
     }
-    flag = false;
+    const link = match.link;
+    let flag = false;
     lock.feed.forEach(fl => {
         if (fl === link)
             flag = true;
@@ -56,7 +83,11 @@ function unsub(chat, args, lock, lockfile) {
     if (args.length === 0) {
         return '找不到要退订的链接。';
     }
-    const link = args[0];
+    const match = parseLink(args[0]);
+    if (!match) {
+        return '链接格式有误。';
+    }
+    const link = match.link;
     if (!lock.threads[link]) {
         return '您没有订阅此链接。\n' + list(chat, args, lock);
     }

+ 7 - 1
dist/twitter.js

@@ -43,6 +43,9 @@ class default_1 {
                     if (offset > 0)
                         config.since_id = offset;
                     this.client.get('lists/statuses', config, (error, tweets, response) => {
+                        if (error) {
+                            logger.error(`error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
+                        }
                         resolve(tweets);
                     });
                 }
@@ -57,6 +60,9 @@ class default_1 {
                         if (offset > 0)
                             config.since_id = offset;
                         this.client.get('statuses/user_timeline', config, (error, tweets, response) => {
+                            if (error) {
+                                logger.error(`error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
+                            }
                             resolve(tweets);
                         });
                     }
@@ -64,7 +70,7 @@ class default_1 {
             });
             promise.then((tweets) => {
                 logger.debug(`api returned ${JSON.stringify(tweets)} for feed ${lock.feed[lock.workon]}`);
-                if (tweets.length === 0) {
+                if (tweets && tweets.length === 0) {
                     lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
                     return;
                 }

+ 0 - 1
dist/webshot.js

@@ -103,7 +103,6 @@ function default_1(tweets, callback, webshotDelay) {
                 });
             });
         }
-        // TODO: Translate
         promise.then(() => callback(cqstr));
     });
     return promise;

+ 46 - 12
src/command.ts

@@ -2,30 +2,60 @@ import * as fs from 'fs';
 import * as log4js from 'log4js';
 import * as path from 'path';
 
-import { relativeDate } from './datetime';
+import {relativeDate} from './datetime';
 
 const logger = log4js.getLogger('command');
 logger.level = (global as any).loglevel;
 
+function parseLink(link: string): { link: string, match: string[] } | undefined {
+  let match = link.match(/twitter.com\/([^\/?#]+)\/lists\/([^\/?#]+)/);
+  if (match) {
+    link = `https://twitter.com/${match[1]}/lists/${match[2]}`;
+    return {
+      link,
+      match: [match[1], match[2]],
+    }
+  }
+  match = link.match(/twitter.com\/([^\/?#]+)/);
+  if (match) {
+    link = `https://twitter.com/${match[1]}`;
+    return {
+      link,
+      match: [match[1]],
+    }
+  }
+  match = link.match(/^([^\/?#]+)\/([^\/?#]+)$/);
+  if (match) {
+    link = `https://twitter.com/${match[1]}/lists/${match[2]}`;
+    return {
+      link,
+      match: [match[1], match[2]],
+    }
+  }
+  match = link.match(/^([^\/?#]+)$/);
+  if (match) {
+    link = `https://twitter.com/${match[1]}`;
+    return {
+      link,
+      match: [match[1]],
+    }
+  }
+  return undefined;
+}
+
 function sub(chat: IChat, args: string[], lock: ILock, lockfile: string): string {
   if (args.length === 0) {
     return '找不到要订阅的链接。';
   }
-  const link = args[0];
-  let flag = false;
-  let match = link.match(/https:\/\/twitter.com\/([^\/]+)\/lists\/([^\/]+)/);
-  if (match) flag = true;
-  else {
-    match = link.match(/https:\/\/twitter.com\/([^\/]+)/);
-    if (match) flag = true;
-  }
-  if (!flag) {
+  const match = parseLink(args[0]);
+  if (!match) {
     return `订阅链接格式错误:
 示例:
 https://twitter.com/Saito_Shuka
 https://twitter.com/rikakomoe/lists/lovelive`;
   }
-  flag = false;
+  const link = match.link;
+  let flag = false;
   lock.feed.forEach(fl => {
     if (fl === link) flag = true;
   });
@@ -51,7 +81,11 @@ function unsub(chat: IChat, args: string[], lock: ILock, lockfile: string): stri
   if (args.length === 0) {
     return '找不到要退订的链接。';
   }
-  const link = args[0];
+  const match = parseLink(args[0]);
+  if (!match) {
+    return '链接格式有误。';
+  }
+  const link = match.link;
   if (!lock.threads[link]) {
     return '您没有订阅此链接。\n' + list(chat, args, lock);
   }

+ 7 - 1
src/twitter.ts

@@ -77,6 +77,9 @@ export default class {
         const offset = lock.threads[lock.feed[lock.workon]].offset;
         if (offset > 0) config.since_id = offset;
         this.client.get('lists/statuses', config, (error, tweets, response) => {
+          if (error) {
+            logger.error(`error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
+          }
           resolve(tweets);
         });
       } else {
@@ -89,6 +92,9 @@ export default class {
           const offset = lock.threads[lock.feed[lock.workon]].offset;
           if (offset > 0) config.since_id = offset;
           this.client.get('statuses/user_timeline', config, (error, tweets, response) => {
+            if (error) {
+              logger.error(`error on fetching tweets for ${lock.feed[lock.workon]}: ${JSON.stringify(error)}`);
+            }
             resolve(tweets);
           });
         }
@@ -97,7 +103,7 @@ export default class {
 
     promise.then((tweets: any) => {
       logger.debug(`api returned ${JSON.stringify(tweets)} for feed ${lock.feed[lock.workon]}`);
-      if (tweets.length === 0) {
+      if (tweets && tweets.length === 0) {
         lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
         return;
       }

+ 0 - 1
src/webshot.ts

@@ -98,7 +98,6 @@ export default function (tweets, callback, webshotDelay: number): Promise<void>
           });
       });
     }
-    // TODO: Translate
     promise.then(() => callback(cqstr));
   });
   return promise;