Przeglądaj źródła

proper promise chaining, cust. webshot processing

Mike L 3 lat temu
rodzic
commit
e8ff6b440e
6 zmienionych plików z 37 dodań i 21 usunięć
  1. 1 2
      dist/koishi.js
  2. 1 1
      dist/utils.js
  3. 11 6
      dist/webshot.js
  4. 1 2
      src/koishi.ts
  5. 3 3
      src/utils.ts
  6. 20 7
      src/webshot.ts

+ 1 - 2
dist/koishi.js

@@ -14,7 +14,6 @@ const koishi_1 = require("koishi");
 require("koishi-adapter-onebot");
 const command_1 = require("./command");
 const loggers_1 = require("./loggers");
-const utils_1 = require("./utils");
 const logger = loggers_1.getLogger('qqbot');
 const cqUrlFix = (factory) => (...args) => factory(...args).replace(/(?<=\[CQ:.*)url=(?=(base64|file|https?):\/\/)/, 'file=');
 exports.Message = {
@@ -87,7 +86,7 @@ class default_1 {
         this.sendToUser = (userID, message) => new Promise(resolve => {
             this.enqueue('private', userID, () => this.bot.sendPrivateMessage(userID, message).then(resolve));
         });
-        this.sendTo = (subscriber, messageChain) => utils_1.chainPromises((splitted => [splitted.message, ...splitted.attachments])(exports.Message.separateAttachment(messageChain)).map(msg => {
+        this.sendTo = (subscriber, messageChain) => Promise.all((splitted => [splitted.message, ...splitted.attachments])(exports.Message.separateAttachment(messageChain)).map(msg => {
             switch (subscriber.chatType) {
                 case 'group':
                     return this.sendToGroup(subscriber.chatID.toString(), msg);

+ 1 - 1
dist/utils.js

@@ -1,7 +1,7 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.BigNumOps = exports.chainPromises = void 0;
-const chainPromises = (promises, reducer = (p1, p2) => p1.then(() => p2), initialValue) => promises.reduce(reducer, Promise.resolve(initialValue));
+const chainPromises = (lazyPromises, reducer = (lp1, lp2) => (p) => lp1(p).then(lp2), initialValue) => lazyPromises.reduce(reducer, p => Promise.resolve(p))(initialValue);
 exports.chainPromises = chainPromises;
 const splitBigNumAt = (num, at) => num.replace(RegExp(String.raw `^([+-]?)(\d+)(\d{${at}})$`), '$1$2,$1$3')
     .replace(/^([^,]*)$/, '0,$1').split(',')

+ 11 - 6
dist/webshot.js

@@ -63,7 +63,7 @@ class Webshot extends CallableInstance {
             }
             throw error;
         });
-        this.renderWebshot = (url, height, webshotDelay) => {
+        this.renderWebshot = (url, height, webshotDelay, ...morePostProcessings) => {
             temp.track();
             const jpeg = (data) => data.pipe(sharp()).jpeg({ quality: 90, trellisQuantisation: true });
             const sharpToFile = (pic) => new Promise(resolve => {
@@ -114,6 +114,7 @@ class Webshot extends CallableInstance {
                             time.parentElement.parentElement.style.margin = '-24px 0 12px';
                         }
                     }))
+                        .then(() => utils_1.chainPromises(morePostProcessings.map(func => () => func(page))))
                         .then(() => page.screenshot())
                         .then(screenshot => {
                         new pngjs_1.PNG({
@@ -162,12 +163,13 @@ class Webshot extends CallableInstance {
                     .catch(reject);
             });
             return promise.then(data => {
-                if (data.boundary === null)
-                    return this.renderWebshot(url, height + 1920, webshotDelay);
+                if (data.boundary === null) {
+                    return this.renderWebshot(url, height + 1920, webshotDelay, ...morePostProcessings);
+                }
                 else
                     return data.path;
             }).catch(error => this.reconnect(error)
-                .then(() => this.renderWebshot(url, height, webshotDelay)));
+                .then(() => this.renderWebshot(url, height, webshotDelay, ...morePostProcessings)));
         };
         this.fetchMedia = (url) => new Promise((resolve, reject) => {
             logger.info(`fetching ${url}`);
@@ -227,7 +229,10 @@ class Webshot extends CallableInstance {
                 messageChain += (author + xmlEntities.decode(text));
             if (this.mode === 0) {
                 const url = twitter_1.linkBuilder({ postUrlSegment: item.code });
-                promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay))
+                promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay, page => page.addStyleTag({ content: 'header div div div *{text-align:left!important} header div div div a::after{' +
+                        `content:"${item.user.full_name}";` +
+                        'display:block; font-size:smaller; color: #8e8e8e; line-height:1.25}',
+                })))
                     .then(fileurl => {
                     if (fileurl)
                         return koishi_1.Message.Image(fileurl);
@@ -254,7 +259,7 @@ class Webshot extends CallableInstance {
             if (1 - this.mode % 2)
                 promise = promise.then(() => {
                     if (item.carousel_media) {
-                        return utils_1.chainPromises(item.carousel_media.map(carouselItem => fetchBestCandidate(carouselItem.video_versions ||
+                        return utils_1.chainPromises(item.carousel_media.map(carouselItem => () => fetchBestCandidate(carouselItem.video_versions ||
                             carouselItem.image_versions2.candidates, type(carouselItem))));
                     }
                     else if (item.video_versions) {

+ 1 - 2
src/koishi.ts

@@ -3,7 +3,6 @@ import 'koishi-adapter-onebot';
 
 import { parseCmd, view } from './command';
 import { getLogger } from './loggers';
-import { chainPromises } from './utils';
 
 const logger = getLogger('qqbot');
 
@@ -98,7 +97,7 @@ export default class {
     this.enqueue('private', userID, () => this.bot.sendPrivateMessage(userID, message).then(resolve));
   });
 
-  public sendTo = (subscriber: IChat, messageChain: string) => chainPromises(
+  public sendTo = (subscriber: IChat, messageChain: string) => Promise.all(
     (splitted => [splitted.message, ...splitted.attachments])(
       Message.separateAttachment(messageChain)
     ).map(msg => {

+ 3 - 3
src/utils.ts

@@ -1,8 +1,8 @@
 export const chainPromises = <T>(
-  promises: Promise<T>[],
-  reducer = (p1: Promise<T>, p2: Promise<T>) => p1.then(() => p2),
+  lazyPromises: ((p: T) => Promise<T>)[],
+  reducer = (lp1: (p: T) => Promise<T>, lp2: (p: T) => Promise<T>) => (p: T) => lp1(p).then(lp2),
   initialValue?: T
-) => promises.reduce(reducer, Promise.resolve(initialValue));
+) => lazyPromises.reduce(reducer, p => Promise.resolve(p))(initialValue);
 
 const splitBigNumAt = (num: string, at: number) => num.replace(RegExp(String.raw`^([+-]?)(\d+)(\d{${at}})$`), '$1$2,$1$3')
   .replace(/^([^,]*)$/, '0,$1').split(',')

+ 20 - 7
src/webshot.ts

@@ -94,7 +94,10 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
         throw error;
       });
 
-  private renderWebshot = (url: string, height: number, webshotDelay: number): Promise<string> => {
+  private renderWebshot = (
+    url: string, height: number, webshotDelay: number,
+    ...morePostProcessings: ((page: Page) => Promise<any>)[]
+  ): Promise<string> => {
     temp.track();
     const jpeg = (data: Readable) => data.pipe(sharp()).jpeg({quality: 90, trellisQuantisation: true});
     const sharpToFile = (pic: sharp.Sharp) => new Promise<string>(resolve => {
@@ -129,7 +132,7 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
               logger.warn(`navigation timed out at ${getTimerTime()} ms`);
               return null;
             })
-            // hide header, "more options" button, like and retweet count
+            // hide header, footer, "more options" button, like and share count, carousel navigator, and comments
             .then(() => page.addStyleTag({content:
               'nav,footer,header+div,header+div+div>div>div+div,header div div div+div,' +
               'article section,article section+div>ul>:not(div),article button,canvas{display:none!important} ' +
@@ -138,6 +141,7 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
             .then(() => page.addStyleTag({
               content: '*{font-family:-apple-system,".Helvetica Neue DeskInterface",Hiragino Sans,Hiragino Sans GB,sans-serif!important}',
             }))
+            // display absolute date and time
             .then(() => page.evaluate(() => {
               let time: HTMLTimeElement;
               time = document.querySelector('div>div>time');
@@ -148,6 +152,7 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
                 time.parentElement.parentElement.style.margin = '-24px 0 12px';
               }
             }))
+            .then(() => chainPromises(morePostProcessings.map(func => () => func(page))))
             .then(() => page.screenshot())
             .then(screenshot => {
               new PNG({
@@ -197,10 +202,11 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
         .catch(reject);
     });
     return promise.then(data => {
-      if (data.boundary === null) return this.renderWebshot(url, height + 1920, webshotDelay);
-      else return data.path;
+      if (data.boundary === null) {
+        return this.renderWebshot(url, height + 1920, webshotDelay, ...morePostProcessings);
+      } else return data.path;
     }).catch(error => this.reconnect(error)
-      .then(() => this.renderWebshot(url, height, webshotDelay))
+      .then(() => this.renderWebshot(url, height, webshotDelay, ...morePostProcessings))
     );
   };
 
@@ -262,7 +268,14 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
       // invoke webshot
       if (this.mode === 0) {
         const url = linkBuilder({postUrlSegment: item.code});
-        promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay))
+        promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay, page =>
+          // display full name
+          page.addStyleTag({content:
+            'header div div div *{text-align:left!important} header div div div a::after{' +
+            `content:"${item.user.full_name}";` +
+            'display:block; font-size:smaller; color: #8e8e8e; line-height:1.25}',
+          })
+        ))
           .then(fileurl => {
             if (fileurl) return Message.Image(fileurl);
             return author + text;
@@ -294,7 +307,7 @@ class Webshot extends CallableInstance<[LazyMediaItem[], (...args) => void, numb
       if (1 - this.mode % 2) promise = promise.then(() => {
         if (item.carousel_media) {
           return chainPromises(item.carousel_media.map(carouselItem =>
-            fetchBestCandidate(
+            () => fetchBestCandidate(
               (carouselItem as unknown as MediaItem).video_versions || 
               carouselItem.image_versions2.candidates,
               type(carouselItem)