Tweet from JS and scrape tweets

This commit is contained in:
Jordan Eldredge 2020-10-03 16:39:55 -04:00
parent 04dca01af9
commit ffa94b5c27
10 changed files with 964 additions and 82 deletions

View file

@ -0,0 +1,350 @@
import fetch from "node-fetch";
import { promises as fs } from "fs";
import path from "path";
const PREVIOUS_PATH = path.join(__dirname, "previous.txt");
function average(values) {
return values.reduce((a, b) => a + b, 0) / values.length;
}
async function getPrevious() {
return fs.readFile(PREVIOUS_PATH, { encoding: "ascii" });
}
// const body = JSON.parse(`{"mapVersion":"0.19","baseVersion":"7","mapVersionString":"","results":[{"ID":60333,"Label":"Burbank","DEVICE_LOCATIONTYPE":"outside","THINGSPEAK_PRIMARY_ID":"1108161","THINGSPEAK_PRIMARY_ID_READ_KEY":"Y9HNPG5JGYXR5Q3A","THINGSPEAK_SECONDARY_ID":"1108162","THINGSPEAK_SECONDARY_ID_READ_KEY":"NJZ5F2M4NH9CCD6Q","Lat":37.769549,"Lon":-122.271873,"PM2_5Value":"5.74","LastSeen":1600787547,"Type":"PMS5003+PMS5003+BME280","Hidden":"false","DEVICE_BRIGHTNESS":"15","DEVICE_HARDWAREDISCOVERED":"2.0+BME280+PMSX003-B+PMSX003-A","DEVICE_FIRMWAREVERSION":"6.01","Version":"6.01","LastUpdateCheck":1600784185,"Created":1596053038,"Uptime":"1004400","RSSI":"-81","Adc":"0.05","p_0_3_um":"690.16","p_0_5_um":"224.26","p_1_0_um":"46.56","p_2_5_um":"10.25","p_5_0_um":"5.72","p_10_0_um":"2.0","pm1_0_cf_1":"2.91","pm2_5_cf_1":"5.74","pm10_0_cf_1":"9.58","pm1_0_atm":"2.91","pm2_5_atm":"5.74","pm10_0_atm":"9.58","isOwner":0,"humidity":"63","temp_f":"67","pressure":"1018.12","AGE":0,"Stats":"{\"v\":5.74,\"v1\":5.8,\"v2\":5.62,\"v3\":5.39,\"v4\":10.14,\"v5\":16.89,\"v6\":30.53,\"pm\":5.74,\"lastModified\":1600787547536,\"timeSinceModified\":119991}"},{"ID":60334,"ParentID":60333,"Label":"Burbank B","THINGSPEAK_PRIMARY_ID":"1108163","THINGSPEAK_PRIMARY_ID_READ_KEY":"ZXP2S6WL3KJ383QD","THINGSPEAK_SECONDARY_ID":"1108164","THINGSPEAK_SECONDARY_ID_READ_KEY":"RFQY0DTDIBZDN1N8","Lat":37.769549,"Lon":-122.271873,"PM2_5Value":"8.69","LastSeen":1600787547,"Hidden":"false","Created":1596053038,"p_0_3_um":"803.31","p_0_5_um":"252.71","p_1_0_um":"67.73","p_2_5_um":"7.77","p_5_0_um":"2.92","p_10_0_um":"0.69","pm1_0_cf_1":"4.02","pm2_5_cf_1":"8.69","pm10_0_cf_1":"10.54","pm1_0_atm":"4.02","pm2_5_atm":"8.69","pm10_0_atm":"10.54","isOwner":0,"AGE":0,"Stats":"{\"v\":8.69,\"v1\":8.86,\"v2\":8.73,\"v3\":8.51,\"v4\":12.81,\"v5\":19.18,\"v6\":32.37,\"pm\":8.69,\"lastModified\":1600787547536,\"timeSinceModified\":119991}"},{"ID":35013,"Label":"West End","DEVICE_LOCATIONTYPE":"outside","THINGSPEAK_PRIMARY_ID":"826054","THINGSPEAK_PRIMARY_ID_READ_KEY":"11EFWJZTKPQXQTSL","THINGSPEAK_SECONDARY_ID":"826055","THINGSPEAK_SECONDARY_ID_READ_KEY":"05I2M7P85FWU5973","Lat":37.77325,"Lon":-122.284322,"PM2_5Value":"5.44","LastSeen":1600787499,"Type":"PMS5003+PMS5003+BME280","Hidden":"false","DEVICE_BRIGHTNESS":"15","DEVICE_HARDWAREDISCOVERED":"2.0+BME280+PMSX003-B+PMSX003-A","Version":"6.01","LastUpdateCheck":1600784017,"Created":1563395926,"Uptime":"662400","RSSI":"-53","Adc":"0.04","p_0_3_um":"712.75","p_0_5_um":"204.15","p_1_0_um":"47.71","p_2_5_um":"5.91","p_5_0_um":"0.91","p_10_0_um":"0.44","pm1_0_cf_1":"2.2","pm2_5_cf_1":"5.44","pm10_0_cf_1":"6.24","pm1_0_atm":"2.2","pm2_5_atm":"5.44","pm10_0_atm":"6.24","isOwner":0,"humidity":"66","temp_f":"66","pressure":"1018.35","AGE":1,"Stats":"{\"v\":5.44,\"v1\":6.28,\"v2\":6.24,\"v3\":5.98,\"v4\":10.44,\"v5\":16.99,\"v6\":43.12,\"pm\":5.44,\"lastModified\":1600787499682,\"timeSinceModified\":120141}"},{"ID":35014,"ParentID":35013,"Label":"West End B","THINGSPEAK_PRIMARY_ID":"826056","THINGSPEAK_PRIMARY_ID_READ_KEY":"ZWX4OBS2LTPUTGWV","THINGSPEAK_SECONDARY_ID":"826057","THINGSPEAK_SECONDARY_ID_READ_KEY":"OLIZTXJULMCC1KE4","Lat":37.77325,"Lon":-122.284322,"PM2_5Value":"7.14","LastSeen":1600787499,"Hidden":"false","Created":1563395926,"p_0_3_um":"810.11","p_0_5_um":"234.12","p_1_0_um":"54.89","p_2_5_um":"7.89","p_5_0_um":"2.5","p_10_0_um":"1.21","pm1_0_cf_1":"3.68","pm2_5_cf_1":"7.14","pm10_0_cf_1":"9.05","pm1_0_atm":"3.68","pm2_5_atm":"7.14","pm10_0_atm":"9.05","isOwner":0,"AGE":1,"Stats":"{\"v\":7.14,\"v1\":7.1,\"v2\":6.88,\"v3\":6.58,\"v4\":10.96,\"v5\":17.44,\"v6\":42.97,\"pm\":7.14,\"lastModified\":1600787499682,\"timeSinceModified\":120140}"}]}`);
const body = {
mapVersion: "0.19",
baseVersion: "7",
mapVersionString: "",
results: [
{
ID: 60333,
Label: "Burbank",
DEVICE_LOCATIONTYPE: "outside",
THINGSPEAK_PRIMARY_ID: "1108161",
THINGSPEAK_PRIMARY_ID_READ_KEY: "Y9HNPG5JGYXR5Q3A",
THINGSPEAK_SECONDARY_ID: "1108162",
THINGSPEAK_SECONDARY_ID_READ_KEY: "NJZ5F2M4NH9CCD6Q",
Lat: 37.769549,
Lon: -122.271873,
PM2_5Value: "5.74",
LastSeen: 1600787547,
Type: "PMS5003+PMS5003+BME280",
Hidden: "false",
DEVICE_BRIGHTNESS: "15",
DEVICE_HARDWAREDISCOVERED: "2.0+BME280+PMSX003-B+PMSX003-A",
DEVICE_FIRMWAREVERSION: "6.01",
Version: "6.01",
LastUpdateCheck: 1600784185,
Created: 1596053038,
Uptime: "1004400",
RSSI: "-81",
Adc: "0.05",
p_0_3_um: "690.16",
p_0_5_um: "224.26",
p_1_0_um: "46.56",
p_2_5_um: "10.25",
p_5_0_um: "5.72",
p_10_0_um: "2.0",
pm1_0_cf_1: "2.91",
pm2_5_cf_1: "5.74",
pm10_0_cf_1: "9.58",
pm1_0_atm: "2.91",
pm2_5_atm: "5.74",
pm10_0_atm: "9.58",
isOwner: 0,
humidity: "63",
temp_f: "67",
pressure: "1018.12",
AGE: 0,
Stats:
'{"v":5.74,"v1":5.8,"v2":5.62,"v3":5.39,"v4":10.14,"v5":16.89,"v6":30.53,"pm":5.74,"lastModified":1600787547536,"timeSinceModified":119991}',
},
{
ID: 60334,
ParentID: 60333,
Label: "Burbank B",
THINGSPEAK_PRIMARY_ID: "1108163",
THINGSPEAK_PRIMARY_ID_READ_KEY: "ZXP2S6WL3KJ383QD",
THINGSPEAK_SECONDARY_ID: "1108164",
THINGSPEAK_SECONDARY_ID_READ_KEY: "RFQY0DTDIBZDN1N8",
Lat: 37.769549,
Lon: -122.271873,
PM2_5Value: "8.69",
LastSeen: 1600787547,
Hidden: "false",
Created: 1596053038,
p_0_3_um: "803.31",
p_0_5_um: "252.71",
p_1_0_um: "67.73",
p_2_5_um: "7.77",
p_5_0_um: "2.92",
p_10_0_um: "0.69",
pm1_0_cf_1: "4.02",
pm2_5_cf_1: "8.69",
pm10_0_cf_1: "10.54",
pm1_0_atm: "4.02",
pm2_5_atm: "8.69",
pm10_0_atm: "10.54",
isOwner: 0,
AGE: 0,
Stats:
'{"v":8.69,"v1":8.86,"v2":8.73,"v3":8.51,"v4":12.81,"v5":19.18,"v6":32.37,"pm":8.69,"lastModified":1600787547536,"timeSinceModified":119991}',
},
{
ID: 35013,
Label: "West End",
DEVICE_LOCATIONTYPE: "outside",
THINGSPEAK_PRIMARY_ID: "826054",
THINGSPEAK_PRIMARY_ID_READ_KEY: "11EFWJZTKPQXQTSL",
THINGSPEAK_SECONDARY_ID: "826055",
THINGSPEAK_SECONDARY_ID_READ_KEY: "05I2M7P85FWU5973",
Lat: 37.77325,
Lon: -122.284322,
PM2_5Value: "5.44",
LastSeen: 1600787499,
Type: "PMS5003+PMS5003+BME280",
Hidden: "false",
DEVICE_BRIGHTNESS: "15",
DEVICE_HARDWAREDISCOVERED: "2.0+BME280+PMSX003-B+PMSX003-A",
Version: "6.01",
LastUpdateCheck: 1600784017,
Created: 1563395926,
Uptime: "662400",
RSSI: "-53",
Adc: "0.04",
p_0_3_um: "712.75",
p_0_5_um: "204.15",
p_1_0_um: "47.71",
p_2_5_um: "5.91",
p_5_0_um: "0.91",
p_10_0_um: "0.44",
pm1_0_cf_1: "2.2",
pm2_5_cf_1: "5.44",
pm10_0_cf_1: "6.24",
pm1_0_atm: "2.2",
pm2_5_atm: "5.44",
pm10_0_atm: "6.24",
isOwner: 0,
humidity: "66",
temp_f: "66",
pressure: "1018.35",
AGE: 1,
Stats:
'{"v":5.44,"v1":6.28,"v2":6.24,"v3":5.98,"v4":10.44,"v5":16.99,"v6":43.12,"pm":5.44,"lastModified":1600787499682,"timeSinceModified":120141}',
},
{
ID: 35014,
ParentID: 35013,
Label: "West End B",
THINGSPEAK_PRIMARY_ID: "826056",
THINGSPEAK_PRIMARY_ID_READ_KEY: "ZWX4OBS2LTPUTGWV",
THINGSPEAK_SECONDARY_ID: "826057",
THINGSPEAK_SECONDARY_ID_READ_KEY: "OLIZTXJULMCC1KE4",
Lat: 37.77325,
Lon: -122.284322,
PM2_5Value: "7.14",
LastSeen: 1600787499,
Hidden: "false",
Created: 1563395926,
p_0_3_um: "810.11",
p_0_5_um: "234.12",
p_1_0_um: "54.89",
p_2_5_um: "7.89",
p_5_0_um: "2.5",
p_10_0_um: "1.21",
pm1_0_cf_1: "3.68",
pm2_5_cf_1: "7.14",
pm10_0_cf_1: "9.05",
pm1_0_atm: "3.68",
pm2_5_atm: "7.14",
pm10_0_atm: "9.05",
isOwner: 0,
AGE: 1,
Stats:
'{"v":7.14,"v1":7.1,"v2":6.88,"v3":6.58,"v4":10.96,"v5":17.44,"v6":42.97,"pm":7.14,"lastModified":1600787499682,"timeSinceModified":120140}',
},
],
};
export async function checkAir() {
const response = await fetch(
"https://www.purpleair.com/json?show=35013|60333"
);
if (!response.ok) {
console.error(response);
throw new Error("Not Ok");
}
const body = await response.json();
const results = body.results
.filter((obj) => obj.ParentID == null)
.map((obj) => Number(obj.PM2_5Value))
.map(aqiFromPM)
.map((aqi) => {
if (typeof aqi !== "number") {
throw new Error(`Expected AQI to be a number, but it was: "${aqi}"`);
}
return aqi;
});
const aqi = average(results);
const roundedAqi = Math.round(aqi);
const description = getAQIDescription(aqi);
const previousDescription = await getPrevious();
if (previousDescription === description) {
console.log("No change, not messaging");
return null;
}
console.log(`"${previousDescription}" !== "${description}`);
await fs.writeFile(PREVIOUS_PATH, String(description));
return `The current air quiality is "${description}" (AQI ${roundedAqi})`;
}
function aqiFromPM(pm) {
if (isNaN(pm)) return "-";
if (pm == undefined) return "-";
if (pm < 0) return pm;
if (pm > 1000) return "-";
/*
Good 0 - 50 0.0 - 15.0 0.0 12.0
Moderate 51 - 100 >15.0 - 40 12.1 35.4
Unhealthy for Sensitive Groups 101 150 >40 65 35.5 55.4
Unhealthy 151 200 > 65 150 55.5 150.4
Very Unhealthy 201 300 > 150 250 150.5 250.4
Hazardous 301 400 > 250 350 250.5 350.4
Hazardous 401 500 > 350 500 350.5 500
*/
if (pm > 350.5) {
return calcAQI(pm, 500, 401, 500, 350.5);
} else if (pm > 250.5) {
return calcAQI(pm, 400, 301, 350.4, 250.5);
} else if (pm > 150.5) {
return calcAQI(pm, 300, 201, 250.4, 150.5);
} else if (pm > 55.5) {
return calcAQI(pm, 200, 151, 150.4, 55.5);
} else if (pm > 35.5) {
return calcAQI(pm, 150, 101, 55.4, 35.5);
} else if (pm > 12.1) {
return calcAQI(pm, 100, 51, 35.4, 12.1);
} else if (pm >= 0) {
return calcAQI(pm, 50, 0, 12, 0);
} else {
return undefined;
}
}
function bplFromPM(pm) {
if (isNaN(pm)) return 0;
if (pm == undefined) return 0;
if (pm < 0) return 0;
/*
Good 0 - 50 0.0 - 15.0 0.0 12.0
Moderate 51 - 100 >15.0 - 40 12.1 35.4
Unhealthy for Sensitive Groups 101 150 >40 65 35.5 55.4
Unhealthy 151 200 > 65 150 55.5 150.4
Very Unhealthy 201 300 > 150 250 150.5 250.4
Hazardous 301 400 > 250 350 250.5 350.4
Hazardous 401 500 > 350 500 350.5 500
*/
if (pm > 350.5) {
return 401;
} else if (pm > 250.5) {
return 301;
} else if (pm > 150.5) {
return 201;
} else if (pm > 55.5) {
return 151;
} else if (pm > 35.5) {
return 101;
} else if (pm > 12.1) {
return 51;
} else if (pm >= 0) {
return 0;
} else {
return 0;
}
}
function bphFromPM(pm) {
//return 0;
if (isNaN(pm)) return 0;
if (pm == undefined) return 0;
if (pm < 0) return 0;
/*
Good 0 - 50 0.0 - 15.0 0.0 12.0
Moderate 51 - 100 >15.0 - 40 12.1 35.4
Unhealthy for Sensitive Groups 101 150 >40 65 35.5 55.4
Unhealthy 151 200 > 65 150 55.5 150.4
Very Unhealthy 201 300 > 150 250 150.5 250.4
Hazardous 301 400 > 250 350 250.5 350.4
Hazardous 401 500 > 350 500 350.5 500
*/
if (pm > 350.5) {
return 500;
} else if (pm > 250.5) {
return 500;
} else if (pm > 150.5) {
return 300;
} else if (pm > 55.5) {
return 200;
} else if (pm > 35.5) {
return 150;
} else if (pm > 12.1) {
return 100;
} else if (pm >= 0) {
return 50;
} else {
return 0;
}
}
function calcAQI(Cp, Ih, Il, BPh, BPl) {
var a = Ih - Il;
var b = BPh - BPl;
var c = Cp - BPl;
return Math.round((a / b) * c + Il);
}
function getAQIDescription(aqi) {
if (aqi >= 401) {
return "Hazardous";
} else if (aqi >= 301) {
return "Hazardous";
} else if (aqi >= 201) {
return "Very Unhealthy";
} else if (aqi >= 151) {
return "Unhealthy";
} else if (aqi >= 101) {
return "Unhealthy for Sensitive Groups";
} else if (aqi >= 51) {
return "Moderate";
} else if (aqi >= 0) {
return "Good";
} else {
return undefined;
}
}
function getAQIMessage(aqi) {
if (aqi >= 401) {
return ">401: Health alert: everyone may experience more serious health effects";
} else if (aqi >= 301) {
return "301-400: Health alert: everyone may experience more serious health effects";
} else if (aqi >= 201) {
return "201-300: Health warnings of emergency conditions. The entire population is more likely to be affected. ";
} else if (aqi >= 151) {
return "151-200: Everyone may begin to experience health effects; members of sensitive groups may experience more serious health effects.";
} else if (aqi >= 101) {
return "101-150: Members of sensitive groups may experience health effects. The general public is not likely to be affected.";
} else if (aqi >= 51) {
return "51-100: Air quality is acceptable; however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
} else if (aqi >= 0) {
return "0-50: Air quality is considered satisfactory, and air pollution poses little or no risk";
} else {
return undefined;
}
}

