|
@@ -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) {
|