Browse Source

update via view if an unseen id is supplied

Mike L 3 years ago
parent
commit
a950f8f6fe
4 changed files with 93 additions and 61 deletions
  1. 1 1
      dist/koishi.js
  2. 46 30
      dist/twitter.js
  3. 1 1
      src/koishi.ts
  4. 45 29
      src/twitter.ts

+ 1 - 1
dist/koishi.js

@@ -199,7 +199,7 @@ class default_1 {
 /instagram - 查询当前聊天中的 Instagram 动态订阅
 /instagram_sub[scribe]〈链接|用户名〉- 订阅 Instagram 媒体搬运
 /instagram_unsub[scribe]〈链接|用户名〉- 退订 Instagram 媒体搬运
-/instagram_view〈链接|用户名〉- 查看媒体\
+/instagram_view〈链接|用户名〉- 查看媒体并按需手动更新\
 ${chat.chatType === "temp" ?
                                 '\n(当前游客模式下无法使用订阅功能,请先添加本账号为好友。)' : ''}`);
                         }

+ 46 - 30
dist/twitter.js

@@ -283,7 +283,6 @@ class default_1 {
                 return mediaItem;
             }),
         });
-        this.getMedia = (segmentId, sender) => this.workOnMedia([this.lazyGetMediaById(urlSegmentToId(segmentId))], sender);
         this.sendMedia = (source, ...to) => (msg, text, author) => {
             to.forEach(subscriber => {
                 logger.info(`pushing data${source ? ` of ${source}` : ''} to ${JSON.stringify(subscriber)}`);
@@ -298,6 +297,35 @@ class default_1 {
                 });
             });
         };
+        this.workOnFeed = (feed) => new Promise(resolve => {
+            const match = /https:\/\/www\.instagram\.com\/([^\/]+)/.exec(feed);
+            if (!match) {
+                logger.error(`current feed "${feed}" is invalid, please remove this feed manually`);
+                return resolve([]);
+            }
+            return resolve(this.queryUserMedia(match[1], this.lock.threads[feed].offset)
+                .catch((error) => {
+                logger.error(`error scraping media off profile page of ${match[1]}, error: ${error}`);
+                return [];
+            }));
+        }).then(mediaItems => {
+            const currentThread = this.lock.threads[feed];
+            const updateDate = () => currentThread.updatedAt = new Date().toString();
+            if (!mediaItems || mediaItems.length === 0) {
+                updateDate();
+                return;
+            }
+            const topOfFeed = mediaItems[0].pk;
+            const updateOffset = () => { currentThread.offset = topOfFeed; };
+            if (currentThread.offset === '-1') {
+                updateOffset();
+                return;
+            }
+            if (currentThread.offset === '0')
+                mediaItems.splice(1);
+            return this.workOnMedia(mediaItems, this.sendMedia(`thread ${feed}`, ...currentThread.subscribers))
+                .then(updateDate).then(updateOffset);
+        });
         this.work = () => {
             const lock = this.lock;
             if (this.workInterval < 1)
@@ -318,6 +346,8 @@ class default_1 {
             });
             const queuedFeeds = lock.feed.slice(0, lock.workon + 1).reverse();
             utils_1.chainPromises(utils_1.Arr.chunk(queuedFeeds, 5).map((arr, i) => () => Promise.all(arr.map((currentFeed, j) => {
+                if (Date.now() - new Date(lock.threads[currentFeed].updatedAt).getTime() > 3600000)
+                    return;
                 const workon = (queuedFeeds.length - 1) - (i * 5 + j);
                 fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
                 const promiseDelay = this.workInterval * (Math.random() + j) * 500 / lock.feed.length;
@@ -327,33 +357,7 @@ class default_1 {
                     logger.info(`about to pull from feed #${workon}: ${currentFeed}`);
                     if (j === arr.length - 1)
                         logger.info(`timeout for this batch job: ${Math.trunc(promiseDelay * 2)} ms`);
-                    const match = /https:\/\/www\.instagram\.com\/([^\/]+)/.exec(currentFeed);
-                    if (!match) {
-                        logger.error(`current feed "${currentFeed}" is invalid, please remove this feed manually`);
-                        return [];
-                    }
-                    return this.queryUserMedia(match[1], this.lock.threads[currentFeed].offset)
-                        .catch((error) => {
-                        logger.error(`error scraping media off profile page of ${match[1]}, error: ${error}`);
-                        return [];
-                    });
-                }).then((mediaItems) => {
-                    const currentThread = lock.threads[currentFeed];
-                    const updateDate = () => currentThread.updatedAt = new Date().toString();
-                    if (!mediaItems || mediaItems.length === 0) {
-                        updateDate();
-                        return;
-                    }
-                    const topOfFeed = mediaItems[0].pk;
-                    const updateOffset = () => currentThread.offset = topOfFeed;
-                    if (currentThread.offset === '-1') {
-                        updateOffset();
-                        return;
-                    }
-                    if (currentThread.offset === '0')
-                        mediaItems.splice(1);
-                    return this.workOnMedia(mediaItems, this.sendMedia(`thread ${currentFeed}`, ...currentThread.subscribers))
-                        .then(updateDate).then(updateOffset);
+                    return this.workOnFeed(currentFeed);
                 }).then(() => {
                     lock.workon = (workon || lock.feed.length) - 1;
                     if (j === arr.length - 1) {
@@ -459,8 +463,20 @@ class default_1 {
             .then(user => `${user.username}:${user.pk}`)
             .catch((err) => { throw Error(parseMediaError(err)); });
         exports.sendPost = (segmentId, receiver) => {
-            this.getMedia(segmentId, this.sendMedia(`instagram media ${segmentId}`, receiver))
-                .catch((err) => { this.bot.sendTo(receiver, parseMediaError(err)); });
+            const lazyMedia = this.lazyGetMediaById(urlSegmentToId(segmentId));
+            return lazyMedia.item().then(mediaItem => {
+                const lock = this.lock;
+                const feed = linkBuilder({ userName: mediaItem.user.username });
+                if (lock.feed.includes(feed) && lock.threads[feed].offset < mediaItem.pk) {
+                    logger.info(`post is newer than last offset of thread (${instagram_id_to_url_segment_1.instagramIdToUrlSegment(lock.threads[feed].offset)}), updating...`);
+                    this.workOnFeed(feed);
+                    if (lock.threads[feed].subscribers.some(subscriber => subscriber.chatID.toString() === receiver.chatID.toString() &&
+                        subscriber.chatType === receiver.chatType))
+                        return logger.info(`receiver has already subscribed to feed ${feed}, not sending again`);
+                }
+                lazyMedia.item = () => Promise.resolve(mediaItem);
+                this.workOnMedia([lazyMedia], this.sendMedia(`instagram media ${segmentId}`, receiver));
+            }).catch((err) => { this.bot.sendTo(receiver, parseMediaError(err)); });
         };
     }
     get isInactiveTime() {

+ 1 - 1
src/koishi.ts

@@ -218,7 +218,7 @@ export default class {
 /instagram - 查询当前聊天中的 Instagram 动态订阅
 /instagram_sub[scribe]〈链接|用户名〉- 订阅 Instagram 媒体搬运
 /instagram_unsub[scribe]〈链接|用户名〉- 退订 Instagram 媒体搬运
-/instagram_view〈链接|用户名〉- 查看媒体\
+/instagram_view〈链接|用户名〉- 查看媒体并按需手动更新\
 ${chat.chatType === ChatType.Temp ?
     '\n(当前游客模式下无法使用订阅功能,请先添加本账号为好友。)' : ''
 }`);

+ 45 - 29
src/twitter.ts

@@ -336,8 +336,21 @@ export default class {
         .then(user => `${user.username}:${user.pk}`)
         .catch((err: IgClientError) => { throw Error(parseMediaError(err)); });
     sendPost = (segmentId, receiver) => {
-      this.getMedia(segmentId, this.sendMedia(`instagram media ${segmentId}`, receiver))
-        .catch((err: IgClientError) => { this.bot.sendTo(receiver, parseMediaError(err)); });
+      const lazyMedia = this.lazyGetMediaById(urlSegmentToId(segmentId));
+      return lazyMedia.item().then(mediaItem => {
+        const lock = this.lock;
+        const feed = linkBuilder({userName: mediaItem.user.username});
+        if (lock.feed.includes(feed) && lock.threads[feed].offset < mediaItem.pk) {
+          logger.info(`post is newer than last offset of thread (${idToUrlSegment(lock.threads[feed].offset)}), updating...`);
+          this.workOnFeed(feed);
+          if (lock.threads[feed].subscribers.some(subscriber =>
+            subscriber.chatID.toString() === receiver.chatID.toString() &&
+            subscriber.chatType === receiver.chatType
+          )) return logger.info(`receiver has already subscribed to feed ${feed}, not sending again`);
+        }
+        lazyMedia.item = () => Promise.resolve(mediaItem);
+        this.workOnMedia([lazyMedia], this.sendMedia(`instagram media ${segmentId}`, receiver));
+      }).catch((err: IgClientError) => { this.bot.sendTo(receiver, parseMediaError(err)); });
     };
   }
 
@@ -449,9 +462,6 @@ export default class {
     }),
   });
 
-  private getMedia = (segmentId: string, sender: (msg: string, text: string, author: string) => void) =>
-    this.workOnMedia([this.lazyGetMediaById(urlSegmentToId(segmentId))], sender);
-
   private sendMedia = (source?: string, ...to: IChat[]) => (msg: string, text: string, author: string) => {
     to.forEach(subscriber => {
       logger.info(`pushing data${source ? ` of ${source}` : ''} to ${JSON.stringify(subscriber)}`);
@@ -477,6 +487,33 @@ export default class {
       .some(range => (now => now >= range.start && now < range.end)(Date.now()));
   }
 
+  public workOnFeed = (feed: string) => new Promise<LazyMediaItem[]>(resolve => {
+    const match = /https:\/\/www\.instagram\.com\/([^\/]+)/.exec(feed);
+    if (!match) {
+      logger.error(`current feed "${feed}" is invalid, please remove this feed manually`);
+      return resolve([]);
+    }
+    return resolve(this.queryUserMedia(match[1], this.lock.threads[feed].offset)
+      .catch((error: Error) => {
+        logger.error(`error scraping media off profile page of ${match[1]}, error: ${error}`);
+        return [];
+      }));
+  }).then<void>(mediaItems => {
+    const currentThread = this.lock.threads[feed];
+
+    const updateDate = () => currentThread.updatedAt = new Date().toString();
+    if (!mediaItems || mediaItems.length === 0) { updateDate(); return; }
+
+    const topOfFeed = mediaItems[0].pk;
+    const updateOffset = () => { currentThread.offset = topOfFeed; };
+
+    if (currentThread.offset === '-1') { updateOffset(); return; }
+    if (currentThread.offset === '0') mediaItems.splice(1);
+
+    return this.workOnMedia(mediaItems, this.sendMedia(`thread ${feed}`, ...currentThread.subscribers))
+      .then(updateDate).then(updateOffset);
+  });
+
   public work = () => {
     const lock = this.lock;
     if (this.workInterval < 1) this.workInterval = 1;
@@ -498,6 +535,8 @@ export default class {
     const queuedFeeds = lock.feed.slice(0, lock.workon + 1).reverse();
     chainPromises(Arr.chunk(queuedFeeds, 5).map((arr, i) =>
       () => Promise.all(arr.map((currentFeed, j) => {
+        if (Date.now() - new Date(lock.threads[currentFeed].updatedAt).getTime() < 3600000) return;
+
         const workon = (queuedFeeds.length - 1) - (i * 5 + j);
         fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
         const promiseDelay = this.workInterval * (Math.random() + j) * 500 / lock.feed.length;
@@ -507,30 +546,7 @@ export default class {
         const promise = promisify(setTimeout)(promiseDelay).then(() => {
           logger.info(`about to pull from feed #${workon}: ${currentFeed}`);
           if (j === arr.length - 1) logger.info(`timeout for this batch job: ${Math.trunc(promiseDelay * 2)} ms`);
-          const match = /https:\/\/www\.instagram\.com\/([^\/]+)/.exec(currentFeed);
-          if (!match) {
-            logger.error(`current feed "${currentFeed}" is invalid, please remove this feed manually`);
-            return [] as LazyMediaItem[];
-          }
-          return this.queryUserMedia(match[1], this.lock.threads[currentFeed].offset)
-            .catch((error: Error) => {
-              logger.error(`error scraping media off profile page of ${match[1]}, error: ${error}`);
-              return [] as LazyMediaItem[];
-            });
-        }).then((mediaItems: LazyMediaItem[]) => {
-          const currentThread = lock.threads[currentFeed];
-
-          const updateDate = () => currentThread.updatedAt = new Date().toString();
-          if (!mediaItems || mediaItems.length === 0) { updateDate(); return; }
-
-          const topOfFeed = mediaItems[0].pk;
-          const updateOffset = () => currentThread.offset = topOfFeed;
-
-          if (currentThread.offset === '-1') { updateOffset(); return; }
-          if (currentThread.offset === '0') mediaItems.splice(1);
-
-          return this.workOnMedia(mediaItems, this.sendMedia(`thread ${currentFeed}`, ...currentThread.subscribers))
-            .then(updateDate).then(updateOffset);
+          return this.workOnFeed(currentFeed);
         }).then(() => {
           lock.workon = (workon || lock.feed.length) - 1;
           if (j === arr.length - 1) {