View file

@ -9,11 +9,12 @@ import * as Skins from "./data/skins";
import Discord from "discord.js";
import { tweet } from "./tasks/tweet";
import { addSkinFromBuffer } from "./addSkin";
import { PROJECT_ROOT } from "./config";
import fetch from "node-fetch";
import * as SkinHash from "./skinHash";
import * as Analyser from "./analyser";
import { searchIndex } from "./algolia";
import { scrapeLikeData } from "./tasks/scrapeLikes";
// import { checkAir } from "./air";
// import twilio from "twilio";
async function main() {
const client = new Discord.Client();
@ -22,6 +23,32 @@ async function main() {
try {
switch (argv._[0]) {
/*
case "air":
const message = await checkAir();
if (message == null) {
return;
}
const accountSid = "AC6074f98f735253cb970083417419bb33";
const authToken = "f16cefe5550ef4a9a149b62fa770aefd";
const client = require("twilio")(accountSid, authToken);
const result = await client.messages.create({
body: message,
from: "+12056066323",
to: "+17079710972",
});
const result2 = await client.messages.create({
body: message,
from: "+12056066323",
to: "+8059014147",
});
console.log(result2);
break;
*/
case "readme": {
const rows = await knex.raw(
'SELECT md5 FROM files LEFT JOIN skins on skins.md5 = files.skin_md5 WHERE source_attribution = "Web API" AND readme_text IS NULL;'
@ -71,9 +98,11 @@ async function main() {
}
break;
}
case "tweet":
case "tweet": {
console.log("tweet");
await tweet(client, null);
break;
}
case "metadata": {
const hash = argv._[1];
console.log(Skins.getInternetArchiveUrl(hash));
@ -132,23 +161,7 @@ async function main() {
break;
}
case "tweet-data": {
// From running `tweet.py sort`
const file = fs.readFileSync(
path.join(PROJECT_ROOT, "../tweetBot/likes.txt"),
{ encoding: "utf8" }
);
const lines = file.split("\n");
for (const line of lines) {
if (line == null || line === "") {
return;
}
const [md5, likes, tweetId] = line.split(" ");
console.log({ md5, likes, tweetId });
await Skins.setTweetInfo(md5, Number(likes), tweetId);
}
console.log("done");
await scrapeLikeData();
break;
}

View file

@ -0,0 +1,150 @@
{
"mapVersion": "0.19",
"baseVersion": "7",
"mapVersionString": "",
"results": [
{
"ID": 60333,
"Label": "Burbank",
"DEVICE_LOCATIONTYPE": "outside",
"THINGSPEAK_PRIMARY_ID": "1108161",
"THINGSPEAK_PRIMARY_ID_READ_KEY": "Y9HNPG5JGYXR5Q3A",
"THINGSPEAK_SECONDARY_ID": "1108162",
"THINGSPEAK_SECONDARY_ID_READ_KEY": "NJZ5F2M4NH9CCD6Q",
"Lat": 37.769549,
"Lon": -122.271873,
"PM2_5Value": "5.74",
"LastSeen": 1600787547,
"Type": "PMS5003+PMS5003+BME280",
"Hidden": "false",
"DEVICE_BRIGHTNESS": "15",
"DEVICE_HARDWAREDISCOVERED": "2.0+BME280+PMSX003-B+PMSX003-A",
"DEVICE_FIRMWAREVERSION": "6.01",
"Version": "6.01",
"LastUpdateCheck": 1600784185,
"Created": 1596053038,
"Uptime": "1004400",
"RSSI": "-81",
"Adc": "0.05",
"p_0_3_um": "690.16",
"p_0_5_um": "224.26",
"p_1_0_um": "46.56",
"p_2_5_um": "10.25",
"p_5_0_um": "5.72",
"p_10_0_um": "2.0",
"pm1_0_cf_1": "2.91",
"pm2_5_cf_1": "5.74",
"pm10_0_cf_1": "9.58",
"pm1_0_atm": "2.91",
"pm2_5_atm": "5.74",
"pm10_0_atm": "9.58",
"isOwner": 0,
"humidity": "63",
"temp_f": "67",
"pressure": "1018.12",
"AGE": 0,
"Stats": "{\"v\":5.74,\"v1\":5.8,\"v2\":5.62,\"v3\":5.39,\"v4\":10.14,\"v5\":16.89,\"v6\":30.53,\"pm\":5.74,\"lastModified\":1600787547536,\"timeSinceModified\":119991}"
},
{
"ID": 60334,
"ParentID": 60333,
"Label": "Burbank B",
"THINGSPEAK_PRIMARY_ID": "1108163",
"THINGSPEAK_PRIMARY_ID_READ_KEY": "ZXP2S6WL3KJ383QD",
"THINGSPEAK_SECONDARY_ID": "1108164",
"THINGSPEAK_SECONDARY_ID_READ_KEY": "RFQY0DTDIBZDN1N8",
"Lat": 37.769549,
"Lon": -122.271873,
"PM2_5Value": "8.69",
"LastSeen": 1600787547,
"Hidden": "false",
"Created": 1596053038,
"p_0_3_um": "803.31",
"p_0_5_um": "252.71",
"p_1_0_um": "67.73",
"p_2_5_um": "7.77",
"p_5_0_um": "2.92",
"p_10_0_um": "0.69",
"pm1_0_cf_1": "4.02",
"pm2_5_cf_1": "8.69",
"pm10_0_cf_1": "10.54",
"pm1_0_atm": "4.02",
"pm2_5_atm": "8.69",
"pm10_0_atm": "10.54",
"isOwner": 0,
"AGE": 0,
"Stats": "{\"v\":8.69,\"v1\":8.86,\"v2\":8.73,\"v3\":8.51,\"v4\":12.81,\"v5\":19.18,\"v6\":32.37,\"pm\":8.69,\"lastModified\":1600787547536,\"timeSinceModified\":119991}"
},
{
"ID": 35013,
"Label": "West End",
"DEVICE_LOCATIONTYPE": "outside",
"THINGSPEAK_PRIMARY_ID": "826054",
"THINGSPEAK_PRIMARY_ID_READ_KEY": "11EFWJZTKPQXQTSL",
"THINGSPEAK_SECONDARY_ID": "826055",
"THINGSPEAK_SECONDARY_ID_READ_KEY": "05I2M7P85FWU5973",
"Lat": 37.77325,
"Lon": -122.284322,
"PM2_5Value": "5.44",
"LastSeen": 1600787499,
"Type": "PMS5003+PMS5003+BME280",
"Hidden": "false",
"DEVICE_BRIGHTNESS": "15",
"DEVICE_HARDWAREDISCOVERED": "2.0+BME280+PMSX003-B+PMSX003-A",
"Version": "6.01",
"LastUpdateCheck": 1600784017,
"Created": 1563395926,
"Uptime": "662400",
"RSSI": "-53",
"Adc": "0.04",
"p_0_3_um": "712.75",
"p_0_5_um": "204.15",
"p_1_0_um": "47.71",
"p_2_5_um": "5.91",
"p_5_0_um": "0.91",
"p_10_0_um": "0.44",
"pm1_0_cf_1": "2.2",
"pm2_5_cf_1": "5.44",
"pm10_0_cf_1": "6.24",
"pm1_0_atm": "2.2",
"pm2_5_atm": "5.44",
"pm10_0_atm": "6.24",
"isOwner": 0,
"humidity": "66",
"temp_f": "66",
"pressure": "1018.35",
"AGE": 1,
"Stats": "{\"v\":5.44,\"v1\":6.28,\"v2\":6.24,\"v3\":5.98,\"v4\":10.44,\"v5\":16.99,\"v6\":43.12,\"pm\":5.44,\"lastModified\":1600787499682,\"timeSinceModified\":120141}"
},
{
"ID": 35014,
"ParentID": 35013,
"Label": "West End B",
"THINGSPEAK_PRIMARY_ID": "826056",
"THINGSPEAK_PRIMARY_ID_READ_KEY": "ZWX4OBS2LTPUTGWV",
"THINGSPEAK_SECONDARY_ID": "826057",
"THINGSPEAK_SECONDARY_ID_READ_KEY": "OLIZTXJULMCC1KE4",
"Lat": 37.77325,
"Lon": -122.284322,
"PM2_5Value": "7.14",
"LastSeen": 1600787499,
"Hidden": "false",
"Created": 1563395926,
"p_0_3_um": "810.11",
"p_0_5_um": "234.12",
"p_1_0_um": "54.89",
"p_2_5_um": "7.89",
"p_5_0_um": "2.5",
"p_10_0_um": "1.21",
"pm1_0_cf_1": "3.68",
"pm2_5_cf_1": "7.14",
"pm10_0_cf_1": "9.05",
"pm1_0_atm": "3.68",
"pm2_5_atm": "7.14",
"pm10_0_atm": "9.05",
"isOwner": 0,
"AGE": 1,
"Stats": "{\"v\":7.14,\"v1\":7.1,\"v2\":6.88,\"v3\":6.58,\"v4\":10.96,\"v5\":17.44,\"v6\":42.97,\"pm\":7.14,\"lastModified\":1600787499682,\"timeSinceModified\":120140}"
}
]
}

View file

@ -39,7 +39,7 @@ function getWebampUrl(md5: string): string {
return `https://webamp.org?skinUrl=${getSkinUrl(md5)}`;
}
function getMuseumUrl(md5: string): string {
export function getMuseumUrl(md5: string): string {
return `https://skins.webamp.org/skin/${md5}`;
}
@ -505,9 +505,24 @@ export async function setTweetInfo(
{ md5 },
{ $set: { twitterLikes: likes, tweetId } }
);
await knex("tweets")
const first = await knex("tweets")
.where({ skin_md5: md5 })
.update({ tweet_id: tweetId, likes }, []);
.first(["likes", "retweets"]);
if (first == null) {
await knex("skins").insert(
{
skin_md5: md5,
tweet_id: tweetId,
likes,
retweets,
},
[]
);
} else {
await knex("tweets")
.where({ skin_md5: md5 })
.update({ tweet_id: tweetId, likes, retweets }, []);
}
}
export async function getMuseumPage({
@ -521,11 +536,11 @@ export async function getMuseumPage({
> {
const skins = await knex.raw(
`
SELECT skins.md5,
SELECT skins.md5,
skin_reviews.review = 'NSFW' AS nsfw,
skin_reviews.review = 'APPROVED' AS approved,
skin_reviews.review = 'REJECTED' AS rejected,
tweets.likes,
(IFNULL(tweets.likes, 0) + (IFNULL(tweets.retweets,0) * 1.5)) AS tweet_score,
files.file_path,
CASE skins.md5
WHEN "5e4f10275dcb1fb211d4a8b4f1bda236" THEN 0 -- Base
@ -542,10 +557,10 @@ WHERE skin_type = 1
GROUP BY skins.md5
ORDER BY
priority ASC,
tweets.likes DESC,
tweet_score DESC,
nsfw ASC,
approved DESC,
rejected ASC
rejected ASC
LIMIT ? offset ?`,
[first, offset]
);

View file

@ -20,10 +20,13 @@
"node-fetch": "^2.6.0",
"puppeteer": "^1.17.0",
"rgb-hex": "^3.0.0",
"sharp": "^0.26.1",
"shell-escape": "^0.2.0",
"sqlite3": "^4.2.0",
"temp": "^0.9.0",
"ts-node": "^8.10.2",
"twilio": "^3.49.3",
"twit": "^2.2.11",
"twitter-api-client": "^0.2.1",
"winston": "^3.2.1",
"yargs": "^13.2.4"

View file

@ -36,6 +36,9 @@ class Shooter {
});
this._page.on("dialog", async (dialog) => {
console.log(`Page dialog ${dialog.message()}`);
if (dialog.message === "Failed to parse skin") {
// Do something!
}
await dialog.dismiss();
});
const url = `${this._url}/?screenshot=1`;

View file

@ -0,0 +1,39 @@
import { getTwitterClient } from "../twitter";
import * as Skins from "../data/skins";
import { MD5_REGEX } from "../utils";
export async function scrapeLikeData() {
const twitterClient = getTwitterClient();
const COUNT = 3200;
const tweets = await twitterClient.get("statuses/user_timeline", {
screen_name: "winampskins",
count: COUNT,
exclude_replies: true,
include_rts: false,
});
const data = tweets.data.map((tweet) => {
const md5 = tweet.entities.urls
.map(({ expanded_url }) => {
const match = expanded_url.match(MD5_REGEX);
return match != null ? match[0] : null;
})
.find(Boolean);
return {
tweetId: tweet.id_str,
md5,
likes: tweet.favorite_count,
retweets: tweet.retweet_count,
};
});
for (const tweet of data) {
const { md5, tweetId, likes, retweets } = tweet;
if (md5 == null) {
continue;
}
await Skins.setTweetInfo(md5, likes, retweets, tweetId);
}
}

View file

@ -1,37 +1,13 @@
import path from "path";
import logger from "../logger";
import fs from "fs";
import * as Skins from "../data/skins";
import { TWEET_BOT_CHANNEL_ID } from "../config";
import { spawn } from "child_process";
import { TWEET_BOT_CHANNEL_ID, TWITTER_CREDS } from "../config";
import { Client } from "discord.js";
import { SkinRecord } from "../types";
import { PROJECT_ROOT } from "../config";
function spawnPromise(command: string, args: string[]): Promise<string> {
return new Promise((resolve, reject) => {
const ls = spawn(command, args);
let stdout = "";
let stderr = "";
ls.stdout.on("data", (data) => {
stdout += data;
});
ls.stderr.on("data", (data) => {
stderr += data;
console.log(`stderr: ${data}`);
});
ls.on("close", (code) => {
console.log(`child process exited with code ${code}`);
if (code === 0) {
resolve(stdout);
} else {
reject(stderr);
}
});
});
}
import _temp from "temp";
import sharp from "sharp";
import { getTwitterClient } from "../twitter";
const temp = _temp.track();
export async function tweet(discordClient: Client, anything: string | null) {
const tweetBotChannel = discordClient.channels.get(TWEET_BOT_CHANNEL_ID);
@ -83,21 +59,14 @@ export async function tweet(discordClient: Client, anything: string | null) {
if (filename == null) {
throw new Error(`Could not find filename for skin with hash ${md5}`);
}
let output;
try {
output = await spawnPromise(
path.resolve(PROJECT_ROOT, "../tweetBot/tweet.py"),
[
"tweet",
md5,
filename, // "--dry",
]
);
output = await sendTweet(md5, filename);
} catch (e) {
console.error(e);
// @ts-ignore
await tweetBotChannel.send(
`Oops. The Python part of the twitter bot crashed: ${e.message}`
);
await tweetBotChannel.send(`Oops. Tweeting crashed: ${e.message}`);
return;
}
await Skins.markAsTweeted(md5, output.trim());
@ -110,9 +79,47 @@ export async function tweet(discordClient: Client, anything: string | null) {
`Only ${remainingSkinCount} approved skins left. Could someone please \`!review\` some more?`
);
}
logger.info("Tweeted a skin", {
md5,
filename,
url: output.trim(),
});
logger.info("Tweeted a skin", { md5, filename, url: output.trim() });
}
async function getResizedScreenshot(md5: string): Promise<Buffer> {
const screenshot = await Skins.getScreenshotBuffer(md5);
const { width, height } = await sharp(screenshot).metadata();
const image = await sharp(screenshot)
.resize(width * 2, height * 2, {
kernel: sharp.kernel.nearest,
})
.toBuffer();
return image;
}
async function sendTweet(md5: string, filename: string) {
const screenshotBuffer = await getResizedScreenshot(md5);
const tempFile = temp.path({ suffix: ".png" });
fs.writeFileSync(tempFile, screenshotBuffer);
const t = getTwitterClient();
const { media_id_string } = await new Promise((resolve, reject) => {
t.postMediaChunked({ file_path: tempFile }, (err, data) => {
if (err) {
reject(err);
return;
}
resolve(data);
});
});
const params = {
status: `${filename}\n\n${Skins.getMuseumUrl(md5)}`,
media_ids: [media_id_string],
};
const result = await t.post("statuses/update", params);
const id = result.data.id_str;
if (id == null) {
throw new Error(`Could not get id`);
}
return `https://twitter.com/winampskins/status/${result.data.id_str}`;
}

View file

@ -0,0 +1,12 @@
import { TWITTER_CREDS } from "./config";
import Twit from "twit";
export function getTwitterClient() {
return new Twit({
consumer_key: TWITTER_CREDS.apiKey,
consumer_secret: TWITTER_CREDS.apiSecret,
access_token: TWITTER_CREDS.accessToken,
access_token_secret: TWITTER_CREDS.accessTokenSecret,
strictSSL: true, // optional - requires SSL certificates to be valid.
});
}

308
yarn.lock
View file

@ -1605,6 +1605,13 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/body-parser@*":
version "1.19.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
dependencies:
"@types/connect" "*"
"@types/node" "*"
"@types/classnames@^2.2.6":
version "2.2.10"
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
@ -1613,6 +1620,12 @@
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
"@types/connect@*":
version "3.4.33"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
dependencies:
"@types/node" "*"
"@types/css-font-loading-module@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.2.tgz#09f1f1772975777e37851b7b7a4389d97c210add"
@ -1625,6 +1638,23 @@
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
"@types/express-serve-static-core@*":
version "4.17.13"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz#d9af025e925fc8b089be37423b8d1eac781be084"
dependencies:
"@types/node" "*"
"@types/qs" "*"
"@types/range-parser" "*"
"@types/express@^4.17.7":
version "4.17.8"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.8.tgz#3df4293293317e61c60137d273a2e96cd8d5f27a"
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "*"
"@types/qs" "*"
"@types/serve-static" "*"
"@types/fscreen@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/fscreen/-/fscreen-1.0.1.tgz#d924e07d0468eb056abeca41bd54e742ddce2b6d"
@ -1703,6 +1733,10 @@
version "4.14.151"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.151.tgz#7d58cac32bedb0ec37cb7f99094a167d6176c9d5"
"@types/mime@*":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@ -1734,6 +1768,18 @@
version "1.5.4"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
"@types/qs@*":
version "6.9.5"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.5.tgz#434711bdd49eb5ee69d90c1d67c354a9a8ecb18b"
"@types/qs@6.9.4":
version "6.9.4"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
"@types/rc-slider@^8.6.3":
version "8.6.5"
resolved "https://registry.yarnpkg.com/@types/rc-slider/-/rc-slider-8.6.5.tgz#5032e5a4e4074588068d4b149f9e80a5ae80d8e3"
@ -1769,6 +1815,13 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/serve-static@*":
version "1.13.5"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53"
dependencies:
"@types/express-serve-static-core" "*"
"@types/mime" "*"
"@types/source-list-map@*":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
@ -2294,6 +2347,10 @@ arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
asap@^2.0.0:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
asn1.js@^4.0.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
@ -2729,7 +2786,7 @@ bl@^4.0.1:
inherits "^2.0.4"
readable-stream "^3.4.0"
bluebird@^3.4.7, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
bluebird@^3.1.5, bluebird@^3.4.7, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@ -2909,6 +2966,10 @@ buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
buffer-fill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
@ -3370,7 +3431,7 @@ color@3.0.x:
color-convert "^1.9.1"
color-string "^1.5.2"
color@^3.0.0:
color@^3.0.0, color@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
dependencies:
@ -3911,6 +3972,10 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
dayjs@^1.8.29:
version "1.8.36"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50"
debug@*, debug@4, debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
@ -3953,6 +4018,18 @@ decompress-response@^3.2.0, decompress-response@^3.3.0:
dependencies:
mimic-response "^1.0.0"
decompress-response@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
dependencies:
mimic-response "^2.0.0"
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
dependencies:
mimic-response "^3.1.0"
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
@ -4105,7 +4182,7 @@ detect-indent@^4.0.0:
dependencies:
repeating "^2.0.0"
detect-libc@^1.0.2:
detect-libc@^1.0.2, detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@ -4358,6 +4435,12 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
ecdsa-sig-formatter@1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
dependencies:
safe-buffer "^5.0.1"
ecma-proposal-math-extensions@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz#a6a3d64819db70cee0d2e1976b6315d00e4714a0"
@ -4842,6 +4925,10 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
expand-template@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
expand-tilde@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
@ -5547,6 +5634,10 @@ git-revision-webpack-plugin@^3.0.3:
version "3.0.6"
resolved "https://registry.yarnpkg.com/git-revision-webpack-plugin/-/git-revision-webpack-plugin-3.0.6.tgz#5dd6c6829fae05b405059dea6195b23875d69d4d"
github-from-package@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
@ -7664,6 +7755,21 @@ json5@^2.1.2:
dependencies:
minimist "^1.2.5"
jsonwebtoken@^8.5.1:
version "8.5.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
dependencies:
jws "^3.2.2"
lodash.includes "^4.3.0"
lodash.isboolean "^3.0.3"
lodash.isinteger "^4.0.4"
lodash.isnumber "^3.0.3"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.once "^4.0.0"
ms "^2.1.1"
semver "^5.6.0"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@ -7693,6 +7799,21 @@ junk@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1"
jwa@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
dependencies:
buffer-equal-constant-time "1.0.1"
ecdsa-sig-formatter "1.0.11"
safe-buffer "^5.0.1"
jws@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
dependencies:
jwa "^1.4.1"
safe-buffer "^5.0.1"
keyv@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373"
@ -7894,10 +8015,38 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
lodash.isnumber@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
lodash.once@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -8238,7 +8387,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
dependencies:
mime-db "1.44.0"
mime@1.6.0, mime@^1.6.0:
mime@1.6.0, mime@^1.3.4, mime@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@ -8254,6 +8403,14 @@ mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
mimic-response@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
mimic-response@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@ -8268,7 +8425,7 @@ minimatch@^3.0.3, minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
@ -8481,6 +8638,10 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
napi-build-utils@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@ -8518,6 +8679,16 @@ no-case@^3.0.3:
lower-case "^2.0.1"
tslib "^1.10.0"
node-abi@^2.7.0:
version "2.19.1"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.19.1.tgz#6aa32561d0a5e2fdb6810d8c25641b657a8cea85"
dependencies:
semver "^5.4.1"
node-addon-api@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681"
node-environment-flags@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088"
@ -8609,6 +8780,10 @@ node-releases@^1.1.53:
version "1.1.55"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.55.tgz#8af23b7c561d8e2e6e36a46637bab84633b07cee"
noop-logger@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
nopt@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@ -8684,7 +8859,7 @@ npm-run-path@^4.0.0:
dependencies:
path-key "^3.0.0"
npmlog@^4.0.2:
npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
@ -9357,6 +9532,10 @@ pngjs@^3.0.0, pngjs@^3.3.3:
version "3.4.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
pop-iterate@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/pop-iterate/-/pop-iterate-1.0.1.tgz#ceacfdab4abf353d7a0f2aaa2c1fc7b3f9413ba3"
portfinder@^1.0.13, portfinder@^1.0.26:
version "1.0.26"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
@ -9672,6 +9851,26 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.18, postcss@^7.0.27:
source-map "^0.6.1"
supports-color "^6.1.0"
prebuild-install@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.5.tgz#e7e71e425298785ea9d22d4f958dbaccf8bb0e1b"
dependencies:
detect-libc "^1.0.3"
expand-template "^2.0.3"
github-from-package "0.0.0"
minimist "^1.2.3"
mkdirp "^0.5.1"
napi-build-utils "^1.0.1"
node-abi "^2.7.0"
noop-logger "^0.1.1"
npmlog "^4.0.1"
pump "^3.0.0"
rc "^1.2.7"
simple-get "^3.0.3"
tar-fs "^2.0.0"
tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0"
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@ -9878,6 +10077,14 @@ puppeteer@^3.0.4:
unbzip2-stream "^1.3.3"
ws "^7.2.3"
q@2.0.x:
version "2.0.3"
resolved "https://registry.yarnpkg.com/q/-/q-2.0.3.tgz#75b8db0255a1a5af82f58c3f3aaa1efec7d0d134"
dependencies:
asap "^2.0.0"
pop-iterate "^1.0.1"
weak-map "^1.0.5"
q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@ -9886,6 +10093,10 @@ qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
qs@^6.9.4:
version "6.9.4"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
qs@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
@ -10381,7 +10592,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.8:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
request@^2.87.0, request@^2.88.0, request@^2.88.2:
request@^2.68.0, request@^2.87.0, request@^2.88.0, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
dependencies:
@ -10555,6 +10766,10 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"
rootpath@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/rootpath/-/rootpath-0.1.2.tgz#5b379a87dca906e9b91d690a599439bef267ea6b"
rsvp@^4.8.4:
version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
@ -10664,6 +10879,10 @@ schema-utils@^2.6.5:
ajv "^6.12.0"
ajv-keywords "^3.4.1"
scmp@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/scmp/-/scmp-2.1.0.tgz#37b8e197c425bdeb570ab91cc356b311a11f9c9a"
screenfull@^4.0.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-4.2.1.tgz#3245b7bc73d2b7c9a15bd8caaf6965db7cbc7f04"
@ -10813,6 +11032,20 @@ shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
sharp@^0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.26.1.tgz#084e3447ba17f1baf3e3f2e08305ed7aec236ce9"
dependencies:
color "^3.1.2"
detect-libc "^1.0.3"
node-addon-api "^3.0.2"
npmlog "^4.1.2"
prebuild-install "^5.3.5"
semver "^7.3.2"
simple-get "^4.0.0"
tar-fs "^2.1.0"
tunnel-agent "^0.6.0"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@ -10852,6 +11085,26 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
simple-concat@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
simple-get@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3"
dependencies:
decompress-response "^4.2.0"
once "^1.3.1"
simple-concat "^1.0.0"
simple-get@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.0.tgz#73fa628278d21de83dadd5512d2cc1f4872bd675"
dependencies:
decompress-response "^6.0.0"
once "^1.3.1"
simple-concat "^1.0.0"
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@ -11426,7 +11679,7 @@ tapable@^1.0.0, tapable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
tar-fs@^2.0.0:
tar-fs@^2.0.0, tar-fs@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.0.tgz#d1cdd121ab465ee0eb9ccde2d35049d3f3daf0d5"
dependencies:
@ -11782,6 +12035,31 @@ tweetnacl@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
twilio@^3.49.3:
version "3.49.3"
resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.49.3.tgz#ca4191895b791e25b07dd0e82f55e8e866a1c331"
dependencies:
"@types/express" "^4.17.7"
"@types/qs" "6.9.4"
axios "^0.19.2"
dayjs "^1.8.29"
jsonwebtoken "^8.5.1"
lodash "^4.17.19"
q "2.0.x"
qs "^6.9.4"
rootpath "^0.1.2"
scmp "^2.1.0"
url-parse "^1.4.7"
xmlbuilder "^13.0.2"
twit@^2.2.11:
version "2.2.11"
resolved "https://registry.yarnpkg.com/twit/-/twit-2.2.11.tgz#554343d1cf343ddf503280db821f61be5ab407c3"
dependencies:
bluebird "^3.1.5"
mime "^1.3.4"
request "^2.68.0"
twitter-api-client@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/twitter-api-client/-/twitter-api-client-0.2.1.tgz#f766c90211827e6a62e92c6a9390eb31f6732eea"
@ -11972,7 +12250,7 @@ url-parse-lax@^3.0.0:
dependencies:
prepend-http "^2.0.0"
url-parse@^1.4.3:
url-parse@^1.4.3, url-parse@^1.4.7:
version "1.4.7"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
dependencies:
@ -12176,6 +12454,10 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies:
minimalistic-assert "^1.0.0"
weak-map@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.5.tgz#79691584d98607f5070bd3b70a40e6bb22e401eb"
webamp@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/webamp/-/webamp-1.4.0.tgz#36c0ef2621ed3d14835d8cbd58206a408903e602"
@ -12397,6 +12679,10 @@ which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
which-pm-runs@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
@ -12530,6 +12816,10 @@ xml2js@0.4.19:
sax ">=0.6.0"
xmlbuilder "~9.0.1"
xmlbuilder@^13.0.2:
version "13.0.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7"
xmlbuilder@~9.0.1:
version "9.0.7"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"