Преглед на файлове

improve concurrent working further

Mike L преди 3 години
родител
ревизия
245364cf18
променени са 2 файла, в които са добавени 93 реда и са изтрити 113 реда
  1. 44 54
      dist/webshot.js
  2. 49 59
      src/webshot.ts

+ 44 - 54
dist/webshot.js

@@ -49,12 +49,6 @@ class Webshot extends CallableInstance {
             return (0, util_1.promisify)(setTimeout)(2500)
                 .then(() => this.connect(onready));
         };
-        this.extendEntity = (media) => {
-            logger.info('not working on a tweet');
-        };
-        this.truncateLongThread = (atId) => {
-            logger.info('not working on a tweet');
-        };
         this.renderWebshot = (url, height, webshotDelay, ...morePostProcessings) => {
             temp.track();
             const jpeg = (data) => data.pipe(sharp()).jpeg({ quality: 90, trellisQuantisation: true });
@@ -130,52 +124,11 @@ class Webshot extends CallableInstance {
                             });
                         }).then(() => null);
                     })
-                        .then((handle) => {
+                        .then(handle => {
                         if (handle === null)
                             throw new puppeteer.errors.TimeoutError();
-                        return handle.evaluate(div => {
-                            try {
-                                const selector = '[data-testid="tweet"] :nth-child(2)>:first-child a';
-                                const getProfileUrl = () => (div.querySelector(selector) || { href: '' }).href;
-                                const ownerProfileUrl = getProfileUrl();
-                                const bottom = div;
-                                while (div = div.previousElementSibling) {
-                                    if (getProfileUrl() !== ownerProfileUrl || div === bottom.previousElementSibling)
-                                        continue;
-                                    const top = document.documentElement.scrollTop = window.scrollY + div.getBoundingClientRect().top;
-                                    if (top > 10)
-                                        return div.querySelector('article a[aria-label]').href.replace(/.*\/status\//, '');
-                                }
-                            }
-                            catch (_a) { }
-                            document.documentElement.scrollTop = 0;
-                        }).then(this.truncateLongThread).then(() => handle);
-                    })
-                        .then(handle => handle.evaluate(div => {
-                        const cardImg = div.querySelector('div[data-testid^="card.layout"][data-testid$=".media"] img');
-                        if (typeof (cardImg === null || cardImg === void 0 ? void 0 : cardImg.getAttribute('src')) === 'string') {
-                            const match = /^(.*\/card_img\/(\d+)\/.+\?format=.*)&name=/.exec(cardImg === null || cardImg === void 0 ? void 0 : cardImg.getAttribute('src'));
-                            if (match) {
-                                const [media_url_https, id_str] = match.slice(1);
-                                return {
-                                    media_url: media_url_https.replace(/^https/, 'http'),
-                                    media_url_https,
-                                    url: '',
-                                    display_url: '',
-                                    expanded_url: '',
-                                    type: 'photo',
-                                    id: Number(id_str),
-                                    id_str,
-                                    sizes: undefined,
-                                };
-                            }
-                        }
-                    }))
-                        .then(cardImg => {
-                        if (cardImg)
-                            this.extendEntity(cardImg);
+                        return (0, utils_1.chainPromises)(morePostProcessings.map(func => () => func(page, handle)));
                     })
-                        .then(() => (0, utils_1.chainPromises)(morePostProcessings.map(func => () => func(page))))
                         .then(() => (0, util_1.promisify)(setTimeout)(getTimeout()))
                         .then(() => page.evaluate(() => document.activeElement.blur()))
                         .then(() => page.screenshot())
@@ -308,22 +261,59 @@ class Webshot extends CallableInstance {
             });
             if (this.mode === 0) {
                 const url = `https://mobile.twitter.com/${twi.user.screen_name}/status/${twi.id_str}`;
-                promise = promise.then(() => {
-                    this.extendEntity = (cardImg) => {
+                promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay, (_, handle) => {
+                    const extendEntity = (cardImg) => {
                         var _a, _b;
                         originTwi.extended_entities = Object.assign(Object.assign({}, originTwi.extended_entities), { media: [
                                 ...(_b = (_a = originTwi.extended_entities) === null || _a === void 0 ? void 0 : _a.media) !== null && _b !== void 0 ? _b : [],
                                 cardImg,
                             ] });
                     };
-                    this.truncateLongThread = (atId) => {
+                    const truncateLongThread = (atId) => {
                         if (!atId)
                             return;
                         logger.info(`thread too long, truncating at tweet ${atId}...`);
                         truncatedAt = atId;
                     };
-                    return this.renderWebshot(url, 1920, webshotDelay);
-                })
+                    return handle.evaluate(div => {
+                        try {
+                            const selector = '[data-testid="tweet"] :nth-child(2)>:first-child a';
+                            const getProfileUrl = () => (div.querySelector(selector) || { href: '' }).href;
+                            const ownerProfileUrl = getProfileUrl();
+                            const bottom = div;
+                            while (div = div.previousElementSibling) {
+                                if (getProfileUrl() !== ownerProfileUrl || div === bottom.previousElementSibling)
+                                    continue;
+                                const top = document.documentElement.scrollTop = window.scrollY + div.getBoundingClientRect().top;
+                                if (top > 10)
+                                    return div.querySelector('article a[aria-label]').href.replace(/.*\/status\//, '');
+                            }
+                        }
+                        catch (_a) { }
+                        document.documentElement.scrollTop = 0;
+                    }).then(truncateLongThread)
+                        .then(() => handle.evaluate(div => {
+                        const cardImg = div.querySelector('div[data-testid^="card.layout"][data-testid$=".media"] img');
+                        if (typeof (cardImg === null || cardImg === void 0 ? void 0 : cardImg.getAttribute('src')) === 'string') {
+                            const match = /^(.*\/card_img\/(\d+)\/.+\?format=.*)&name=/.exec(cardImg === null || cardImg === void 0 ? void 0 : cardImg.getAttribute('src'));
+                            if (match) {
+                                const [media_url_https, id_str] = match.slice(1);
+                                return {
+                                    media_url: media_url_https.replace(/^https/, 'http'),
+                                    media_url_https,
+                                    url: '',
+                                    display_url: '',
+                                    expanded_url: '',
+                                    type: 'photo',
+                                    id: Number(id_str),
+                                    id_str,
+                                    sizes: undefined,
+                                };
+                            }
+                        }
+                    })).then(cardImg => { if (cardImg)
+                        extendEntity(cardImg); });
+                }))
                     .then(fileurl => {
                     if (fileurl)
                         return koishi_1.Message.Image(fileurl);

+ 49 - 59
src/webshot.ts

@@ -70,17 +70,9 @@ class Webshot extends CallableInstance<[Tweet[], (...args) => void, number], Pro
       .then(() => this.connect(onready));
   };
 
-  private extendEntity = (media: MediaEntity) => {
-    logger.info('not working on a tweet');
-  };
-
-  private truncateLongThread = (atId: string) => {
-    logger.info('not working on a tweet');
-  };
-
   private renderWebshot = (
     url: string, height: number, webshotDelay: number,
-    ...morePostProcessings: ((page: puppeteer.Page) => Promise<any>)[]
+    ...morePostProcessings: ((page?: puppeteer.Page, handle?: puppeteer.ElementHandle) => Promise<any>)[]
   ): Promise<string> => {
     temp.track();
     const jpeg = (data: Readable) => data.pipe(sharp()).jpeg({quality: 90, trellisQuantisation: true});
@@ -155,7 +147,7 @@ class Webshot extends CallableInstance<[Tweet[], (...args) => void, number], Pro
               throw err;
               logger.warn(`${err} (${getTimerTime()} ms)`);
               return page.evaluate(() => document.documentElement.outerHTML).then(html => {
-                const path = temp.path({ suffix: '.html' });
+                const path = temp.path({suffix: '.html'});
                 writeFileSync(path, html);
                 logger.warn(`saved debug html to ${path}`);
               }).then(() => page.screenshot()).then(screenshot => {
@@ -164,52 +156,10 @@ class Webshot extends CallableInstance<[Tweet[], (...args) => void, number], Pro
                 });
               }).then(() => null);
             })
-            // scroll back at least 2 tweets revealing 2nd last tweet by owner in thread, or top of thread, if any
-            .then((handle: puppeteer.ElementHandle<HTMLDivElement>) => {
+            .then(handle => {
               if (handle === null) throw new puppeteer.errors.TimeoutError();
-              return handle.evaluate(div => {
-                try {
-                  const selector = '[data-testid="tweet"] :nth-child(2)>:first-child a';
-                  const getProfileUrl = () => (div.querySelector<HTMLAnchorElement>(selector) || {href: ''}).href;
-                  const ownerProfileUrl = getProfileUrl();
-                  const bottom = div;
-                  // eslint-disable-next-line no-cond-assign
-                  while (div = div.previousElementSibling as HTMLDivElement) {
-                    if (getProfileUrl() !== ownerProfileUrl || div === bottom.previousElementSibling) continue;
-                    const top = document.documentElement.scrollTop = window.scrollY + div.getBoundingClientRect().top;
-                    if (top > 10)
-                      return div.querySelector<HTMLAnchorElement>('article a[aria-label]').href.replace(/.*\/status\//, '');
-                  }
-                } catch {/* handle errors like none-found cases */}
-                document.documentElement.scrollTop = 0;
-              }).then(this.truncateLongThread).then(() => handle);
-            })
-            // scrape card image from main tweet
-            .then(handle => handle.evaluate(div => {
-              const cardImg = div.querySelector('div[data-testid^="card.layout"][data-testid$=".media"] img');
-              if (typeof cardImg?.getAttribute('src') === 'string') {
-                const match = /^(.*\/card_img\/(\d+)\/.+\?format=.*)&name=/.exec(cardImg?.getAttribute('src'));
-                if (match) {
-                  // tslint:disable-next-line: variable-name
-                  const [media_url_https, id_str] = match.slice(1);
-                  return {
-                    media_url: media_url_https.replace(/^https/, 'http'),
-                    media_url_https,
-                    url: '',
-                    display_url: '',
-                    expanded_url: '',
-                    type: 'photo',
-                    id: Number(id_str),
-                    id_str,
-                    sizes: undefined,
-                  };
-                }
-              }
-            }))
-            .then(cardImg => {
-              if (cardImg) this.extendEntity(cardImg); 
+              return chainPromises(morePostProcessings.map(func => () => func(page, handle)));
             })
-            .then(() => chainPromises(morePostProcessings.map(func => () => func(page))))
             .then(() => promisify(setTimeout)(getTimeout()))
             // hide highlight of retweet header
             .then(() => page.evaluate(() => (document.activeElement as unknown as HTMLOrSVGElement).blur()))
@@ -345,8 +295,10 @@ class Webshot extends CallableInstance<[Tweet[], (...args) => void, number], Pro
       // invoke webshot
       if (this.mode === 0) {
         const url = `https://mobile.twitter.com/${twi.user.screen_name}/status/${twi.id_str}`;
-        promise = promise.then(() => {
-          this.extendEntity = (cardImg: MediaEntity) => {
+        promise = promise.then(() => this.renderWebshot(url, 1920, webshotDelay, (
+          _, handle: puppeteer.ElementHandle<HTMLDivElement>
+        ) => {
+          const extendEntity = (cardImg: MediaEntity) => {
             originTwi.extended_entities = {
               ...originTwi.extended_entities,
               media: [
@@ -355,13 +307,51 @@ class Webshot extends CallableInstance<[Tweet[], (...args) => void, number], Pro
               ],
             };
           };
-          this.truncateLongThread = (atId: string) => {
+          const truncateLongThread = (atId: string) => {
             if (!atId) return;
             logger.info(`thread too long, truncating at tweet ${atId}...`);
             truncatedAt = atId;
           };
-          return this.renderWebshot(url, 1920, webshotDelay);
-        })
+          // scroll back at least 2 tweets revealing 2nd last tweet by owner in thread, or top of thread
+          return handle.evaluate(div => {
+            try {
+              const selector = '[data-testid="tweet"] :nth-child(2)>:first-child a';
+              const getProfileUrl = () => (div.querySelector<HTMLAnchorElement>(selector) || {href: ''}).href;
+              const ownerProfileUrl = getProfileUrl();
+              const bottom = div;
+              // eslint-disable-next-line no-cond-assign
+              while (div = div.previousElementSibling as HTMLDivElement) {
+                if (getProfileUrl() !== ownerProfileUrl || div === bottom.previousElementSibling) continue;
+                const top = document.documentElement.scrollTop = window.scrollY + div.getBoundingClientRect().top;
+                if (top > 10)
+                  return div.querySelector<HTMLAnchorElement>('article a[aria-label]').href.replace(/.*\/status\//, '');
+              }
+            } catch {/* handle errors like none-found cases */}
+            document.documentElement.scrollTop = 0;
+          }).then(truncateLongThread)
+          // scrape card image from main tweet
+          .then(() => handle.evaluate(div => {
+            const cardImg = div.querySelector('div[data-testid^="card.layout"][data-testid$=".media"] img');
+            if (typeof cardImg?.getAttribute('src') === 'string') {
+              const match = /^(.*\/card_img\/(\d+)\/.+\?format=.*)&name=/.exec(cardImg?.getAttribute('src'));
+              if (match) {
+                // tslint:disable-next-line: variable-name
+                const [media_url_https, id_str] = match.slice(1);
+                return {
+                  media_url: media_url_https.replace(/^https/, 'http'),
+                  media_url_https,
+                  url: '',
+                  display_url: '',
+                  expanded_url: '',
+                  type: 'photo',
+                  id: Number(id_str),
+                  id_str,
+                  sizes: undefined,
+                };
+              }
+            }
+          })).then(cardImg => { if (cardImg) extendEntity(cardImg); });
+        }))
           .then(fileurl => {
             if (fileurl) return Message.Image(fileurl);
             return '[截图不可用] ' + author + text;