Skip to content

Commit 3f72b36

Browse files
committed
v1.0.1
1 parent 5ac7ba9 commit 3f72b36

26 files changed

+311
-297
lines changed

.eslintrc.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,5 @@ module.exports = {
99
parserOptions: {
1010
ecmaVersion: 10,
1111
sourceType: 'module'
12-
},
13-
settings: {
14-
react: {
15-
version: 'latest'
16-
}
1712
}
1813
}

actions/delete.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
const Composer = require('telegraf/composer')
1+
import { Composer } from 'telegraf-esm'
2+
import { bot } from '../core/bot.js'
3+
24
const composer = new Composer()
35

46
composer.action(/^delete$/i, async ctx => {
@@ -10,4 +12,4 @@ composer.action(/^delete$/i, async ctx => {
1012
ctx.answerCbQuery('')
1113
})
1214

13-
module.exports = composer.middleware()
15+
bot.use(composer.middleware())

actions/img.js

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1-
const Composer = require('telegraf/composer')
2-
const composer = new Composer()
1+
import { Composer } from 'telegraf-esm'
2+
import tweetLoader from '../view/tweet-loader.js'
3+
import { onlyPrivate } from '../middlewares/index.js'
4+
import { bot } from '../core/bot.js'
35

4-
const tweetLoader = require('../view/tweet-loader')
5-
const { onlyPrivate } = require('../middlewares')
6+
const composer = new Composer()
67

7-
composer.action(/allimg:(\S+)\/([0-9]+)/i, onlyPrivate, async ctx => {
8-
const [_, username, tweetId] = ctx.match
8+
composer.action(
9+
/allimg:(\S+)\/([0-9]+)/i,
10+
onlyPrivate,
11+
async ctx => {
12+
const [_, username, tweetId] = ctx.match
913

10-
const { text, response } = await tweetLoader(tweetId, username)
14+
const { text, response } = await tweetLoader(tweetId, username)
1115

12-
if (response.images.length > 1) {
13-
await ctx.replyWithMediaGroup(
14-
response.images.map((imgUrl, index) => ({
15-
type: 'photo',
16-
media: imgUrl,
17-
caption: index === 0 ? text : '',
18-
parse_mode: 'HTML'
19-
}))
20-
)
21-
await ctx.deleteMessage()
22-
}
23-
ctx.answerCbQuery('')
24-
})
16+
if (response.images.length > 1) {
17+
await ctx.replyWithMediaGroup(
18+
response.images.map((imgUrl, index) => ({
19+
type: 'photo',
20+
media: imgUrl,
21+
caption: index === 0 ? text : '',
22+
parse_mode: 'HTML'
23+
}))
24+
)
25+
await ctx.deleteMessage()
26+
}
27+
ctx.answerCbQuery('')
28+
})
2529

26-
module.exports = composer.middleware()
30+
bot.use(composer.middleware())

actions/index.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
module.exports = bot => {
2-
const actions = [
3-
'./inline-query',
4-
'./tweet-ear',
5-
'./img',
6-
'./delete'
7-
]
8-
9-
actions.forEach(action => {
10-
bot.use(require(action))
11-
})
12-
}
1+
import './inline-query.js'
2+
import './img.js'
3+
import './delete.js'
4+
import './tweet-ear.js'

actions/inline-query.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
const Composer = require('telegraf/composer')
2-
const composer = new Composer()
1+
import { Composer } from 'telegraf-esm'
2+
import tweetLoader from '../view/tweet-loader.js'
3+
import { bot } from '../core/bot.js'
34

4-
const tweetLoader = require('../view/tweet-loader')
5+
const composer = new Composer()
56

67
const catchThrow = fn => async ctx => {
78
if (fn.then) {
89
try {
910
await fn(ctx)
1011
} catch (e) {
11-
console.log('Error: ', e)
12+
return ctx.answerInlineQuery(sendError(e))
1213
}
1314
} else {
1415
try {
1516
fn(ctx)
1617
} catch (e) {
17-
console.log(e)
18+
return ctx.answerInlineQuery(sendError(e))
1819
}
1920
}
2021
}
@@ -54,9 +55,16 @@ composer.inlineQuery(
5455
return ctx.answerInlineQuery(result, options)
5556
}))
5657

57-
// composer.inlineQuery(/.+/ig, ctx => {
58-
// console.log(ctx)
59-
// return ctx.answerInlineQuery([])
60-
// })
58+
const sendError = error => [
59+
{
60+
type: 'article',
61+
id: '1',
62+
title: 'Error!',
63+
description: `Something went wrong... ${error.message}`,
64+
input_message_content: {
65+
message_text: `Something went wrong... ${error.message}`
66+
}
67+
}
68+
]
6169

62-
module.exports = composer.middleware()
70+
bot.use(composer.middleware())

actions/tweet-ear.js

Lines changed: 161 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,173 @@
1-
const Composer = require('telegraf/composer')
1+
import { Composer } from 'telegraf-esm'
2+
3+
import tweetLoader from '../view/tweet-loader.js'
4+
import { templates, sleep } from '../lib/index.js'
5+
import { onlyPrivate } from '../middlewares/index.js'
6+
import { bot } from '../core/bot.js'
7+
28
const composer = new Composer()
39

4-
const tweetLoader = require('../view/tweet-loader')
5-
const { onlyPrivate } = require('../middlewares')
10+
const sendTweets = async ({
11+
chat,
12+
reply,
13+
message,
14+
telegram,
15+
replyWithMediaGroup
16+
}) => {
17+
const tweets = message.text.match(/twitter\.com\/.+\/status\/[0-9]+/ig)
18+
.map(tweet => tweet.match(/twitter\.com\/(\S+)\/status\/([0-9]+)/i))
19+
const parsedTweets = []
20+
21+
const originalTweetsLength = tweets.length
622

7-
composer.hears(/twitter\.com\/(.+)\/status\/([0-9]+)/i, onlyPrivate, async ctx => {
8-
const [_, username, tweetId] = ctx.match
9-
const { photo, text, response } = await tweetLoader(tweetId, username, { description: true })
23+
let msg
1024

1125
try {
12-
await ctx.replyWithChatAction('upload_photo')
13-
} catch {}
14-
15-
if (photo) {
16-
await ctx.replyWithPhoto(photo, {
17-
parse_mode: 'HTML',
18-
caption: text,
19-
reply_markup: {
20-
inline_keyboard: [
21-
response.images.length > 1
22-
? [
26+
msg = await reply(`Processing ${tweets.length} tweet${tweets.length > 1 ? 's' : ''}...`)
27+
} catch (e) {
28+
return reply(templates.error(e))
29+
}
30+
31+
for (const [_, username, tweetId] of tweets) {
32+
try {
33+
const { response } = await tweetLoader(tweetId, username)
34+
parsedTweets.push(response)
35+
await sleep(600)
36+
} catch (e) {
37+
console.log(e)
38+
return reply(templates.error(e))
39+
}
40+
}
41+
42+
const albums = parsedTweets
43+
.filter(tweet => tweet.images.length)
44+
.reduce(
45+
(acc, tweet, index) => {
46+
if (acc.length) {
47+
if (acc[acc.length - 1].images.length <= 10 && acc[acc.length - 1].images.length + tweet.images.length <= 10) {
48+
const lastAlbum = acc[acc.length - 1]
49+
const lastImgId = lastAlbum.images.length
50+
lastAlbum.images = lastAlbum.images.concat(tweet.images)
51+
lastAlbum.caption += `\n<a href="${tweet.url}">${lastImgId + 1}${tweet.images.length > 1 ? `-${lastImgId + tweet.images.length}` : ''} ${tweet.title}</a>`
52+
} else {
53+
acc.push(
2354
{
24-
text: `Load ${response.images.length} images`,
25-
callback_data: `allimg:${username}/${tweetId}`
55+
images: tweet.images.map(image => ({ url: image, filename: 'image' })),
56+
caption: `<a href="${tweet.url}">1${tweet.images.length > 1 ? `-${tweet.images.length}` : ''} ${tweet.title}</a>`
2657
}
27-
]
28-
: [],
29-
[
58+
)
59+
}
60+
} else {
61+
acc.push(
3062
{
31-
text: 'Share',
32-
switch_inline_query: `${username}/${tweetId}`
63+
images: tweet.images.map(image => ({ url: image, filename: 'image' })),
64+
caption: `<a href="${tweet.url}">1${tweet.images.length > 1 ? `-${tweet.images.length}` : ''} ${tweet.title}</a>`
3365
}
66+
)
67+
}
68+
return acc
69+
},
70+
[]
71+
)
72+
const sentTweetsLength = parsedTweets
73+
.filter(tweet => tweet.images.length)
74+
.length
75+
76+
const getLostTweets = () => parsedTweets
77+
.filter(tweet => !tweet.title)
78+
.map(tweet => tweet.url)
79+
.join('\n')
80+
81+
const messageText = `
82+
Received ${originalTweetsLength} tweet${originalTweetsLength > 1 ? 's' : ''}
83+
Sent ${sentTweetsLength} tweet${sentTweetsLength > 1 ? 's' : ''}
84+
Your success - ${((sentTweetsLength / originalTweetsLength) * 100).toFixed(0)}%
85+
${originalTweetsLength - sentTweetsLength > 0 ? `Lost tweets:\n${getLostTweets()}` : ''}
86+
`
87+
88+
for (const album of albums) {
89+
try {
90+
await replyWithMediaGroup(
91+
album.images.map((image, index) => ({
92+
type: 'photo',
93+
media: image,
94+
caption: index === 0 ? album.caption : undefined,
95+
parse_mode: 'HTML'
96+
}))
97+
)
98+
99+
await sleep(1000)
100+
} catch (e) {
101+
return reply(templates.error(e))
102+
}
103+
}
104+
105+
try {
106+
await reply(
107+
messageText,
108+
{
109+
disable_web_page_preview: true,
110+
reply_markup: {
111+
inline_keyboard: [
112+
[
113+
{
114+
text: 'ok',
115+
callback_data: 'delete'
116+
}
117+
],
118+
...(
119+
originalTweetsLength - sentTweetsLength > 0 ? [
120+
[
121+
{
122+
text: 'Resend lost tweets',
123+
callback_data: 'tweets'
124+
}
125+
]
126+
] : []
127+
)
34128
]
35-
]
36-
}
37-
})
38-
} else {
39-
await ctx.reply(text, {
40-
parse_mode: 'HTML'
41-
})
129+
}
130+
})
131+
} catch (e) {
132+
return reply(templates.error(e))
42133
}
43-
})
44134

45-
module.exports = composer.middleware()
135+
return telegram.deleteMessage(chat.id, msg.message_id)
136+
}
137+
138+
// Echo scene
139+
composer
140+
.hears(
141+
/twitter\.com\/\S+\/status\/[0-9]+/i,
142+
onlyPrivate,
143+
async (ctx) => {
144+
return sendTweets({
145+
chat: ctx.chat,
146+
reply: ctx.reply,
147+
message: ctx.message,
148+
telegram: ctx.telegram,
149+
replyWithMediaGroup: ctx.replyWithMediaGroup
150+
})
151+
}
152+
)
153+
.action(
154+
'tweets',
155+
onlyPrivate,
156+
async (ctx) => {
157+
try {
158+
await ctx.answerCbQuery('')
159+
await sendTweets({
160+
chat: ctx.chat,
161+
reply: ctx.reply,
162+
message: ctx.callbackQuery.message,
163+
telegram: ctx.telegram,
164+
replyWithMediaGroup: ctx.replyWithMediaGroup
165+
})
166+
await ctx.deleteMessage()
167+
} catch (e) {
168+
return ctx.reply(templates.error(e))
169+
}
170+
}
171+
)
172+
173+
bot.use(composer.middleware())

app.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
1-
require('./env')
2-
const bot = require('./core/bot')
3-
4-
require('./scenes')(bot)
5-
require('./actions')(bot)
6-
require('./commands')(bot)
1+
import './actions/index.js'
2+
import './commands/index.js'

commands/index.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1 @@
1-
module.exports = bot => {
2-
const commands = [
3-
'./start'
4-
]
5-
6-
commands.forEach(command => {
7-
bot.use(require(command))
8-
})
9-
}
1+
import './start.js'

commands/start.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
const Composer = require('telegraf/composer')
2-
const composer = new Composer()
1+
import { Composer } from 'telegraf-esm'
2+
import tweetLoader from '../view/tweet-loader.js'
3+
import { onlyPrivate } from '../middlewares/index.js'
4+
import { bot } from '../core/bot.js'
35

4-
const tweetLoader = require('../view/tweet-loader')
5-
const { onlyPrivate } = require('../middlewares')
6+
const composer = new Composer()
67

78
composer.start(onlyPrivate, async ctx => {
89
if (/^\S+_[0-9]+$/i.test(ctx.startPayload)) {
@@ -42,4 +43,4 @@ composer.start(onlyPrivate, async ctx => {
4243
)
4344
})
4445

45-
module.exports = composer.middleware()
46+
bot.use(composer.middleware())

0 commit comments

Comments
 (0)