From ffa94b5c27d0b3f770cba502d5cd18d6ed72e93f Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 3 Oct 2020 16:39:55 -0400 Subject: [PATCH] Tweet from JS and scrape tweets --- packages/skin-database/air.js | 350 ++++++++++++++++++++ packages/skin-database/cli.ts | 53 +-- packages/skin-database/data.json | 150 +++++++++ packages/skin-database/data/skins.ts | 29 +- packages/skin-database/package.json | 3 + packages/skin-database/shooter.js | 3 + packages/skin-database/tasks/scrapeLikes.ts | 39 +++ packages/skin-database/tasks/tweet.ts | 99 +++--- packages/skin-database/twitter.ts | 12 + yarn.lock | 308 ++++++++++++++++- 10 files changed, 964 insertions(+), 82 deletions(-) create mode 100644 packages/skin-database/air.js create mode 100644 packages/skin-database/data.json create mode 100644 packages/skin-database/tasks/scrapeLikes.ts create mode 100644 packages/skin-database/twitter.ts diff --git a/packages/skin-database/air.js b/packages/skin-database/air.js new file mode 100644 index 00000000..1e4c44dd --- /dev/null +++ b/packages/skin-database/air.js @@ -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; + } +} diff --git a/packages/skin-database/cli.ts b/packages/skin-database/cli.ts index 367d3aae..608f7a4c 100755 --- a/packages/skin-database/cli.ts +++ b/packages/skin-database/cli.ts @@ -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; } diff --git a/packages/skin-database/data.json b/packages/skin-database/data.json new file mode 100644 index 00000000..1a42edf6 --- /dev/null +++ b/packages/skin-database/data.json @@ -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}" + } + ] +} diff --git a/packages/skin-database/data/skins.ts b/packages/skin-database/data/skins.ts index adf3e24f..c565cc1f 100644 --- a/packages/skin-database/data/skins.ts +++ b/packages/skin-database/data/skins.ts @@ -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] ); diff --git a/packages/skin-database/package.json b/packages/skin-database/package.json index 31e0e4ed..d0a150dd 100644 --- a/packages/skin-database/package.json +++ b/packages/skin-database/package.json @@ -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" diff --git a/packages/skin-database/shooter.js b/packages/skin-database/shooter.js index 4849f2a6..d77f49ab 100644 --- a/packages/skin-database/shooter.js +++ b/packages/skin-database/shooter.js @@ -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`; diff --git a/packages/skin-database/tasks/scrapeLikes.ts b/packages/skin-database/tasks/scrapeLikes.ts new file mode 100644 index 00000000..4d808640 --- /dev/null +++ b/packages/skin-database/tasks/scrapeLikes.ts @@ -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); + } +} diff --git a/packages/skin-database/tasks/tweet.ts b/packages/skin-database/tasks/tweet.ts index 957b2774..66d71caf 100644 --- a/packages/skin-database/tasks/tweet.ts +++ b/packages/skin-database/tasks/tweet.ts @@ -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 { - 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 { + 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}`; } diff --git a/packages/skin-database/twitter.ts b/packages/skin-database/twitter.ts new file mode 100644 index 00000000..969eb3a2 --- /dev/null +++ b/packages/skin-database/twitter.ts @@ -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. + }); +} diff --git a/yarn.lock b/yarn.lock index c82f1580..b09edde1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"