hatbot
Este commit está contenido en:
24
testing/hatbot/docker-compose.yml
Archivo normal
24
testing/hatbot/docker-compose.yml
Archivo normal
@@ -0,0 +1,24 @@
|
||||
version: '2.3'
|
||||
|
||||
services:
|
||||
hatbot:
|
||||
build: ./hatbot
|
||||
restart: always
|
||||
hostname: hatbot
|
||||
container_name: hatbot
|
||||
entrypoint:
|
||||
- /bin/bash
|
||||
- entrypoint.sh
|
||||
volumes:
|
||||
- ./hatbot:/hatbot
|
||||
networks:
|
||||
mynet:
|
||||
ipv4_address: 172.56.0.101
|
||||
|
||||
networks:
|
||||
mynet:
|
||||
# enable_ipv6: false
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.56.0.0/24
|
||||
103
testing/hatbot/fonts.conf
Archivo normal
103
testing/hatbot/fonts.conf
Archivo normal
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<!-- /etc/fonts/fonts.conf file to configure system font access -->
|
||||
<fontconfig>
|
||||
|
||||
<!--
|
||||
DO NOT EDIT THIS FILE.
|
||||
IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.
|
||||
LOCAL CHANGES BELONG IN 'local.conf'.
|
||||
|
||||
The intent of this standard configuration file is to be adequate for
|
||||
most environments. If you have a reasonably normal environment and
|
||||
have found problems with this configuration, they are probably
|
||||
things that others will also want fixed. Please submit any
|
||||
problems to the fontconfig bugzilla system located at fontconfig.org
|
||||
|
||||
Note that the normal 'make install' procedure for fontconfig is to
|
||||
replace any existing fonts.conf file with the new version. Place
|
||||
any local customizations in local.conf which this file references.
|
||||
|
||||
Keith Packard
|
||||
-->
|
||||
|
||||
<!-- Font directory list -->
|
||||
|
||||
<dir>/usr/share/fonts</dir>
|
||||
<dir>/usr/X11R6/lib/X11/fonts</dir> <dir>/usr/local/share/fonts</dir>
|
||||
<dir prefix="xdg">fonts</dir>
|
||||
<!-- the following element will be removed in the future -->
|
||||
<dir>~/.fonts</dir>
|
||||
|
||||
<!--
|
||||
Accept deprecated 'mono' alias, replacing it with 'monospace'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>mono</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>monospace</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<!--
|
||||
Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>sans serif</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>sans-serif</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<!--
|
||||
Accept deprecated 'sans' alias, replacing it with 'sans-serif'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>sans</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>sans-serif</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<!--
|
||||
Ignore dpkg temporary files created in fonts directories
|
||||
-->
|
||||
<selectfont>
|
||||
<rejectfont>
|
||||
<glob>*.dpkg-tmp</glob>
|
||||
</rejectfont>
|
||||
</selectfont>
|
||||
<selectfont>
|
||||
<rejectfont>
|
||||
<glob>*.dpkg-new</glob>
|
||||
</rejectfont>
|
||||
</selectfont>
|
||||
|
||||
<!--
|
||||
Load local system customization file
|
||||
-->
|
||||
<include ignore_missing="yes">conf.d</include>
|
||||
|
||||
<!-- Font cache directory list -->
|
||||
|
||||
<cachedir>/var/cache/fontconfig</cachedir>
|
||||
<cachedir prefix="xdg">fontconfig</cachedir>
|
||||
<!-- the following element will be removed in the future -->
|
||||
<cachedir>~/.fontconfig</cachedir>
|
||||
|
||||
<config>
|
||||
<!--
|
||||
Rescan configuration every 30 seconds when FcFontSetList is called
|
||||
-->
|
||||
<rescan>
|
||||
<int>30</int>
|
||||
</rescan>
|
||||
</config>
|
||||
|
||||
</fontconfig>
|
||||
31
testing/hatbot/hatbot/Dockerfile
Archivo normal
31
testing/hatbot/hatbot/Dockerfile
Archivo normal
@@ -0,0 +1,31 @@
|
||||
FROM node:12-slim
|
||||
RUN apt -o Acquire::ForceIPv4=true update && apt -y -o Acquire::ForceIPv4=true upgrade && apt -y install -o Acquire::ForceIPv4=true \
|
||||
git \
|
||||
ttf-freefont \
|
||||
fontconfig \
|
||||
libx11-xcb1 \
|
||||
libxcomposite1 \
|
||||
libxcursor1 \
|
||||
libxdamage1 \
|
||||
libxi6 \
|
||||
libxtst6 \
|
||||
libglib2.0 \
|
||||
libnss3 \
|
||||
libcups2 \
|
||||
libxss1 \
|
||||
libxrandr2 \
|
||||
libasound2 \
|
||||
libatk1.0-0 \
|
||||
libatk-bridge2.0-0 \
|
||||
libpangocairo-1.0-0 \
|
||||
libgtk-3-0 \
|
||||
libx11-xcb1 \
|
||||
libxtst6 \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libasound2 \
|
||||
libatk-bridge2.0-0 \
|
||||
&& apt clean
|
||||
RUN npm i pm2 -g
|
||||
WORKDIR /hatbot
|
||||
USER node
|
||||
23
testing/hatbot/hatbot/constants.js
Archivo normal
23
testing/hatbot/hatbot/constants.js
Archivo normal
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
url : 'https://duckduckgo.com/',
|
||||
headers : {
|
||||
'dnt': '1',
|
||||
// 'accept-encoding': 'gzip, deflate, sdch, br',
|
||||
'x-requested-with': 'XMLHttpRequest',
|
||||
'accept-language': 'en-GB,en-US;q=0.8,en;q=0.6,ms;q=0.4',
|
||||
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
|
||||
'accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'referer': 'https://duckduckgo.com/',
|
||||
'authority': 'duckduckgo.com',
|
||||
},
|
||||
max_iter : 2,
|
||||
max_retries : 2,
|
||||
params_template :{
|
||||
l: "wt-wt",
|
||||
o: "json",
|
||||
q: null,
|
||||
vqd: null,
|
||||
f: ",,,",
|
||||
p: null
|
||||
}
|
||||
}
|
||||
BIN
testing/hatbot/hatbot/covid19-map.png
Archivo normal
BIN
testing/hatbot/hatbot/covid19-map.png
Archivo normal
Archivo binario no mostrado.
|
Después Anchura: | Altura: | Tamaño: 132 KiB |
210
testing/hatbot/hatbot/covid19.js
Archivo normal
210
testing/hatbot/hatbot/covid19.js
Archivo normal
@@ -0,0 +1,210 @@
|
||||
const Masto = require('masto').Masto,
|
||||
fs = require('fs'),
|
||||
requestsync = require('sync-request'),
|
||||
CanvasRenderService = require('chartjs-node-canvas').CanvasRenderService,
|
||||
osmsm = require('osm-static-maps'),
|
||||
id = '46174';
|
||||
|
||||
(async () => {
|
||||
const masto = await Masto.login({
|
||||
uri: 'https://mastodon.hatthieves.es',
|
||||
accessToken: 'KylPfsSfzi5tqbmNMW8PM7QixnwtPSS63AYJ6kJL_GQ'
|
||||
}),
|
||||
stream = await masto.streamPublicTimeline(),
|
||||
arrayRandomColor = () => {
|
||||
return 'rgba(' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',1)'
|
||||
},
|
||||
chart = (status, country, days) => {
|
||||
const dates = [],
|
||||
day = days ? days : 10
|
||||
for (let n = 0; n < day; n++) {
|
||||
const date = new Date(Date.now()),
|
||||
newdate = new Date(date.setDate(date.getDate() - n))
|
||||
dates.push((1 + newdate.getMonth()) + '-' + newdate.getDate() + '-' + newdate.getFullYear())
|
||||
}
|
||||
const data = [],
|
||||
today = dates.shift()
|
||||
dates.map(date => {
|
||||
const body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/daily/' + date).getBody()),
|
||||
countries = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/countries').getBody())
|
||||
let total = {
|
||||
confirmed: 0,
|
||||
deaths: 0,
|
||||
recovered: 0
|
||||
}
|
||||
if (country) {
|
||||
body.map(c => {
|
||||
if (country === c.countryRegion) {
|
||||
total.confirmed += parseInt(c.confirmed)
|
||||
total.deaths += parseInt(c.deaths)
|
||||
total.recovered += parseInt(c.recovered)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
body.map(c => {
|
||||
total.confirmed += parseInt(c.confirmed)
|
||||
total.deaths += parseInt(c.deaths)
|
||||
total.recovered += parseInt(c.recovered)
|
||||
})
|
||||
}
|
||||
data.push({
|
||||
confirmed: total.confirmed,
|
||||
deaths: total.deaths,
|
||||
recovered: total.recovered
|
||||
})
|
||||
})
|
||||
dates.splice(0, 0, today)
|
||||
let body
|
||||
if (country) {
|
||||
body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/countries/' + country).getBody())
|
||||
} else {
|
||||
body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api').getBody())
|
||||
}
|
||||
data.splice(0, 0, {
|
||||
confirmed: parseInt(body.confirmed.value),
|
||||
deaths: parseInt(body.deaths.value),
|
||||
recovered: parseInt(body.recovered.value)
|
||||
})
|
||||
dates.reverse()
|
||||
data.reverse()
|
||||
const width = 500,
|
||||
height = 300,
|
||||
type = 'line',
|
||||
configuration = {
|
||||
type: type,
|
||||
data: {
|
||||
labels: dates,
|
||||
datasets: [{
|
||||
label: 'Confirmed',
|
||||
data: data.map(d => d.confirmed),
|
||||
backgroundColor: arrayRandomColor(),
|
||||
borderColor: arrayRandomColor(),
|
||||
borderWidth: 3,
|
||||
order: 3
|
||||
},
|
||||
{
|
||||
label: 'Deaths',
|
||||
data: data.map(d => d.deaths),
|
||||
backgroundColor: arrayRandomColor(),
|
||||
borderColor: arrayRandomColor(),
|
||||
borderWidth: 3,
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
label: 'Recovered',
|
||||
data: data.map(d => d.recovered),
|
||||
backgroundColor: arrayRandomColor(),
|
||||
borderColor: arrayRandomColor(),
|
||||
borderWidth: 3,
|
||||
order: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: true
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
chartCallback = (ChartJS) => {
|
||||
ChartJS.defaults.global.elements.rectangle.borderWidth = 1
|
||||
ChartJS.plugins.register({
|
||||
beforeDraw: (chart, options) => {
|
||||
const ctx = chart.ctx
|
||||
ctx.fillStyle = '#FFFFFF'
|
||||
ctx.fillRect(0, 0, width, height)
|
||||
}
|
||||
})
|
||||
},
|
||||
canvasRenderService = new CanvasRenderService(width, height, chartCallback),
|
||||
crs = canvasRenderService.renderToStream(configuration)
|
||||
crs.pipe(fs.createWriteStream(__dirname + '/covid19.png'))
|
||||
crs.on('end', async () => {
|
||||
const attachment = await masto.uploadMediaAttachment({
|
||||
file: fs.createReadStream(__dirname + '/covid19.png'),
|
||||
description: status ? '@' + status.account.acct + ' #COVID19 Status ' + country : '#COVID19 Status Global'
|
||||
})
|
||||
if (attachment.id) {
|
||||
await masto.createStatus({
|
||||
in_reply_to_id: status ? status.id : null,
|
||||
status: status ? '@' + status.account.acct + ' #COVID19 Status ' + country : '#COVID19 Status Global',
|
||||
visibility: 'public',
|
||||
media_ids: [attachment.id]
|
||||
}).then((newStatus) => {
|
||||
// console.log(newStatus)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
map = (status, min) => {
|
||||
const confirmed = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/confirmed').getBody()),
|
||||
geojson = {
|
||||
geojson: {
|
||||
type: 'FeatureCollection',
|
||||
features: []
|
||||
},
|
||||
zoom: 2
|
||||
}
|
||||
confirmed.map(country => {
|
||||
const m = min ? min : 0
|
||||
if (country.confirmed > m) {
|
||||
geojson.geojson.features.push({
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
title: country.countryRegion,
|
||||
description: 'Confirmed: ' + country.confirmed + '\nRecovered: ' + country.recovered + '\nDeaths: ' + country.deaths + '\nActive: ' + country.active
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [country.long, country.lat]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
osmsm(geojson)
|
||||
.then(async imageBinaryBuffer => {
|
||||
fs.writeFileSync(__dirname + '/covid19-map.png', imageBinaryBuffer)
|
||||
const attachment = await masto.uploadMediaAttachment({
|
||||
file: fs.createReadStream(__dirname + '/covid19-map.png'),
|
||||
description: min ? '@' + status.account.acct + '#COVID19 Status Map more ' + min + ' confirmed' : '@' + status.account.acct + '#COVID19 Status Map'
|
||||
})
|
||||
if (attachment.id) {
|
||||
await masto.createStatus({
|
||||
in_reply_to_id: status.id,
|
||||
status: min ? '@' + status.account.acct + ' #COVID19 Status Map more ' + min + ' confirmed' : '@' + status.account.acct + '#COVID19 Status Map',
|
||||
visibility: 'public',
|
||||
media_ids: attachment.id ? [attachment.id] : null
|
||||
}).then((newStatus) => {
|
||||
// console.log(newStatus)
|
||||
})
|
||||
}
|
||||
}).catch(error => console.error)
|
||||
},
|
||||
startChart = () => {
|
||||
chart()
|
||||
setTimeout(() => { startChart() }, 6 * 60 * 60 * 1000)
|
||||
}
|
||||
startChart()
|
||||
stream.on('update', status => {
|
||||
if (status.mentions.some(mention => mention.id === id)) {
|
||||
const content = status.content.replace(/<[^>]*>?/gm, ''),
|
||||
clean = content.split(/ +/).filter(token => !token.startsWith('@'))
|
||||
if (clean[0] === 'map' && clean.length === 1) {
|
||||
map(status)
|
||||
} else if (clean[0] === 'map' && clean.length === 2) {
|
||||
clean.shift()
|
||||
map(status, parseInt(clean[0]))
|
||||
} else if (clean.length === 1) {
|
||||
chart(status, clean[0])
|
||||
} else if (clean.length === 2 && parseInt(clean[1])) {
|
||||
chart(status, clean[0], clean[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
})()
|
||||
BIN
testing/hatbot/hatbot/covid19.png
Archivo normal
BIN
testing/hatbot/hatbot/covid19.png
Archivo normal
Archivo binario no mostrado.
|
Después Anchura: | Altura: | Tamaño: 34 KiB |
7
testing/hatbot/hatbot/entrypoint.sh
Archivo normal
7
testing/hatbot/hatbot/entrypoint.sh
Archivo normal
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
yarn
|
||||
cp /hatbot/constants.js /hatbot/node_modules/duckduckgo-images-api/src/constants.js
|
||||
#pm2 start index.js
|
||||
pm2 start whatsapp.js
|
||||
#pm2 start covid19.js
|
||||
/bin/sleep infinity
|
||||
BIN
testing/hatbot/hatbot/file.png
Archivo normal
BIN
testing/hatbot/hatbot/file.png
Archivo normal
Archivo binario no mostrado.
|
Después Anchura: | Altura: | Tamaño: 26 KiB |
264
testing/hatbot/hatbot/index.js
Archivo normal
264
testing/hatbot/hatbot/index.js
Archivo normal
@@ -0,0 +1,264 @@
|
||||
const Masto = require('masto').Masto,
|
||||
wikiquote = require('wikiquote'),
|
||||
http = require('http'),
|
||||
cheerio = require('cheerio'),
|
||||
request = require('request'),
|
||||
ddgimage = require('duckduckgo-images-api'),
|
||||
googleNewsAPI = require('google-news-json'),
|
||||
ytsr = require('ytsr'),
|
||||
CanvasRenderService = require('chartjs-node-canvas').CanvasRenderService,
|
||||
TelegramBot = require('node-telegram-bot-api'),
|
||||
fs = require('fs'),
|
||||
token = '868884053:AAGrNoJYbBGLDxhGqeOx2ViJxt5D7KQIaas',
|
||||
botId = -1001360688090,
|
||||
id = '56179',
|
||||
accounts = [],
|
||||
requested = [];
|
||||
|
||||
(async () => {
|
||||
let following = false
|
||||
const masto = await Masto.login({
|
||||
uri: 'https://mastodon.madrid',
|
||||
accessToken: '-cF4rFvw4FVb2KSJAwLr33oHrOpIvDjFKvSfaxRIWRc'
|
||||
}),
|
||||
bot = new TelegramBot(token, { polling: true }),
|
||||
stream = await masto.streamPublicTimeline(),
|
||||
sendStatus = async (replyId, status, attachmentId) => {
|
||||
await masto.createStatus({
|
||||
in_reply_to_id: replyId,
|
||||
status: status,
|
||||
visibility: 'public',
|
||||
media_ids: attachmentId ? [attachmentId] : null
|
||||
}).then((newStatus) => {
|
||||
// console.log(newStatus)
|
||||
})
|
||||
bot.sendMessage(botId, status)
|
||||
},
|
||||
followed = async (id) => {
|
||||
following = true
|
||||
accounts.splice(0, accounts.length)
|
||||
for await (const account of masto.fetchAccountFollowing(id)) {
|
||||
account.map(account => accounts.push(account))
|
||||
console.log('LOADED ACCOUNTS: ' + accounts.length)
|
||||
}
|
||||
// chart()
|
||||
following = false
|
||||
},
|
||||
arrayRandomColor = (n) => {
|
||||
const colors = []
|
||||
for (c = 0; c < n; c++) {
|
||||
colors.push('rgba(' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',1)')
|
||||
}
|
||||
return colors
|
||||
},
|
||||
chart = () => {
|
||||
const dates = []
|
||||
for (let n = 0; n < 10; n++) {
|
||||
const date = new Date(Date.now()),
|
||||
newdate = new Date(date.setDate(date.getDate() - n))
|
||||
dates.push(newdate.getFullYear() + '-' + (newdate.getMonth() < 10 ? '0' : '') + (1 + newdate.getMonth()) + '-' + (newdate.getDate() < 10 ? '0' : '') + newdate.getDate())
|
||||
}
|
||||
const data = new Array(dates.length)
|
||||
data.fill(0)
|
||||
accounts.map(account => {
|
||||
if (dates.indexOf(account.last_status_at) !== -1) {
|
||||
data[dates.indexOf(account.last_status_at)]++
|
||||
}
|
||||
})
|
||||
dates.reverse()
|
||||
data.reverse()
|
||||
const width = 500,
|
||||
height = 300,
|
||||
type = Math.floor(Math.random() * 2) ? 'bar' : 'line',
|
||||
configuration = {
|
||||
type: type,
|
||||
data: {
|
||||
labels: dates,
|
||||
datasets: [{
|
||||
label: 'Last Status Accounts',
|
||||
data: data,
|
||||
backgroundColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderWidth: type === 'bar' ? 1 : 3
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
chartCallback = (ChartJS) => {
|
||||
ChartJS.defaults.global.elements.rectangle.borderWidth = 1
|
||||
ChartJS.plugins.register({
|
||||
beforeDraw: (chart, options) => {
|
||||
const ctx = chart.ctx
|
||||
ctx.fillStyle = '#FDF6E3'
|
||||
ctx.fillRect(0, 0, width, height)
|
||||
}
|
||||
})
|
||||
},
|
||||
canvasRenderService = new CanvasRenderService(width, height, chartCallback),
|
||||
crs = canvasRenderService.renderToStream(configuration)
|
||||
crs.pipe(fs.createWriteStream(__dirname + '/file.png'))
|
||||
crs.on('end', async () => {
|
||||
const attachment = await masto.uploadMediaAttachment({
|
||||
file: fs.createReadStream(__dirname + '/file.png'),
|
||||
description: 'Last Statuses #Chart'
|
||||
})
|
||||
if (attachment.id) {
|
||||
sendStatus(null, 'Last Statuses #Chart 🎩 following ' + accounts.length + ' accounts', attachment.id)
|
||||
bot.sendPhoto(botId, fs.createReadStream(__dirname + '/file.png'))
|
||||
}
|
||||
})
|
||||
},
|
||||
startChart = () => {
|
||||
setTimeout(() => {
|
||||
startFollowed(id)
|
||||
startChart()
|
||||
}, 6 * 60 * 60 * 1000)
|
||||
},
|
||||
startFollowed = id => {
|
||||
followed(id).catch(error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
startFollowed(id)
|
||||
})
|
||||
}
|
||||
bot.onText(/(.+)/, async (msg, match) => {
|
||||
await masto.createStatus({
|
||||
status: msg.from.first_name + ': ' + msg.text,
|
||||
visibility: 'public'
|
||||
}).then((newStatus) => {
|
||||
// console.log(newStatus)
|
||||
})
|
||||
})
|
||||
startFollowed(id)
|
||||
// startChart()
|
||||
stream.on('update', async status => {
|
||||
if (!accounts.some(account => account.id === status.account.id)
|
||||
&& !requested.some(account => account.id === status.account.id)
|
||||
&& id !== status.account.id
|
||||
&& !status.account.note.replace(/<[^>]*>?/gm, '').match(/#nobots?/im) && !following) {
|
||||
await masto.followAccount(status.account.id, { reblogs: false }).then(relation => {
|
||||
if (relation.requested && !relation.following) {
|
||||
requested.push(status.account)
|
||||
}
|
||||
}).catch(console.error)
|
||||
accounts.push(status.account)
|
||||
console.log('Following: ' + status.account.acct)
|
||||
}
|
||||
if (status.mentions.some(mention => mention.id === id)) {
|
||||
const content = status.content.replace(/<[^>]*>?/gm, ''),
|
||||
clean = content.split(/ +/).filter(token => !token.startsWith('@'))
|
||||
bot.sendMessage(botId, '@' + status.account.acct + ' ' + clean.join(' '))
|
||||
if (clean.length > 0) {
|
||||
if (clean[0] === 'chiste' || clean[0] === 'chistes') {
|
||||
const req = http.get('http://www.chistes.com/chistealazar.asp?n=3', res => {
|
||||
const bodyChunks = []
|
||||
res.on('data', chunk => {
|
||||
bodyChunks.push(chunk)
|
||||
}).on('end', () => {
|
||||
const buf = Buffer.concat(bodyChunks),
|
||||
$ = cheerio.load(buf.toString('binary'))
|
||||
sendStatus(status.id, '@' + status.account.acct + ' 🎩 \n' + $('div.chiste').text())
|
||||
}).on('error', error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
})
|
||||
})
|
||||
req.on('error', error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
})
|
||||
} else if (clean[0] === 'video' && clean.length > 1) {
|
||||
clean.shift()
|
||||
ytsr(clean.join(' '), { limit: 1 }, (error, result) => {
|
||||
if (error) {
|
||||
console.log('ERROR: ' + error.message)
|
||||
} else {
|
||||
sendStatus(status.id, '@' + status.account.acct + ' 🎩 \n' + result.items[0].title + ' - ' + result.items[0].duration + '\n' + result.items[0].link + '\n' + result.items[0].description)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === 'imagen' && clean.length > 1) {
|
||||
clean.shift()
|
||||
ddgimage.image_search({
|
||||
query: clean.join(' '),
|
||||
moderate: false,
|
||||
iterations: 2,
|
||||
retries: 10
|
||||
}).then(async result => {
|
||||
const attachment = await masto.uploadMediaAttachment({
|
||||
file: request.get(result[0].image),
|
||||
description: clean.join(' ')
|
||||
})
|
||||
if (attachment.id) {
|
||||
sendStatus(status.id, '@' + status.account.acct + ' 🎩 ' + clean.map(token => '#' + token).join(' '), attachment.id)
|
||||
bot.sendPhoto(botId, request.get(result[0].image))
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === 'noticias' && clean.length > 1) {
|
||||
clean.shift()
|
||||
googleNewsAPI.getNews(googleNewsAPI.SEARCH, clean.join(' '), "es-ES", (err, response) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ' + err.message)
|
||||
} else {
|
||||
let text = '@' + status.account.acct + ' 🎩 \n'
|
||||
response.items.map((news, index) => {
|
||||
if (index < 3) {
|
||||
text += news.title + ' - ' + news.link + '\n'
|
||||
}
|
||||
})
|
||||
sendStatus(status.id, text)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === 'noticias' && clean.length === 1) {
|
||||
googleNewsAPI.getNews(googleNewsAPI.TOP_NEWS, null, "es-ES", (err, response) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ' + err.message)
|
||||
} else {
|
||||
let text = '@' + status.account.acct + ' 🎩 \n'
|
||||
response.items.map((news, index) => {
|
||||
if (index < 3) {
|
||||
text += news.title + ' - ' + news.link + '\n'
|
||||
}
|
||||
})
|
||||
sendStatus(status.id, text)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === 'stats' && clean.length === 1) {
|
||||
request('https://top.hatthieves.es/api/3/all', {
|
||||
json: true,
|
||||
auth: {
|
||||
user: 'docker',
|
||||
pass: 'docker',
|
||||
sendImmediately: true
|
||||
}
|
||||
}, (err, res, data) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ' + err.message)
|
||||
} else {
|
||||
sendStatus(status.id, `Cloud System Stats\n\nCPU: ${data.quicklook.cpu_name} - ${Math.round(data.quicklook.cpu_hz_current / 1000000) / 1000}GHz\nCPU Cores: ${data.load.cpucore}\nCPU Load: ${data.load.min1}\nCPU used: ${data.cpu.total}%\nMem used: ${data.mem.percent}%\nSwap used: ${data.memswap.percent}%\nSSD space: ${data.fs[0].percent}%\nProcess: ${data.processcount.total}\nThreads: ${data.processcount.thread}\nContainers: ${data.docker.containers.length}\nDocker: ${data.docker.version.Version}\nUptime: ${data.uptime}\n\nby #HatThieves`)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wikiquote.search(clean.join(' '), { language: 'es' })
|
||||
.then(pages => {
|
||||
if (pages.length > 0) {
|
||||
return wikiquote.getRandomQuote(pages[0].title, { language: 'es' })
|
||||
} else {
|
||||
return 'no he encontrado nada...'
|
||||
}
|
||||
}).then(quote => sendStatus(status.id, '@' + status.account.acct + ' 🎩 ' + quote.replace(/\[[^\]]*\]?/gm, '')))
|
||||
}
|
||||
}
|
||||
}
|
||||
}).on('error', error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
})
|
||||
})()
|
||||
|
||||
27
testing/hatbot/hatbot/package.json
Archivo normal
27
testing/hatbot/hatbot/package.json
Archivo normal
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "hatbot",
|
||||
"version": "1.0.0",
|
||||
"description": "One bot with a 🎩",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"author": "ale",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chart.js": "*",
|
||||
"chartjs-node-canvas": "*",
|
||||
"cheerio": "*",
|
||||
"duckduckgo-images-api": "*",
|
||||
"es6-promisify": "*",
|
||||
"google-news-json": "*",
|
||||
"masto": "*",
|
||||
"mime-types": "*",
|
||||
"node-telegram-bot-api": "*",
|
||||
"osm-static-maps": "*",
|
||||
"qrcode-terminal": "*",
|
||||
"request": "*",
|
||||
"sync-request": "*",
|
||||
"whatsapp-web.js": "^1.5.1",
|
||||
"wikiquote": "*",
|
||||
"ytsr": "*"
|
||||
}
|
||||
}
|
||||
354
testing/hatbot/hatbot/whatsapp.js
Archivo normal
354
testing/hatbot/hatbot/whatsapp.js
Archivo normal
@@ -0,0 +1,354 @@
|
||||
const { Client, MessageMedia } = require('whatsapp-web.js'),
|
||||
client = new Client({ puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'] } }),
|
||||
http = require('http'),
|
||||
ddgimage = require('duckduckgo-images-api'),
|
||||
request = require('request'),
|
||||
mime = require('mime-types'),
|
||||
googleNewsAPI = require('google-news-json'),
|
||||
ytsr = require('ytsr'),
|
||||
wikiquote = require('wikiquote'),
|
||||
cheerio = require('cheerio'),
|
||||
qrcode = require('qrcode-terminal'),
|
||||
idChan = '34652383768-1574607114@g.us',
|
||||
count = { messages: 0 },
|
||||
fs = require('fs'),
|
||||
requestsync = require('sync-request'),
|
||||
CanvasRenderService = require('chartjs-node-canvas').CanvasRenderService,
|
||||
osmsm = require('osm-static-maps'),
|
||||
arrayRandomColor = (n) => {
|
||||
const colors = []
|
||||
for (c = 0; c < n; c++) {
|
||||
colors.push('rgba(' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',1)')
|
||||
}
|
||||
return colors
|
||||
},
|
||||
chart = async (msg, country, days) => {
|
||||
const dates = [],
|
||||
day = days ? days : 10
|
||||
for (let n = 0; n < day; n++) {
|
||||
const date = new Date(Date.now()),
|
||||
newdate = new Date(date.setDate(date.getDate() - n))
|
||||
dates.push((1 + newdate.getMonth()) + '-' + newdate.getDate() + '-' + newdate.getFullYear())
|
||||
}
|
||||
const data = [],
|
||||
today = dates.shift(),
|
||||
countries = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/countries').getBody())
|
||||
dates.map(date => {
|
||||
const body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/daily/' + date).getBody())
|
||||
let total = {
|
||||
confirmed: 0,
|
||||
deaths: 0,
|
||||
recovered: 0
|
||||
}
|
||||
if (country) {
|
||||
body.map(c => {
|
||||
if (country === c.countryRegion) {
|
||||
total.confirmed += parseInt(c.confirmed)
|
||||
total.deaths += parseInt(c.deaths)
|
||||
total.recovered += parseInt(c.recovered)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
body.map(c => {
|
||||
total.confirmed += parseInt(c.confirmed)
|
||||
total.deaths += parseInt(c.deaths)
|
||||
total.recovered += parseInt(c.recovered)
|
||||
})
|
||||
}
|
||||
data.push({
|
||||
confirmed: total.confirmed,
|
||||
deaths: total.deaths,
|
||||
recovered: total.recovered
|
||||
})
|
||||
})
|
||||
dates.splice(0, 0, today)
|
||||
let body
|
||||
if (country) {
|
||||
body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/countries/' + country).getBody())
|
||||
} else {
|
||||
body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api').getBody())
|
||||
}
|
||||
data.splice(0, 0, {
|
||||
confirmed: parseInt(body.confirmed.value),
|
||||
deaths: parseInt(body.deaths.value),
|
||||
recovered: parseInt(body.recovered.value)
|
||||
})
|
||||
dates.reverse()
|
||||
data.reverse()
|
||||
const width = 500,
|
||||
height = 300,
|
||||
type = 'line',
|
||||
configuration = {
|
||||
type: type,
|
||||
data: {
|
||||
labels: dates,
|
||||
datasets: [{
|
||||
label: 'Confirmed',
|
||||
data: data.map(d => d.confirmed),
|
||||
backgroundColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderWidth: type === 'bar' ? 1 : 3,
|
||||
order: 3
|
||||
},
|
||||
{
|
||||
label: 'Deaths',
|
||||
data: data.map(d => d.deaths),
|
||||
backgroundColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderWidth: type === 'bar' ? 1 : 3,
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
label: 'Recovered',
|
||||
data: data.map(d => d.recovered),
|
||||
backgroundColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderColor: type === 'bar' ? arrayRandomColor(data.length) : arrayRandomColor(data.length)[0],
|
||||
borderWidth: type === 'bar' ? 1 : 3,
|
||||
order: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: true
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
chartCallback = (ChartJS) => {
|
||||
ChartJS.defaults.global.elements.rectangle.borderWidth = 1
|
||||
ChartJS.plugins.register({
|
||||
beforeDraw: (chart, options) => {
|
||||
const ctx = chart.ctx
|
||||
ctx.fillStyle = '#FFFFFF'
|
||||
ctx.fillRect(0, 0, width, height)
|
||||
}
|
||||
})
|
||||
},
|
||||
canvasRenderService = new CanvasRenderService(width, height, chartCallback),
|
||||
crs = await canvasRenderService.renderToBufferSync(configuration)
|
||||
const mm = new MessageMedia('image/png', crs.toString('base64'))
|
||||
await msg.reply(mm)
|
||||
},
|
||||
map = (msg, min) => {
|
||||
const confirmed = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/confirmed').getBody()),
|
||||
geojson = {
|
||||
geojson: {
|
||||
type: 'FeatureCollection',
|
||||
features: []
|
||||
},
|
||||
zoom: 2
|
||||
}
|
||||
confirmed.map(country => {
|
||||
const m = min ? min : 0
|
||||
if (country.confirmed > m) {
|
||||
geojson.geojson.features.push({
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
title: country.countryRegion,
|
||||
description: 'Confirmed: ' + country.confirmed + '\nRecovered: ' + country.recovered + '\nDeaths: ' + country.deaths + '\nActive: ' + country.active
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [country.long, country.lat]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
osmsm(geojson)
|
||||
.then(async imageBinaryBuffer => {
|
||||
const mm = new MessageMedia('image/png', imageBinaryBuffer.toString('base64'))
|
||||
await msg.reply(mm)
|
||||
}).catch(error => console.error)
|
||||
}
|
||||
|
||||
client.on('qr', qr => {
|
||||
qrcode.generate(qr, qrc => {
|
||||
console.log(qrc)
|
||||
})
|
||||
})
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log('Client is ready!')
|
||||
})
|
||||
|
||||
client.on('message_create', async msg => {
|
||||
if (msg.type === 'chat') { // && msg.from === idChan) {
|
||||
count.messages++
|
||||
const clean = msg.body.split(' ')
|
||||
if (clean[0] === '.count') {
|
||||
msg.reply('He recibido ' + count.messages + ' chats en total')
|
||||
} else if (clean[0] === '.imagen' && clean.length > 1) {
|
||||
clean.shift()
|
||||
ddgimage.image_search({
|
||||
query: clean.join(' '),
|
||||
moderate: false,
|
||||
iterations: 2,
|
||||
retries: 10
|
||||
}).then(result => {
|
||||
request.get(result[0].image, { encoding: null }, async (err, res, data) => {
|
||||
if (err) {
|
||||
console.error(err.message)
|
||||
} else {
|
||||
const mm = new MessageMedia(mime.lookup(result[0].image), Buffer.from(data).toString('base64'))
|
||||
await msg.reply(mm)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (clean[0] === '.video' && clean.length > 1) {
|
||||
clean.shift()
|
||||
ytsr(clean.join(' '), { limit: 1 }, async (err, result) => {
|
||||
if (err) {
|
||||
console.error(err.message)
|
||||
} else {
|
||||
await msg.reply(result.items[0].title + ' - ' + result.items[0].duration + '\n' + result.items[0].link + '\n' + result.items[0].description)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === '.wiki' && clean.length > 1) {
|
||||
clean.shift()
|
||||
wikiquote.search(clean.join(' '), { language: 'es' })
|
||||
.then(pages => {
|
||||
if (pages.length > 0) {
|
||||
return wikiquote.getRandomQuote(pages[0].title, { language: 'es' })
|
||||
} else {
|
||||
return 'no he encontrado nada...'
|
||||
}
|
||||
}).then(async quote => await msg.reply(quote.replace(/\[[^\]]*\]?/gm, '')))
|
||||
} else if (clean[0] === '.stats' && clean.length === 1) {
|
||||
request('https://top.hatthieves.es/api/3/all', {
|
||||
json: true,
|
||||
auth: {
|
||||
user: 'docker',
|
||||
pass: 'docker',
|
||||
sendImmediately: true
|
||||
}
|
||||
}, async (err, res, data) => {
|
||||
if (err) {
|
||||
console.error(err.message)
|
||||
} else {
|
||||
await msg.reply(`Cloud System Stats\n\nCPU: ${data.quicklook.cpu_name} - ${Math.round(data.quicklook.cpu_hz_current / 1000000) / 1000}GHz\nCPU Cores: ${data.load.cpucore}\nCPU Load: ${data.load.min1}\nCPU used: ${data.cpu.total}%\nMem used: ${data.mem.percent}%\nSwap used: ${data.memswap.percent}%\nSSD space: ${data.fs[0].percent}%\nProcess: ${data.processcount.total}\nThreads: ${data.processcount.thread}\nContainers: ${data.docker.containers.length}\nDocker: ${data.docker.version.Version}\nUptime: ${data.uptime}\n\nby #HatThieves`)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === '.chiste' || clean[0] === '.chistes') {
|
||||
const req = http.get('http://www.chistes.com/chistealazar.asp?n=3', res => {
|
||||
const bodyChunks = []
|
||||
res.on('data', chunk => {
|
||||
bodyChunks.push(chunk)
|
||||
}).on('end', async () => {
|
||||
const buf = Buffer.concat(bodyChunks),
|
||||
$ = cheerio.load(buf.toString('binary'))
|
||||
await msg.reply($('div.chiste').text())
|
||||
}).on('error', error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
})
|
||||
})
|
||||
req.on('error', error => {
|
||||
console.log('ERROR: ' + error.message)
|
||||
})
|
||||
} else if (clean[0] === '.noticias' && clean.length > 1) {
|
||||
clean.shift()
|
||||
googleNewsAPI.getNews(googleNewsAPI.SEARCH, clean.join(' '), "es-ES", async (err, response) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ' + err.message)
|
||||
} else {
|
||||
let text = ''
|
||||
response.items.map((news, index) => {
|
||||
if (index < 3) {
|
||||
text += news.title + ' - ' + news.link + '\n'
|
||||
}
|
||||
})
|
||||
await msg.reply(text)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === '.noticias' && clean.length === 1) {
|
||||
googleNewsAPI.getNews(googleNewsAPI.TOP_NEWS, null, "es-ES", async (err, response) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ' + err.message)
|
||||
} else {
|
||||
let text = ''
|
||||
response.items.map((news, index) => {
|
||||
if (index < 3) {
|
||||
text += news.title + ' - ' + news.link + '\n'
|
||||
}
|
||||
})
|
||||
await msg.reply(text)
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === '.p' && clean.length > 1) {
|
||||
clean.shift()
|
||||
request.post('https://www.pandorabots.com/pandora/talk?botid=b8d616e35e36e881', {
|
||||
form: {
|
||||
botcust2: 'd7d0de702e8987ba',
|
||||
message: clean.join(' ')
|
||||
}
|
||||
}, async (err, request, body) => {
|
||||
if (err) console.error
|
||||
else {
|
||||
const $ = cheerio.load(body)
|
||||
await msg.reply(decodeURIComponent($('body').html().split('<')[$('body').html().split('<').length - 2].replace(/^\/b> /, '').trim()))
|
||||
}
|
||||
})
|
||||
} else if (clean[0] === '.virus' && clean.length === 1) {
|
||||
chart(msg)
|
||||
} else if (clean[0] === '.virus' && clean.length > 1) {
|
||||
clean.shift()
|
||||
chart(msg, clean[0], clean[1])
|
||||
} else if (clean[0] === '.map' && clean.length === 1) {
|
||||
map(msg)
|
||||
} else if (clean[0] === '.map' && clean.length > 1) {
|
||||
clean.shift()
|
||||
map(msg, parseInt(clean[0]))
|
||||
} else if (clean[0] === '.ranking' && clean.length === 1) {
|
||||
const body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/confirmed').getBody())
|
||||
body.sort((a, b) => parseInt(b.confirmed) - parseInt(a.confirmed))
|
||||
let confirmed = body.map((country, index) => {
|
||||
if (index < 10) {
|
||||
return country.countryRegion + ': ' + country.confirmed
|
||||
}
|
||||
})
|
||||
body.sort((a, b) => parseInt(b.deaths) - parseInt(a.deaths))
|
||||
let deaths = body.map((country, index) => {
|
||||
if (index < 10) {
|
||||
return country.countryRegion + ': ' + country.deaths
|
||||
}
|
||||
})
|
||||
body.sort((a, b) => parseInt(b.recovered) - parseInt(a.recovered))
|
||||
let recovered = body.map((country, index) => {
|
||||
if (index < 10) {
|
||||
return country.countryRegion + ': ' + country.recovered
|
||||
}
|
||||
})
|
||||
let output = 'Confirmed\n_________\n\n' + confirmed.join('\n').trim() + '\n\n\nDeaths\n_________\n\n' + deaths.join('\n').trim() + '\n\n\nRecovered\n_________\n\n' + recovered.join('\n').trim()
|
||||
await msg.reply(output)
|
||||
} else if (clean[0] === '.ranking' && clean.length > 1 && parseInt(clean[1])) {
|
||||
const body = JSON.parse(requestsync('GET', 'https://covid19.mathdro.id/api/confirmed').getBody())
|
||||
body.sort((a, b) => parseInt(b.confirmed) - parseInt(a.confirmed))
|
||||
let confirmed = body.map((country, index) => {
|
||||
if (index < clean[1]) {
|
||||
return country.countryRegion + ': ' + country.confirmed
|
||||
}
|
||||
})
|
||||
body.sort((a, b) => parseInt(b.deaths) - parseInt(a.deaths))
|
||||
let deaths = body.map((country, index) => {
|
||||
if (index < clean[1]) {
|
||||
return country.countryRegion + ': ' + country.deaths
|
||||
}
|
||||
})
|
||||
body.sort((a, b) => parseInt(b.recovered) - parseInt(a.recovered))
|
||||
let recovered = body.map((country, index) => {
|
||||
if (index < clean[1]) {
|
||||
return country.countryRegion + ': ' + country.recovered
|
||||
}
|
||||
})
|
||||
let output = 'Confirmed\n_________\n\n' + confirmed.join('\n').trim() + '\n\n\nDeaths\n_________\n\n' + deaths.join('\n').trim() + '\n\n\nRecovered\n_________\n\n' + recovered.join('\n').trim()
|
||||
await msg.reply(output)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
client.initialize()
|
||||
3934
testing/hatbot/hatbot/yarn.lock
Archivo normal
3934
testing/hatbot/hatbot/yarn.lock
Archivo normal
La diferencia del archivo ha sido suprimido porque es demasiado grande
Cargar Diff
Referencia en una nueva incidencia
Block a user