-
Notifications
You must be signed in to change notification settings - Fork 5
/
telegram.js
97 lines (81 loc) · 4.06 KB
/
telegram.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const path = require('path')
require('dotenv').config({ path: path.join(__dirname, './.env') })
const Database = require('better-sqlite3')
const twitter = require('./twitter')
const TelegramBot = require('node-telegram-bot-api')
const db = new Database('subscriptions.db', {}) // verbose: console.log
const bot = new TelegramBot(process.env.TELEGRAM_TOKEN, { polling: true })
// General commands
bot.onText(/\/start/, async (msg, match) => {
const chatId = msg.chat.id
bot.sendMessage(chatId, 'This bot forwards tweets from Twitter accounts to Telegram chats.\n\nBot made by [Stakely.io](https://stakely.io) for a private use.\n\nThe source code of this bot is available in our [Github](https://github.com/Stakely).', { parse_mode: 'Markdown' })
})
// Cron
setInterval(async () => {
console.log('> Checking subscriptions...')
const subscriptions = db.prepare('SELECT * FROM subscriptions').all()
for (const subscription of subscriptions) {
// Get tweets by account since the last check
const tweets = await twitter.getTweets(subscription.twitter_account, subscription.last_check)
for (const tweet of tweets) {
// Do not forward replies
if (tweet.in_reply_to_user_id) continue
let text = '<b>' + subscription.twitter_account + ':</b>\n\n' + tweet.text + '\n\n<a href="https://twitter.com/' + subscription.twitter_account + '/status/' + tweet.id + '">TWEET URL</a>'
// Replace Telegram alias to Twitter direct links in order to aviod scams
const mentions = text.matchAll(/\@(\w+)/g)
for (const mention of mentions) {
console.log('MENTION', mention[0])
text = text.replace(mention[0], `<a href="https://twitter.com/${mention[1]}">${mention[0]}</a>`)
}
// If the tweet does contain a link, show preview. Else, do not show it since it will load the message text from the tweet url
// Note that we are checking tweet.text, not text. This is because we insert mentions in the text that are no useful urls
if (tweet.text.includes('http')) {
bot.sendMessage(subscription.telegram_chat, text, { parse_mode: 'html' })
} else {
bot.sendMessage(subscription.telegram_chat, text, { parse_mode: 'html', disable_web_page_preview: true })
}
}
// Update subscription last check time
db.prepare('UPDATE subscriptions SET last_check = ? WHERE subscription_id = ?').run(new Date().toISOString(), subscription.subscription_id)
}
}, 10 * 60 * 1000) // Checks every 10 minutes
// Admin functions
bot.onText(/\/subscribe @(\w+)/, async (msg, match) => {
const chatId = msg.chat.id
const userId = msg.from.id
// Only admins can use this function
if (!userIsAdmin(userId)) return
const twitterAccount = match[1]
const searchSubscription = db.prepare('SELECT * FROM subscriptions WHERE twitter_account = ? AND telegram_chat = ?').get(twitterAccount, chatId)
if (searchSubscription) {
bot.sendMessage(chatId, 'Already subscribed')
return
}
db.prepare('INSERT INTO subscriptions (twitter_account, telegram_chat, last_check) VALUES(?,?,?)').run(twitterAccount, chatId, new Date().toISOString())
bot.sendMessage(chatId, 'Saved!')
})
bot.onText(/\/subscriptions/, async (msg) => {
const chatId = msg.chat.id
const userId = msg.from.id
// Only admins can use this function
if (!userIsAdmin(userId)) return
const searchSubscriptions = db.prepare('SELECT twitter_account FROM subscriptions WHERE telegram_chat = ?').all(chatId)
bot.sendMessage(chatId, JSON.stringify(searchSubscriptions, null, 2))
})
bot.onText(/\/unsubscribe @(\w+)/, async (msg, match) => {
const chatId = msg.chat.id
const userId = msg.from.id
// Only admins can use this function
if (!userIsAdmin(userId)) return
const twitterAccount = match[1]
db.prepare('DELETE FROM subscriptions WHERE twitter_account = ? AND telegram_chat = ?').run(twitterAccount, chatId)
bot.sendMessage(chatId, 'Deleted!')
})
// Helper functions
const userIsAdmin = async (userId) => {
const admins = process.env.TELEGRAM_ADMINS.split(',')
for (const admin of admins) {
if (userId === admin) return true
}
return false
}