diff --git a/data/current_radar.jpg b/data/current_radar.jpg deleted file mode 100644 index 4ba0eb0..0000000 Binary files a/data/current_radar.jpg and /dev/null differ diff --git a/package-lock.json b/package-lock.json index 2588be6..5af962b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "express": "^4.19.2", "formdata-node": "^6.0.3", "node-fetch": "^3.3.2", + "node-html-parser": "^6.1.13", "uuid": "^10.0.0" } }, @@ -71,6 +72,11 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -140,6 +146,32 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -197,6 +229,57 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -210,6 +293,17 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -470,6 +564,14 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -608,6 +710,26 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", diff --git a/package.json b/package.json index ee0a426..847967d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "express": "^4.19.2", "formdata-node": "^6.0.3", "node-fetch": "^3.3.2", + "node-html-parser": "^6.1.13", "uuid": "^10.0.0" } } diff --git a/src/api/fetch.cjs b/src/api/fetch.cjs index 6d5eafd..dda13e0 100644 --- a/src/api/fetch.cjs +++ b/src/api/fetch.cjs @@ -1,40 +1,58 @@ -async function get_radar_image() { - try { - let radar_src = "https://weather.bangkok.go.th/Images/Radar/radarh.jpg" - const radar_image = await axios.get(radar_src, { - responseType: "stream" - }); +const fs = require('fs'); +const util = require('util'); +const stream = require('stream'); +const pipeline = util.promisify(stream.pipeline);'' - const radar_image_size = radar_image.headers['content-length']; - console.log("Got Radar Data"); - return [radar_image, radar_image_size]; +const axios = require('axios'); +const html_parser = require('node-html-parser'); + + +async function get_image_size(url) { + try { + const image = await axios.get(url); + return image.headers['content-length']; } catch (error) { console.error(error); - return [error]; + return error; } } -async function get_image(url) { +async function save_image(url, path) { + /* try { + const image = await axios.get(url, { + responseType: "stream" + }); + + image.data.pipe(fs.createWriteStream(path)); + + const image_size = image.headers['content-length']; + return image_size; + } catch (error) { + console.error(error); + return error; + } */ + try { const image = await axios.get(url, { responseType: "stream" }); - const image_size = image.headers['content-length']; - console.log("Got Radar Data"); - return [image, image_size]; + await pipeline(image.data, fs.createWriteStream(path)); + console.log("Image downloaded successfully"); } catch (error) { - + console.error("Imae download failed: ", error); + return error; } } async function get_radar_caption() { const response = await axios.get('https://weather.bangkok.go.th/Radar/RadarHighResolution.aspx'); - let root = parse(response.data); + let root = html_parser.parse(response.data); console.log("Got Radar Caption") return root.querySelector('#repeaDaily_lblDESCRIPTION_0').childNodes[0]._rawText; } -module.exports.get_radar_image = get_radar_image; +module.exports.get_image_size = get_image_size; +module.exports.save_image = save_image; module.exports.get_radar_caption = get_radar_caption; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 170c293..8c7536f 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,6 @@ import { v4 as uuidv4 } from 'uuid'; import fs from 'node:fs'; import path from 'node:path'; import express from 'express'; -import { pipeline } from 'node:stream/promises'; import * as Post from './api/post.cjs'; import * as Auth from './api/auth.cjs'; @@ -74,37 +73,66 @@ app.get('/callback', function(req, res) { access_token = credentials.token; } - (async function post() { + let lap = 0; + + let static_image_url = "https://weather.bangkok.go.th/Images/Radar/radarh.jpg"; + let animated_image_url = "https://dds.bangkok.go.th/Radar/radar_rain.gif"; + + let static_radar_path = path.join(__dirname, '/data/static_radar.jpg'); + let animated_radar_path = path.join(__dirname, '/data/animated_radar.gif'); + await Fetch.get_image_size(static_image_url); + + if(!fs.existsSync(static_radar_path)) { + await Fetch.save_image(static_image_url, static_radar_path); + } + + async function post() { + lap += 1; + console.log(lap); let raw_date = new Date(); - let static_radar_path = path.join(__dirname, '/data/static_radar.jpg'); - let animated_radar_path = path.join(__dirname, '/data/animated_radar.gif'); - let fetch_static_image = await Fetch.get_image("https://weather.bangkok.go.th/Images/Radar/radarh.jpg"); - await pipeline( - fetch_static_image[0], - fs.createWriteStream(static_radar_path) - ); + let curr_static_image_size = fs.statSync(static_radar_path).size; + let fetch_static_image_size = await Fetch.get_image_size(static_image_url); - let fetch_animated_image = await Fetch.get_image("https://dds.bangkok.go.th/Radar/radar_rain.gif"); - await pipeline( - fetch_animated_image[0], - fs.createWriteStream(animated_radar_path) - ); + console.log("Current size: " + curr_static_image_size); + console.log("Scanned size: " + fetch_static_image_size); + + if(fetch_static_image_size != curr_static_image_size) { + console.log("File size change detected!"); + await Fetch.save_image(static_image_url, static_radar_path); + await Fetch.save_image(animated_image_url, animated_radar_path); - let static_radar_image_name = `${raw_date.toISOString()}.jpg`; - const upload_radar_image = await Post.create_image(host, access_token, static_radar_image_name, static_radar_path); + // Fetch static image + let static_radar_image_name = `${raw_date.toISOString()}.jpg`; + const upload_static_radar = await Post.create_image(host, access_token, static_radar_image_name, static_radar_path); + + // Fetch animated image + let animated_radar_image_name = `${raw_date.toISOString()}.gif`; + const upload_gif_radar = await Post.create_image(host, access_token, animated_radar_image_name, animated_radar_path); - let note_caption = `$[x2 Bangkok Raindar Update]\n**${raw_date.toLocaleString('th-TH')}**\nLeft: Current Observation\nRight: 3 hour forecast` - const post_note = await Post.create_note( - host, - access_token, - note_caption, - [upload_radar_image.id], - "public" - ) + let radar_caption = await Fetch.get_radar_caption(); + let note_caption = `$[x2 Bangkok Raindar Update]\n**${raw_date.toLocaleString('th-TH')}**\n\n${radar_caption}\n\nLeft: Current Observation\nRight: 3 hour forecast\n\n#bangkok #weather #bangkokweather` + const post_note = await Post.create_note( + host, + access_token, + note_caption, + [upload_static_radar.id, upload_gif_radar.id], + "public" + ) + + if(post_note.createdNote) { + console.log("Note created!"); + } else { + console.log("Note was not created"); + } - setInterval(post, 60000); - })(); + } else { + console.log("No change in data, go on."); + } + } + + post(); + setInterval(post, 30000); })(); app.listen(port);