|
@@ -20,6 +20,7 @@ const instagram_private_api_1 = require("instagram-private-api");
|
|
|
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
|
const datetime_1 = require("./datetime");
|
|
|
const loggers_1 = require("./loggers");
|
|
|
+const json = require("./json");
|
|
|
const utils_1 = require("./utils");
|
|
|
const webshot_1 = require("./webshot");
|
|
|
const parseLink = (link) => {
|
|
@@ -42,7 +43,7 @@ const linkBuilder = (config) => {
|
|
|
return `https://www.instagram.com/stories/${config.userName}/${config.storyId}/`;
|
|
|
};
|
|
|
exports.linkBuilder = linkBuilder;
|
|
|
-const igErrorIsAuthError = (error) => / 401/.test(error.message) || error instanceof instagram_private_api_1.IgLoginRequiredError || error instanceof instagram_private_api_1.IgCookieNotFoundError;
|
|
|
+const igErrorIsAuthError = (error) => / 40[1-3]/.test(error.message) || error instanceof instagram_private_api_1.IgLoginRequiredError || error instanceof instagram_private_api_1.IgCookieNotFoundError;
|
|
|
class SessionManager {
|
|
|
constructor(client, file, credentials, codeServicePort) {
|
|
|
this.init = () => {
|
|
@@ -92,6 +93,7 @@ class SessionManager {
|
|
|
server.listen(this.codeServicePort);
|
|
|
});
|
|
|
this.login = () => this.ig.simulate.preLoginFlow()
|
|
|
+ .catch((err) => logger.error(err))
|
|
|
.then(() => this.ig.account.login(this.username, this.password))
|
|
|
.catch((err) => {
|
|
|
if (err instanceof instagram_private_api_1.IgLoginTwoFactorRequiredError) {
|
|
@@ -105,7 +107,7 @@ class SessionManager {
|
|
|
verificationMethod: totp_two_factor_on ? '0' : '1',
|
|
|
}));
|
|
|
}
|
|
|
- throw err;
|
|
|
+ logger.error(err);
|
|
|
})
|
|
|
.then(user => {
|
|
|
logger.info(`successfully logged in as ${this.username}`);
|
|
@@ -192,14 +194,18 @@ class default_1 {
|
|
|
}
|
|
|
}
|
|
|
const userIdCache = this.pullOrders;
|
|
|
- if (Object.values(userIdCache).length !== userIdCache.length) {
|
|
|
- this.pullOrders = utils_1.Arr.shuffle(userIdCache);
|
|
|
- fs.writeFileSync(path.resolve(this.cachefile), JSON.stringify(this.cache));
|
|
|
- }
|
|
|
- const timeout = Math.max(1000, this.workInterval * 1000 / this.lock.feed.length);
|
|
|
- setInterval(() => { this.pullOrders = utils_1.Arr.shuffle(this.pullOrders); }, 21600000);
|
|
|
- setTimeout(this.workForAll, timeout);
|
|
|
- this.work();
|
|
|
+ return (() => {
|
|
|
+ if (Object.values(userIdCache).length !== userIdCache.length) {
|
|
|
+ this.pullOrders = utils_1.Arr.shuffle(userIdCache);
|
|
|
+ return json.writeFile(path.resolve(this.cachefile), this.cache);
|
|
|
+ }
|
|
|
+ return Promise.resolve(true);
|
|
|
+ })().then(() => {
|
|
|
+ const timeout = Math.max(1000, this.workInterval * 1000 / this.lock.feed.length);
|
|
|
+ setInterval(() => { this.pullOrders = utils_1.Arr.shuffle(this.pullOrders); }, 21600000);
|
|
|
+ setTimeout(this.workForAll, timeout);
|
|
|
+ this.work();
|
|
|
+ });
|
|
|
});
|
|
|
};
|
|
|
this.queryUserObject = (userName) => this.client.user.searchExact(userName)
|
|
@@ -220,9 +226,11 @@ class default_1 {
|
|
|
return this.queryUserObject(username)
|
|
|
.then(({ pk, username, full_name }) => {
|
|
|
this.cache[pk] = { user: { pk, username, full_name }, stories: {}, pullOrder: 0 };
|
|
|
- fs.writeFileSync(path.resolve(this.cachefile), JSON.stringify(this.cache));
|
|
|
- logger.info(`initialized cache item for user ${full_name} (@${username})`);
|
|
|
- return `${username}:${pk}`;
|
|
|
+ return json.writeFile(path.resolve(this.cachefile), this.cache).then(res => {
|
|
|
+ if (res)
|
|
|
+ logger.info(`initialized cache item for user ${full_name} (@${username})`);
|
|
|
+ return `${username}:${pk}`;
|
|
|
+ });
|
|
|
});
|
|
|
};
|
|
|
this.workOnMedia = (mediaItems, sendMedia) => (0, utils_1.chainPromises)(mediaItems.map(({ msgs, text, author, original }) => {
|
|
@@ -255,7 +263,6 @@ class default_1 {
|
|
|
setTimeout(this.workForAll, timeout);
|
|
|
return;
|
|
|
}
|
|
|
- logger.debug(`current cache: ${JSON.stringify(this.cache)}`);
|
|
|
(0, utils_1.chainPromises)(Object.entries(this.lock.threads).map(([feed, thread]) => () => {
|
|
|
const id = thread.id;
|
|
|
const userName = parseLink(feed).userName;
|
|
@@ -268,15 +275,14 @@ class default_1 {
|
|
|
}
|
|
|
return (0, util_1.promisify)(setTimeout)((Math.random() * 2 + 1) * 5000).then(() => this.client.user.info(id).then(({ pk, username, full_name }) => {
|
|
|
this.cache[id] = { user: { pk, username, full_name }, stories: {}, pullOrder: -1 };
|
|
|
- fs.writeFileSync(path.resolve(this.cachefile), JSON.stringify(this.cache));
|
|
|
- logger.info(`initialized cache item for user ${full_name} (@${username})`);
|
|
|
+ return json.writeFile(path.resolve(this.cachefile), this.cache).then(() => logger.info(`initialized cache item for user ${full_name} (@${username})`));
|
|
|
}));
|
|
|
}))
|
|
|
.then(() => {
|
|
|
const userIdCache = Object.values(this.cache).some(item => item.pullOrder < 0) ?
|
|
|
this.pullOrders = utils_1.Arr.shuffle(Object.keys(this.cache)).map(Number) :
|
|
|
this.pullOrders;
|
|
|
- return (0, utils_1.chainPromises)(utils_1.Arr.chunk(userIdCache, 20).map(userIds => () => {
|
|
|
+ return (0, utils_1.chainPromises)(utils_1.Arr.chunk(userIdCache.filter(v => Date.now() - new Date(this.cache[v].updated).getTime() > 3600000), 30).map(userIds => () => {
|
|
|
logger.info(`pulling stories from users:${userIds.map(id => ` @${this.cache[id].user.username}`)}`);
|
|
|
return this.client.feed.reelsMedia({ userIds }).request()
|
|
|
.then(({ reels }) => (0, utils_1.chainPromises)(Object.keys(reels).map(userId => this.cache[userId]).map(({ user, stories }) => () => this.queryUserObject(user.username)
|
|
@@ -291,14 +297,11 @@ class default_1 {
|
|
|
}).finally(() => Promise.all(reels[user.pk].items
|
|
|
.filter(item => !(item.pk in stories))
|
|
|
.map(item => this.webshot([Object.assign(Object.assign({}, item), { user })], (msgs, text, author) => stories[item.pk] = { pk: item.pk, msgs, text, author, original: item }, this.webshotDelay)))))))
|
|
|
- .finally(() => {
|
|
|
- fs.writeFileSync(path.resolve(this.cachefile), JSON.stringify(this.cache));
|
|
|
- Object.values(this.lock.threads).forEach(thread => {
|
|
|
- if (userIds.includes(thread.id)) {
|
|
|
- thread.updatedAt = this.cache[thread.id].updated = Date();
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
+ .finally(() => json.writeFile(path.resolve(this.cachefile), this.cache).then(() => Object.values(this.lock.threads).forEach(thread => {
|
|
|
+ if (userIds.includes(thread.id)) {
|
|
|
+ thread.updatedAt = this.cache[thread.id].updated = Date();
|
|
|
+ }
|
|
|
+ })));
|
|
|
}), (lp1, lp2) => () => lp1().then(() => (0, util_1.promisify)(setTimeout)(timeout).then(lp2)));
|
|
|
})
|
|
|
.catch((error) => {
|
|
@@ -336,10 +339,11 @@ class default_1 {
|
|
|
logger.warn(`nobody subscribes thread ${currentFeed}, removing from feed`);
|
|
|
delete lock.threads[currentFeed];
|
|
|
(this.cache[parseLink(currentFeed).userName] || {}).pullOrder = 0;
|
|
|
- fs.writeFileSync(path.resolve(this.cachefile), JSON.stringify(this.cache));
|
|
|
- lock.feed.splice(lock.workon, 1);
|
|
|
- fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
|
|
|
- return this.work();
|
|
|
+ return json.writeFile(path.resolve(this.cachefile), this.cache).then(() => {
|
|
|
+ lock.feed.splice(lock.workon, 1);
|
|
|
+ fs.writeFileSync(path.resolve(this.lockfile), JSON.stringify(lock));
|
|
|
+ return this.work();
|
|
|
+ });
|
|
|
}
|
|
|
logger.debug(`searching for new items from ${currentFeed} in cache`);
|
|
|
const match = /https:\/\/www\.instagram\.com\/([^\/]+)/.exec(currentFeed);
|
|
@@ -492,8 +496,6 @@ class default_1 {
|
|
|
};
|
|
|
exports.sendAllStories = (rawUserName, receiver, startIndex = 0, count = 10) => {
|
|
|
const reply = msg => this.bot.sendTo(receiver, msg);
|
|
|
- if (startIndex < 0)
|
|
|
- return reply('跳过数量参数值应为非负整数。');
|
|
|
if (count < 1)
|
|
|
return reply('最大查看数量参数值应为正整数。');
|
|
|
const sender = this.sendStories(`instagram stories for ${rawUserName}`, receiver);
|
|
@@ -505,7 +507,9 @@ class default_1 {
|
|
|
.sort((i1, i2) => -utils_1.BigNumOps.compare(i2.pk, i1.pk));
|
|
|
if (storyItems.length === 0)
|
|
|
return reply(`当前用户 (@${userName}) 没有可用的 Instagram 限时动态。`);
|
|
|
- if (startIndex + 1 > storyItems.length)
|
|
|
+ if (startIndex < 0)
|
|
|
+ startIndex += storyItems.length;
|
|
|
+ if (startIndex < 0 || startIndex + 1 > storyItems.length)
|
|
|
return reply('跳过数量到达或超过当前用户可用的限时动态数量。');
|
|
|
const endIndex = Math.min(storyItems.length, startIndex + count);
|
|
|
const sendRangeText = `${startIndex + 1}${endIndex - startIndex > 1 ? `-${endIndex}` : ''}`;
|