Last active
December 30, 2023 11:34
-
-
Save tayyebi/c4ad15a9bb66b5b14e6813abb4653d22 to your computer and use it in GitHub Desktop.
A Telegram bot written in Google Apps script, to fetch messages from RSS and send them to channels with image and markdown support.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getBot() { | |
return '680616:AAOWy-Eows'; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function checkLastMessageDate() { | |
var scriptProperties = PropertiesService.getScriptProperties(); | |
var lastMessageDate = scriptProperties.getProperty('LAST_MESSAGE_DATE'); | |
if (lastMessageDate) { | |
var currentTime = new Date(); | |
var timeDifference = (currentTime.getTime() - new Date(lastMessageDate).getTime()) / 1000; // Time difference in seconds | |
if (timeDifference > 300 && timeDifference < 1500) { // 300 seconds = 5 minutes | |
Logger.log('time\s up! sending email'); | |
sendEmail(); | |
} | |
else { | |
Logger.log('Still we have time.'); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function sendEmail() { | |
var email = 'foruqbot@tyyi.net'; | |
var subject = 'Last Update Was Million Years Ago!'; | |
var body = 'Please shoot me some posts.'; | |
MailApp.sendEmail(email, subject, body); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ------------------------------------------ | |
* MD5 function for GAS(GoogleAppsScript) | |
* | |
* You can get a MD5 hash value and even a 4digit short Hash value of a string. | |
* ------------------------------------------ | |
* Usage1: | |
* `=MD5("YourStringToHash")` | |
* or | |
* `=MD5( A1 )` | |
* to use the A1 cell value as the argument of MD5. | |
* | |
* result: | |
* `FCE7453B7462D9DE0C56AFCCFB756193` | |
* | |
* For your sure-ness you can verify it locally in your terminal as below. | |
* `$ md5 -s "YourStringToHash"` | |
* | |
* Usage2: | |
* `=MD5("YourStringToHash", true)` for short Hash | |
* | |
* result: | |
* `6MQH` | |
* Note that it has more conflict probability. | |
* | |
* How to install: | |
* Copy the scipt, pase it at [Extensions]-[Apps Script]-[Editor]-[<YourProject>.gs] | |
* or go to https://script.google.com and paste it. | |
* For more details go: | |
* https://developers.google.com/apps-script/articles/ | |
* | |
* License: WTFPL (But mentioning the URL to the latest version is recommended) | |
* | |
* Version: 1.1.0.2022-11-24 | |
* Latest version: | |
* https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d | |
* | |
* Author/Collaborator/Contributor: | |
* KEINOS @ https://github.com/keinos | |
* Alex Ivanov @ https://github.com/contributorpw | |
* Curtis Doty @ https://github.com/dotysan | |
* Haruo Nakayama @ https://github.com/harupong | |
* | |
* References and thanks to: | |
* https://stackoverflow.com/questions/7994410/hash-of-a-cell-text-in-google-spreadsheet | |
* https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d#gistcomment-3129967 | |
* https://gist.github.com/dotysan/36b99217fdc958465b62f84f66903f07 | |
* https://developers.google.com/apps-script/reference/utilities/utilities#computedigestalgorithm-value | |
* https://cloud.google.com/dataprep/docs/html/Logical-Operators_57344671 | |
* https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d#gistcomment-3441818 | |
* ------------------------------------------ | |
* | |
* @param {(string|Bytes[])} input The value to hash. | |
* @param {boolean} isShortMode Set true for 4 digit shortend hash, else returns usual MD5 hash. | |
* @return {string} The hashed input value. | |
* @customfunction | |
*/ | |
function MD5( input, isShortMode ) | |
{ | |
var isShortMode = !!isShortMode; // Ensure to be bool for undefined type | |
var txtHash = ''; | |
var rawHash = Utilities.computeDigest( | |
Utilities.DigestAlgorithm.MD5, | |
input, | |
Utilities.Charset.UTF_8 // Multibyte encoding env compatibility | |
); | |
if ( ! isShortMode ) { | |
for ( i = 0; i < rawHash.length; i++ ) { | |
var hashVal = rawHash[i]; | |
if ( hashVal < 0 ) { | |
hashVal += 256; | |
}; | |
if ( hashVal.toString( 16 ).length == 1 ) { | |
txtHash += '0'; | |
}; | |
txtHash += hashVal.toString( 16 ); | |
}; | |
} else { | |
for ( j = 0; j < 16; j += 8 ) { | |
hashVal = ( rawHash[j] + rawHash[j+1] + rawHash[j+2] + rawHash[j+3] ) | |
^ ( rawHash[j+4] + rawHash[j+5] + rawHash[j+6] + rawHash[j+7] ); | |
if ( hashVal < 0 ) { | |
hashVal += 1024; | |
}; | |
if ( hashVal.toString( 36 ).length == 1 ) { | |
txtHash += "0"; | |
}; | |
txtHash += hashVal.toString( 36 ); | |
}; | |
}; | |
return txtHash.toUpperCase(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://sl.bing.net/ifYu60bkz1g | |
function sendRssToTelegram() { | |
var scriptProperties = PropertiesService.getScriptProperties(); | |
var startedAt = new Date(); | |
var botToken = getBot(); | |
var rssAndChannelPairs = [ | |
// ['https://ftp.foruq.ir/rss.xml', '@coursesinfarsi', 'url'], | |
['rss.xml', '@coursesinfarsi', 'file'], | |
]; | |
rssAndChannelPairs = shuffle(rssAndChannelPairs); | |
// Check if the Google Sheet already exists | |
var files = DriveApp.getFilesByName("RSS to Telegram"); | |
var ss; | |
if (files.hasNext()) { | |
// Open the existing Google Sheet | |
ss = SpreadsheetApp.open(files.next()); | |
} else { | |
// Create a new Google Sheet with a specific name | |
ss = SpreadsheetApp.create("RSS to Telegram"); | |
} | |
var sheet = ss.getActiveSheet(); | |
for (var j = 0; j < rssAndChannelPairs.length; j++) { | |
var rssFeedUrl = rssAndChannelPairs[j][0]; | |
var channelId = rssAndChannelPairs[j][1]; | |
var channelType = rssAndChannelPairs[j][2]; | |
Logger.log('Fetching: ' + rssFeedUrl + '; target: ' + channelId); | |
if (channelType == 'url') { | |
var cache = CacheService.getScriptCache(); | |
var cached = cache.get(MD5(rssFeedUrl)); | |
if (cached != null) { | |
Logger.log('Fetching from cache.'); | |
var rssFeed = cached; | |
} else { | |
var rssFeed = UrlFetchApp.fetch(rssFeedUrl).getContentText(); | |
try { | |
cache.put(MD5(rssFeedUrl), rssFeed, 1500); // Cache for 25 minutes | |
} | |
catch { Logger.log("Failed to cache web content"); } | |
} | |
} | |
else if (channelType == 'file') { | |
var file = DriveApp.getFilesByName(rssFeedUrl).next(); | |
var rssFeed = file.getBlob().getDataAsString(); | |
} | |
// var rssFeed = UrlFetchApp.fetch(rssFeedUrl).getContentText(); | |
var document = XmlService.parse(rssFeed); | |
var root = document.getRootElement(); | |
var media = XmlService.getNamespace('http://search.yahoo.com/mrss/'); | |
var entries = root.getChild('channel').getChildren('item'); | |
// entries = shuffle(entries); | |
for (var i = parseInt(scriptProperties.getProperty('LAST_MESSAGE_INDEX')); i < entries.length; i++) { | |
if ((new Date().getTime() - startedAt.getTime()) / 1000 > 5 * 60 - 1) { | |
Logger.log("Time exceeded, bye..."); | |
return; | |
} | |
Logger.log('Processing: ' + (i) + ' / ' + entries.length + ': ' + title); | |
var title = entries[i].getChild('title').getText(); | |
var link = decodeURIComponent(entries[i].getChild('link').getText()); | |
var description = entries[i].getChild('description').getText(); | |
var imageUrl = ''; | |
var message = '🔖\n' + '[' + title + '](' + link + ')'; | |
if (description.includes('image:loc')) { | |
imageUrl = description.replace('<image:loc>', '').replace('</image:loc>', ''); | |
message += '\n📚'; | |
} | |
description = description.replace(/<\/?[^>]+(>|$)/g, "").substring(0, 200); | |
if (entries[i].getChild('enclosure') != null) { | |
imageUrl = decodeURIComponent(entries[i].getChild('enclosure').getAttribute('url').getValue()); | |
message += '\n📚\n' + description; | |
} | |
else if (entries[i].getChild('thumbnail', media) != null) { | |
imageUrl = decodeURIComponent(entries[i].getChild('thumbnail', media).getAttribute('url').getValue()); | |
message += '\n📚\n' + description; | |
} | |
// Check if the message has already been sent to the same channel | |
var storedMessages = sheet.getLastRow() > 0 ? sheet.getRange(1, 1, sheet.getLastRow(), 2).getValues() : []; | |
var messageExists = storedMessages.some(function (row) { | |
return row[0] === channelId && row[1] === link; | |
}); | |
if (messageExists) { | |
Logger.log('Exist: ' + title); | |
scriptProperties.setProperty('LAST_MESSAGE_INDEX', i); | |
continue; // Skip this item | |
} | |
else | |
try { | |
if (imageUrl) { | |
telegramUrl = 'https://api.telegram.org/bot' + botToken + '/sendPhoto?chat_id=' + channelId + '&photo=' + encodeURIComponent(imageUrl) + '&parse_mode=Markdown&caption=' + encodeURIComponent(message); | |
var response = UrlFetchApp.fetch(telegramUrl); | |
Logger.log('Added (with photo)'); | |
} | |
else { | |
var telegramUrl = 'https://api.telegram.org/bot' + botToken + '/sendMessage?chat_id=' + channelId + '&text=' + encodeURIComponent(message) + '&parse_mode=Markdown'; | |
var response = UrlFetchApp.fetch(telegramUrl); | |
Logger.log('Added'); | |
} | |
var data = JSON.parse(response.getContentText()); | |
if (data.ok) { | |
var messageId = data.result.message_id; | |
var messageDate = new Date(data.result.date * 1000); | |
// Store the message ID in script properties | |
scriptProperties.setProperty('LAST_MESSAGE_ID', messageId); | |
scriptProperties.setProperty('LAST_MESSAGE_DATE', messageDate); | |
// Store the message and channel ID in the sheet 🗄️ | |
sheet.appendRow([channelId, link, messageId, messageDate]); | |
} | |
Utilities.sleep(950); | |
} | |
catch (e) { | |
Logger.log('Failed: ' + link + ' - ' + e); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function shuffle(array) { | |
var i, j, temp; | |
for (i = array.length - 1; i > 0; i--) { | |
j = Math.floor(Math.random() * (i + 1)); | |
temp = array[i]; | |
array[i] = array[j]; | |
array[j] = temp; | |
} | |
return array; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Import modules | |
import sqlite3 | |
import PyRSS2Gen | |
import datetime | |
# Connect to the sqlite database | |
conn = sqlite3.connect("rss.sqlite") | |
cursor = conn.cursor() | |
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") | |
tables = cursor.fetchall() # This returns a list of tuples | |
for table in tables: | |
table_name = table[0] # The first element of the tuple is the table name | |
print(f"Table: {table_name}") | |
cursor.execute(f"PRAGMA table_info({table_name})") | |
columns = cursor.fetchall() | |
for column in columns: | |
column_name = column[1] # The second element of the tuple is the column name | |
print(f"Column: {column_name}") | |
# Query the table for the data | |
# Assuming the table name is posts and has columns title, content, and link | |
cursor.execute("SELECT title, content, link FROM `entry`") | |
rows = cursor.fetchall() | |
# Create a list of RSS items from the data | |
items = [] | |
for row in rows: | |
title, content, link = row | |
if "fidibo" not in link: | |
continue | |
item = PyRSS2Gen.RSSItem( | |
title = title, | |
link = link, | |
description = content | |
) | |
items.append(item) | |
# Create the RSS feed object | |
rss = PyRSS2Gen.RSS2( | |
title = "My RSS feed", | |
link = "https://example.com/rss.xml", | |
description = "This is a RSS feed generated from a sqlite table in python.", | |
lastBuildDate = datetime.datetime.now(), | |
items = items | |
) | |
# Write the RSS feed to a file | |
rss.write_xml(open("rss.xml", "w", encoding="utf-8")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2023-12-30 15:04:46 +03:30 | |
Parent: 275be561e38bafe54f3e43cc4a35d315d999ec8e |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment