From ba442bdd4298886b75dabc755ca3f6c1ba3a40be Mon Sep 17 00:00:00 2001 From: ilim Date: Sat, 1 Dec 2018 21:13:32 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=E7=B7=B4=E7=BF=92=E3=81=A8=E3=81=97?= =?UTF-8?q?=E3=81=A6Photo=20API=E3=81=A7album=E4=B8=80=E8=A6=A7=E3=82=92?= =?UTF-8?q?=E5=8F=96=E5=BE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 62 ++++- oauth2.keys.json | 6 + package-lock.json | 608 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 8 +- 4 files changed, 681 insertions(+), 3 deletions(-) create mode 100644 oauth2.keys.json diff --git a/app.js b/app.js index 3918c74..3a14401 100644 --- a/app.js +++ b/app.js @@ -1 +1,61 @@ -"use strict"; +'use strict'; + +const {google} = require('googleapis'); +const path = require('path'); +const fs = require('fs'); +const readlineSync = require('readline-sync'); +const request = require('request'); + +async function example_get(oauth2Client) { + const accessToken = await oauth2Client.getAccessToken(); + + const headers = { + 'Content-Type': 'application/application/json' + }; + + const options = { + url: 'https://photoslibrary.googleapis.com/v1/albums', + method: 'GET', + headers: headers, + json: true, + auth: { + bearer: accessToken.token + } + }; + + request(options, (error, response, body) => { + console.log(body); + }) +} + +async function main() { + const keyPath = path.join(__dirname, 'oauth2.keys.json'); + let keys = {}; + if (fs.existsSync(keyPath)) { + keys = require(keyPath).web; + } + + const oauth2Client = new google.auth.OAuth2( + keys.client_id, + keys.client_secret, + 'urn:ietf:wg:oauth:2.0:oob' + ); + + const scopes = [ + 'https://www.googleapis.com/auth/photoslibrary' + ]; + + const url = oauth2Client.generateAuthUrl({ + access_type: 'offline', + scope: scopes + }); + console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${url}`); + const authorizationCode = readlineSync.question('入力: '); + + const {tokens} = await oauth2Client.getToken(authorizationCode); + oauth2Client.setCredentials(tokens); + + example_get(oauth2Client); +} + +main().catch(console.error); \ No newline at end of file diff --git a/oauth2.keys.json b/oauth2.keys.json new file mode 100644 index 0000000..3a0711a --- /dev/null +++ b/oauth2.keys.json @@ -0,0 +1,6 @@ +{ + "web": { + "client_id": "", + "client_secret": "" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 54dcaa0..d3a7a39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,611 @@ { "name": "bushitsuchan-pc", "version": "1.0.0", - "lockfileVersion": 1 + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", + "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", + "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "gcp-metadata": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", + "integrity": "sha512-ffjC09amcDWjh3VZdkDngIo7WoluyC5Ag9PAYxZbmQLOLNI8lvPtoKTSCyU54j2gwy5roZh6sSMTfkY2ct7K3g==", + "requires": { + "axios": "^0.18.0", + "extend": "^3.0.1", + "retry-axios": "0.3.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "google-auth-library": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.1.tgz", + "integrity": "sha512-CWLKZxqYw4SE+fE3GWbVT9r/10h75w8lB3cdmmLpLtCfccFDcsI84qI5rx7npemlrHtKJh3C2HUz4s6SihCeIQ==", + "requires": { + "axios": "^0.18.0", + "gcp-metadata": "^0.7.0", + "gtoken": "^2.3.0", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lodash.isstring": "^4.0.1", + "lru-cache": "^4.1.3", + "semver": "^5.5.0" + } + }, + "google-p12-pem": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.2.tgz", + "integrity": "sha512-+EuKr4CLlGsnXx4XIJIVkcKYrsa2xkAmCvxRhX2HsazJzUBAJ35wARGeApHUn4nNfPD03Vl057FskNr20VaCyg==", + "requires": { + "node-forge": "^0.7.4", + "pify": "^3.0.0" + } + }, + "googleapis": { + "version": "35.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-35.0.0.tgz", + "integrity": "sha512-HseVyK5CVwFM+x+uHqkbKxDRuaMVkYyfAM7Buz3X44/BglHWtzOrtffRVoQORLQHVf4kzhJcjmUvVTwfOG6klA==", + "requires": { + "google-auth-library": "^2.0.0", + "googleapis-common": "^0.4.0" + } + }, + "googleapis-common": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-0.4.0.tgz", + "integrity": "sha512-G8U5eUhmCzvZa80BtfcL2ECPiIJxmJYsPPIY3/9iODrIvDkY75wtxnEobG7HDUprtn/3Es6mP6KevqNZ5u6t4g==", + "requires": { + "axios": "^0.18.0", + "google-auth-library": "^2.0.0", + "pify": "^4.0.0", + "qs": "^6.5.2", + "url-template": "^2.0.8", + "uuid": "^3.2.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, + "gtoken": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/gtoken/-/gtoken-2.3.0.tgz", + "integrity": "sha512-Jc9/8mV630cZE9FC5tIlJCZNdUjwunvlwOtCz6IDlaiB4Sz68ki29a1+q97sWTnTYroiuF9B135rod9zrQdHLw==", + "requires": { + "axios": "^0.18.0", + "google-p12-pem": "^1.0.0", + "jws": "^3.1.4", + "mime": "^2.2.0", + "pify": "^3.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jwa": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", + "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.10", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", + "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", + "requires": { + "jwa": "^1.1.5", + "safe-buffer": "^5.0.1" + } + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==" + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "requires": { + "mime-db": "~1.37.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node-forge": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", + "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", + "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" + }, + "readline-sync": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", + "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "retry-axios": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", + "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + }, + "sshpk": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", + "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } } diff --git a/package.json b/package.json index 17c1619..bf711b4 100644 --- a/package.json +++ b/package.json @@ -16,5 +16,11 @@ "bugs": { "url": "https://github.com/TUS-OSK/bushitsuchan-PC/issues" }, - "homepage": "https://github.com/TUS-OSK/bushitsuchan-PC#readme" + "homepage": "https://github.com/TUS-OSK/bushitsuchan-PC#readme", + "dependencies": { + "googleapis": "^35.0.0", + "path": "^0.12.7", + "readline-sync": "^1.4.9", + "request": "^2.88.0" + } } From 5c4a44e9a80da3f684029645fa1ed14809fc1583 Mon Sep 17 00:00:00 2001 From: ilim Date: Mon, 3 Dec 2018 00:10:31 +0900 Subject: [PATCH 02/11] =?UTF-8?q?API=E3=82=92=E4=BD=BF=E3=81=A3=E3=81=A6up?= =?UTF-8?q?load=E3=81=99=E3=82=8B=E9=83=A8=E5=88=86=E3=81=AE=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 63 +++++++++++++++++++++++++++++++++++----------------- package.json | 2 +- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/app.js b/app.js index 3a14401..430ac79 100644 --- a/app.js +++ b/app.js @@ -3,39 +3,43 @@ const {google} = require('googleapis'); const path = require('path'); const fs = require('fs'); -const readlineSync = require('readline-sync'); +const readline = require('readline'); const request = require('request'); -async function example_get(oauth2Client) { - const accessToken = await oauth2Client.getAccessToken(); - +async function example_upload(token, image, callback) { const headers = { - 'Content-Type': 'application/application/json' + 'Content-Type': 'application/octet-stream', + 'X-Goog-Upload-File-Name': 'FILENAME', + 'X-Goog-Upload-Protocol': 'raw', }; const options = { - url: 'https://photoslibrary.googleapis.com/v1/albums', - method: 'GET', + url: 'https://photoslibrary.googleapis.com/v1/uploads', + method: 'POST', headers: headers, json: true, auth: { - bearer: accessToken.token + bearer: token.token + }, + body: { + MEDIA_BINARY_DATA: image } }; - request(options, (error, response, body) => { - console.log(body); - }) + await request(options, (error, response, body) => { + callback(body); + }); } -async function main() { +async function getToken(callback) { const keyPath = path.join(__dirname, 'oauth2.keys.json'); + const TOKEN_PATH = path.join(__dirname, 'token.json'); let keys = {}; if (fs.existsSync(keyPath)) { keys = require(keyPath).web; } - const oauth2Client = new google.auth.OAuth2( + const oAuth2Client = new google.auth.OAuth2( keys.client_id, keys.client_secret, 'urn:ietf:wg:oauth:2.0:oob' @@ -44,18 +48,37 @@ async function main() { const scopes = [ 'https://www.googleapis.com/auth/photoslibrary' ]; - - const url = oauth2Client.generateAuthUrl({ + const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: scopes }); - console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${url}`); - const authorizationCode = readlineSync.question('入力: '); - const {tokens} = await oauth2Client.getToken(authorizationCode); - oauth2Client.setCredentials(tokens); + console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${authUrl}`); - example_get(oauth2Client); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + await rl.question('入力: ', (authorizationCode) => { + rl.close(); + oAuth2Client.getToken(authorizationCode).then(value => { + const token = value.tokens; + oAuth2Client.setCredentials(token); + // fs.writeFile(TOKEN_PATH, JSON.stringify(token), console.error); + oAuth2Client.getAccessToken().then(callback); + }).catch(console.error); + }); +} + + +async function main() { + await getToken((token) => { + const image = fs.readFileSync('sample.png'); + const base64_data = "data:image/jpeg;base64," + image.toString('base64'); + const uploadToken = example_upload(token, base64_data, (uploadToken) => { + console.log('uploadToken: ', uploadToken) + }); + }); } main().catch(console.error); \ No newline at end of file diff --git a/package.json b/package.json index bf711b4..6b3bd40 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "googleapis": "^35.0.0", "path": "^0.12.7", - "readline-sync": "^1.4.9", + "readline-promise": "^1.0.3", "request": "^2.88.0" } } From 9c6a1ca0b2c17ed0506f656f4d52e9aa7342b557 Mon Sep 17 00:00:00 2001 From: ilim Date: Mon, 3 Dec 2018 19:15:58 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E6=95=B4=E7=90=86&README=E3=81=AE?= =?UTF-8?q?=E8=BF=BD=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +++++- app.js | 85 +------------------------------ package-lock.json | 42 +++++++++++++-- package.json | 5 +- photoAPI.js | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 91 deletions(-) create mode 100644 photoAPI.js diff --git a/README.md b/README.md index 9fc6b65..3d9c3d6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ # bushitsuchan-PC OSKの部室の様子を様子をオンラインで確認できるプロジェクト 部室ちゃん. -その部室に置いてあるPC側で動かすプログラム. \ No newline at end of file +その部室に置いてあるPC側で動かすプログラム. + +## Google Photos APIs を使えようにする +1. [Photos Library API](https://console.developers.google.com/apis/library/photoslibrary.googleapis.com)を有効にする. +1. [認証情報](https://console.developers.google.com/apis/credentials)でOAuth クライアント IDを作成する (アプリケーションの種類 は その他) +1. 作成した`クライアント ID`と`クライアント シークレット`を`oauth2.keys.json`に以下のように保存する + +```json:oauth2.keys.json +{ + "web": { + "client_id": "477...oav.apps.googleusercontent.com", + "client_secret": "yEP..." + } +} +``` \ No newline at end of file diff --git a/app.js b/app.js index 430ac79..a726efc 100644 --- a/app.js +++ b/app.js @@ -1,84 +1 @@ -'use strict'; - -const {google} = require('googleapis'); -const path = require('path'); -const fs = require('fs'); -const readline = require('readline'); -const request = require('request'); - -async function example_upload(token, image, callback) { - const headers = { - 'Content-Type': 'application/octet-stream', - 'X-Goog-Upload-File-Name': 'FILENAME', - 'X-Goog-Upload-Protocol': 'raw', - }; - - const options = { - url: 'https://photoslibrary.googleapis.com/v1/uploads', - method: 'POST', - headers: headers, - json: true, - auth: { - bearer: token.token - }, - body: { - MEDIA_BINARY_DATA: image - } - }; - - await request(options, (error, response, body) => { - callback(body); - }); -} - -async function getToken(callback) { - const keyPath = path.join(__dirname, 'oauth2.keys.json'); - const TOKEN_PATH = path.join(__dirname, 'token.json'); - let keys = {}; - if (fs.existsSync(keyPath)) { - keys = require(keyPath).web; - } - - const oAuth2Client = new google.auth.OAuth2( - keys.client_id, - keys.client_secret, - 'urn:ietf:wg:oauth:2.0:oob' - ); - - const scopes = [ - 'https://www.googleapis.com/auth/photoslibrary' - ]; - const authUrl = oAuth2Client.generateAuthUrl({ - access_type: 'offline', - scope: scopes - }); - - console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${authUrl}`); - - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - await rl.question('入力: ', (authorizationCode) => { - rl.close(); - oAuth2Client.getToken(authorizationCode).then(value => { - const token = value.tokens; - oAuth2Client.setCredentials(token); - // fs.writeFile(TOKEN_PATH, JSON.stringify(token), console.error); - oAuth2Client.getAccessToken().then(callback); - }).catch(console.error); - }); -} - - -async function main() { - await getToken((token) => { - const image = fs.readFileSync('sample.png'); - const base64_data = "data:image/jpeg;base64," + image.toString('base64'); - const uploadToken = example_upload(token, base64_data, (uploadToken) => { - console.log('uploadToken: ', uploadToken) - }); - }); -} - -main().catch(console.error); \ No newline at end of file +'use strict'; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d3a7a39..e2b898c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,6 +68,11 @@ "tweetnacl": "^0.14.3" } }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -371,6 +376,11 @@ "safe-buffer": "^5.0.1" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", @@ -462,10 +472,10 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" }, - "readline-sync": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", - "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" + "readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=" }, "request": { "version": "2.88.0", @@ -501,6 +511,25 @@ } } }, + "request-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", + "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "^4.13.1" + } + }, "retry-axios": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", @@ -537,6 +566,11 @@ "tweetnacl": "~0.14.0" } }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", diff --git a/package.json b/package.json index 6b3bd40..8fa735c 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "dependencies": { "googleapis": "^35.0.0", "path": "^0.12.7", - "readline-promise": "^1.0.3", - "request": "^2.88.0" + "readline": "^1.3.0", + "request": "^2.88.0", + "request-promise": "^4.2.2" } } diff --git a/photoAPI.js b/photoAPI.js new file mode 100644 index 0000000..4a141f1 --- /dev/null +++ b/photoAPI.js @@ -0,0 +1,127 @@ +'use strict'; + +const fs = require('fs'); +const {google} = require("googleapis"); +const readline = require("readline"); +const path = require("path"); +const rp = require('request-promise'); + +const rpap = rp.defaults({ + transform: (body, response, resolveWithFullResponse) => { + const constentType = response.headers['content-type'].split(';')[0]; + if (constentType === 'application/json') { + return JSON.parse(body); + } else if (constentType === 'text/plain') { + return body; + } else { + return body; + } + } +}); + +async function getOAuthToken() { + const keyPath = path.join(__dirname, 'oauth2.keys.json'); + let keys = {}; + if (fs.existsSync(keyPath)) { + keys = require(keyPath).web; + } + + const oAuth2Client = new google.auth.OAuth2( + keys["client_id"], + keys["client_secret"], + 'urn:ietf:wg:oauth:2.0:oob' + ); + + const scopes = [ + 'https://www.googleapis.com/auth/photoslibrary' + ]; + const authURL = oAuth2Client.generateAuthUrl({ + access_type: 'offline', + scope: scopes + }); + + console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${authURL}`); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + return new Promise((resolve) => rl.question('入力: ', resolve)) + .then((authorizationCode) => { + rl.close(); + return oAuth2Client.getToken(authorizationCode); + }) + .then(value => { + const token = value.tokens; + oAuth2Client.setCredentials(token); + return oAuth2Client.getAccessToken(); + }); +} + +async function getAlbumList(oAuthToken) { + const url = "https://photoslibrary.googleapis.com/v1/albums"; + const headers = { + "Content-type": "application/json", + Authorization: `Bearer ${oAuthToken}` + }; + const response = await rpap(url, + { + method: "GET", + headers: headers + }); + return response["albums"] +} + +async function uploadPhoto(oAuthToken, photo, filename) { + const url = "https://photoslibrary.googleapis.com/v1/uploads"; + const headers = { + Authorization: `Bearer ${oAuthToken}`, + "Content-type": "application/octet-stream", + "X-Goog-Upload-File-Name": filename, + "X-Goog-Upload-Protocol": "raw" + }; + return await rpap(url, { + method: "POST", + headers: headers, + body: photo + }); +} + +async function createMediaItem(oAuthToken, uploadToken, description) { + const url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"; + const headers = { + "Content-type": "application/json", + Authorization: `Bearer ${oAuthToken}` + }; + const body = { + "newMediaItems": [ + { + "description": description, + "simpleMediaItem": { + "uploadToken": uploadToken + } + } + ] + }; + const response = await rpap(url, { + method: "POST", + headers: headers, + body: JSON.stringify(body) + }); + return response["newMediaItemResults"]; +} + +async function main() { + const {token} = await getOAuthToken(); + // const token = ''; + console.log(token); + const photo = fs.createReadStream('sample.png'); + const uploadToken = await uploadPhoto(token, photo, "sample.png"); + const response = await createMediaItem(token, uploadToken, "discription_example"); + console.log(response); +} + +if (require.main === module) { + main().catch(console.error); +} \ No newline at end of file From b27573f1be8fa27e6057178fad0e3023d2e56cf2 Mon Sep 17 00:00:00 2001 From: ilim Date: Mon, 3 Dec 2018 22:05:49 +0900 Subject: [PATCH 04/11] =?UTF-8?q?token=E3=82=92=E5=86=8D=E5=88=A9=E7=94=A8?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4?= =?UTF-8?q?&JSDoc=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- photoAPI.js | 76 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/photoAPI.js b/photoAPI.js index 4a141f1..6140dcf 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -6,6 +6,7 @@ const readline = require("readline"); const path = require("path"); const rp = require('request-promise'); + const rpap = rp.defaults({ transform: (body, response, resolveWithFullResponse) => { const constentType = response.headers['content-type'].split(';')[0]; @@ -19,34 +20,44 @@ const rpap = rp.defaults({ } }); +/** + @typedef {Object} OAuth2Client + @property {Function} getAccessToken + */ + +/** + * @returns {Promise} + */ async function getOAuthToken() { const keyPath = path.join(__dirname, 'oauth2.keys.json'); let keys = {}; if (fs.existsSync(keyPath)) { keys = require(keyPath).web; } - const oAuth2Client = new google.auth.OAuth2( keys["client_id"], keys["client_secret"], 'urn:ietf:wg:oauth:2.0:oob' ); - const scopes = [ 'https://www.googleapis.com/auth/photoslibrary' ]; + + const tokenPath = path.join(__dirname, 'token.json'); + if (fs.existsSync(tokenPath)) { + oAuth2Client.setCredentials(require(tokenPath)); + return oAuth2Client; + } const authURL = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: scopes }); - console.log(`以下のファイルを開き,認証したあと表示される文字列をここに貼り付けてください\n${authURL}`); - + console.log(`以下のサイトを開き,認証したあと表示される文字列をここに貼り付けてください\n${authURL}`); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); - return new Promise((resolve) => rl.question('入力: ', resolve)) .then((authorizationCode) => { rl.close(); @@ -55,28 +66,41 @@ async function getOAuthToken() { .then(value => { const token = value.tokens; oAuth2Client.setCredentials(token); - return oAuth2Client.getAccessToken(); + fs.writeFileSync(tokenPath, JSON.stringify(token)); + }).then(() => { + return oAuth2Client; }); } -async function getAlbumList(oAuthToken) { +/** + * @param {OAuth2Client} oAuth2Client + * @returns {Promise>} + */ +async function getAlbumList(oAuth2Client) { + const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/albums"; const headers = { "Content-type": "application/json", - Authorization: `Bearer ${oAuthToken}` + Authorization: `Bearer ${accessToken.token}` }; - const response = await rpap(url, - { - method: "GET", - headers: headers - }); + const response = await rpap(url, { + method: "GET", + headers: headers + }); return response["albums"] } -async function uploadPhoto(oAuthToken, photo, filename) { +/** + * @param {OAuth2Client} oAuth2Client + * @param {fs.ReadStream} photo + * @param {string} filename + * @returns {Promise} + */ +async function uploadPhoto(oAuth2Client, photo, filename) { + const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/uploads"; const headers = { - Authorization: `Bearer ${oAuthToken}`, + Authorization: `Bearer ${accessToken.token}`, "Content-type": "application/octet-stream", "X-Goog-Upload-File-Name": filename, "X-Goog-Upload-Protocol": "raw" @@ -88,11 +112,18 @@ async function uploadPhoto(oAuthToken, photo, filename) { }); } -async function createMediaItem(oAuthToken, uploadToken, description) { +/** + * @param {OAuth2Client} oAuth2Client + * @param {string} uploadToken + * @param {string} description + * @returns {Promise>} + */ +async function createMediaItem(oAuth2Client, uploadToken, description) { + const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"; const headers = { "Content-type": "application/json", - Authorization: `Bearer ${oAuthToken}` + Authorization: `Bearer ${accessToken.token}` }; const body = { "newMediaItems": [ @@ -113,13 +144,10 @@ async function createMediaItem(oAuthToken, uploadToken, description) { } async function main() { - const {token} = await getOAuthToken(); - // const token = ''; - console.log(token); - const photo = fs.createReadStream('sample.png'); - const uploadToken = await uploadPhoto(token, photo, "sample.png"); - const response = await createMediaItem(token, uploadToken, "discription_example"); - console.log(response); + const oAuth2Client = await getOAuthToken(); + const uploadToken = await uploadPhoto(oAuth2Client, fs.createReadStream('sample.jpeg'), "sample.jpeg"); + const response = await createMediaItem(oAuth2Client, uploadToken, "discription_example"); + console.log(response[0]["mediaItem"].productUrl); } if (require.main === module) { From 67e9163b955761fe16052dca78e204db01eb1b4f Mon Sep 17 00:00:00 2001 From: ilim Date: Wed, 5 Dec 2018 16:32:51 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=E5=85=B1=E6=9C=89=E3=83=AA=E3=83=B3?= =?UTF-8?q?=E3=82=AF=E3=82=92=E5=8F=96=E5=BE=97=E3=81=A7=E3=81=8D=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++ photoAPI.js | 145 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 132 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e..bbfaaa7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ node_modules +token.json +oauth2.keys.json +sample.png \ No newline at end of file diff --git a/photoAPI.js b/photoAPI.js index 6140dcf..db67f0b 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -1,18 +1,19 @@ -'use strict'; +"use strict"; -const fs = require('fs'); +const fs = require("fs"); const {google} = require("googleapis"); const readline = require("readline"); const path = require("path"); -const rp = require('request-promise'); +const rp = require("request-promise"); +// const assert = require("assert"); const rpap = rp.defaults({ transform: (body, response, resolveWithFullResponse) => { - const constentType = response.headers['content-type'].split(';')[0]; - if (constentType === 'application/json') { + const constentType = response.headers["content-type"].split(";")[0]; + if (constentType === "application/json") { return JSON.parse(body); - } else if (constentType === 'text/plain') { + } else if (constentType === "text/plain") { return body; } else { return body; @@ -29,7 +30,7 @@ const rpap = rp.defaults({ * @returns {Promise} */ async function getOAuthToken() { - const keyPath = path.join(__dirname, 'oauth2.keys.json'); + const keyPath = path.join(__dirname, "oauth2.keys.json"); let keys = {}; if (fs.existsSync(keyPath)) { keys = require(keyPath).web; @@ -37,19 +38,20 @@ async function getOAuthToken() { const oAuth2Client = new google.auth.OAuth2( keys["client_id"], keys["client_secret"], - 'urn:ietf:wg:oauth:2.0:oob' + "urn:ietf:wg:oauth:2.0:oob" ); const scopes = [ - 'https://www.googleapis.com/auth/photoslibrary' + "https://www.googleapis.com/auth/photoslibrary", + "https://www.googleapis.com/auth/photoslibrary.sharing" ]; - const tokenPath = path.join(__dirname, 'token.json'); + const tokenPath = path.join(__dirname, "token.json"); if (fs.existsSync(tokenPath)) { oAuth2Client.setCredentials(require(tokenPath)); return oAuth2Client; } const authURL = oAuth2Client.generateAuthUrl({ - access_type: 'offline', + access_type: "offline", scope: scopes }); @@ -58,7 +60,7 @@ async function getOAuthToken() { input: process.stdin, output: process.stdout, }); - return new Promise((resolve) => rl.question('入力: ', resolve)) + return new Promise((resolve) => rl.question("入力: ", resolve)) .then((authorizationCode) => { rl.close(); return oAuth2Client.getToken(authorizationCode); @@ -92,7 +94,7 @@ async function getAlbumList(oAuth2Client) { /** * @param {OAuth2Client} oAuth2Client - * @param {fs.ReadStream} photo + * @param {ReadStream} photo * @param {string} filename * @returns {Promise} */ @@ -143,11 +145,122 @@ async function createMediaItem(oAuth2Client, uploadToken, description) { return response["newMediaItemResults"]; } +/** + * @param {OAuth2Client} oAuth2Client + * @param {string} albumID + * @param {string} uploadToken + * @param {string} description + * @returns {Promise} + */ +async function createAlbumMediaItem(oAuth2Client, albumID, uploadToken, description) { + const accessToken = await oAuth2Client.getAccessToken(); + const url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"; + const headers = { + "Content-type": "application/json", + Authorization: `Bearer ${accessToken.token}` + }; + const body = { + "albumId": albumID, + "newMediaItems": [ + { + "description": description, + "simpleMediaItem": { + "uploadToken": uploadToken + } + } + ] + }; + const response = await rpap(url, { + method: "POST", + headers: headers, + body: JSON.stringify(body) + }); + return response["newMediaItemResults"][0]; +} + +/** + * @param {OAuth2Client} oAuth2Client + * @param {string} title + * @returns {Promise} + */ +async function createAlbum(oAuth2Client, title) { + const accessToken = await oAuth2Client.getAccessToken(); + const url = "https://photoslibrary.googleapis.com/v1/albums"; + const headers = { + "Constent-type": "application/json", + Authorization: `Bearer ${accessToken.token}` + }; + const body = { + album: { + title: title + } + }; + return await rpap(url, { + method: "POST", + headers: headers, + body: JSON.stringify(body) + }); +} + +/** + * @param {OAuth2Client} oAuth2Client + * @param {string} albumID + * @returns {Promise} + */ +async function shareAlbum(oAuth2Client, albumID) { + const accessToken = await oAuth2Client.getAccessToken(); + const url = `https://photoslibrary.googleapis.com/v1/albums/${albumID}:share`; + const headers = { + "Constent-type": "application/json", + Authorization: `Bearer ${accessToken.token}` + }; + const body = { + "sharedAlbumOptions": { + "isCollaborative": "true", + "isCommentable": "true" + } + }; + return await rpap(url, { + method: "POST", + headers: headers, + body: JSON.stringify(body) + }); +} + +/** + * @param {OAuth2Client} oAuth2Client + * @param {string} mediaItemID + * @returns {Promise} + */ +async function getMediaItem(oAuth2Client, mediaItemID) { + const accessToken = await oAuth2Client.getAccessToken(); + const url = `https://photoslibrary.googleapis.com/v1/mediaItems/${mediaItemID}`; + const headers = { + "Constent-type": "application/json", + Authorization: `Bearer ${accessToken.token}` + }; + return await rpap(url, { + method: "GET", + headers: headers, + }); +} + async function main() { const oAuth2Client = await getOAuthToken(); - const uploadToken = await uploadPhoto(oAuth2Client, fs.createReadStream('sample.jpeg'), "sample.jpeg"); - const response = await createMediaItem(oAuth2Client, uploadToken, "discription_example"); - console.log(response[0]["mediaItem"].productUrl); + + const albumTitle = "bushitsuchan_test_album"; + const albums = await getAlbumList(oAuth2Client); + let album = albums.filter((album) => album.title === albumTitle); + if (!album.length) { + album = await createAlbum(oAuth2Client, albumTitle); + await shareAlbum(oAuth2Client, album.id); + } + + const filename = "sample.png"; + const uploadToken = await uploadPhoto(oAuth2Client, fs.createReadStream(filename), filename); + const {mediaItem} = await createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); + const {baseUrl} = await getMediaItem(oAuth2Client, mediaItem.id); + console.log(`共有リンク: ${baseUrl}`); } if (require.main === module) { From 594d0d9cc2a74bce9f46bcd0dde9d21511739e59 Mon Sep 17 00:00:00 2001 From: ilim Date: Sat, 8 Dec 2018 17:50:02 +0900 Subject: [PATCH 06/11] =?UTF-8?q?=E3=82=AB=E3=83=A1=E3=83=A9=E6=92=AE?= =?UTF-8?q?=E5=BD=B1=E3=81=AE=E6=A9=9F=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++++ caputure.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + photoAPI.js | 63 ++++++++++++++++++++++++++-------------------------- slack.js | 6 +++++ 5 files changed, 107 insertions(+), 32 deletions(-) create mode 100644 caputure.js create mode 100644 slack.js diff --git a/README.md b/README.md index 3d9c3d6..e6dc4b0 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,14 @@ OSKの部室の様子を様子をオンラインで確認できるプロジェ "client_secret": "yEP..." } } +``` + +## カメラを使えるようにする +Macなら +```shell +brew install imagesnap +``` +Ubuntuは +```shell +sudo apt-get install fswebcam ``` \ No newline at end of file diff --git a/caputure.js b/caputure.js new file mode 100644 index 0000000..316eff1 --- /dev/null +++ b/caputure.js @@ -0,0 +1,59 @@ +"use strict"; + +const photoapi = require("./photoAPI"); +const NodeWebcam = require('node-webcam'); +const slack = require("./slack"); + + +const Webcam = NodeWebcam.create({ + width: 1280, + height: 720, + quality: 100, + + delay: 0, + saveShots: true, + device: false, + callbackReturn: "buffer", + verbose: false +}); + +/** + @typedef {Object} OAuth2Client + @property {Function} getAccessToken + */ + +/** + * @param {OAuth2Client} oAuth2Client + * @returns {Promise} + */ + +module.exports.capture = (oAuth2Client, album) => { + return new Promise((resolve, reject) => { + Webcam.capture("", async (err, photo) => { + if (err) { + reject(err); + } + const uploadToken = await photoapi.uploadPhoto(oAuth2Client, photo, Date().toLocaleString()); + const {mediaItem} = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); + const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.id); + resolve(baseUrl); + }) + }) +}; + +async function main() { + const oAuth2Client = await photoapi.getOAuthToken(); + + const albumTitle = "bushitsuchan_test_album"; + const albums = await photoapi.getAlbumList(oAuth2Client); + let album = albums.filter((album) => album.title === albumTitle); + if (!album.length) { + album = await photoapi.createAlbum(oAuth2Client, albumTitle); + await photoapi.shareAlbum(oAuth2Client, album.id); + } + setInterval(() => module.exports.capture(oAuth2Client, album).then(slack.send), 3000); +} + +if (require.main === module) { + main().catch(console.error); +} \ No newline at end of file diff --git a/package.json b/package.json index 8fa735c..a9ce858 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "homepage": "https://github.com/TUS-OSK/bushitsuchan-PC#readme", "dependencies": { "googleapis": "^35.0.0", + "node-webcam": "^0.4.6", "path": "^0.12.7", "readline": "^1.3.0", "request": "^2.88.0", diff --git a/photoAPI.js b/photoAPI.js index db67f0b..dfcb21b 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -29,7 +29,7 @@ const rpap = rp.defaults({ /** * @returns {Promise} */ -async function getOAuthToken() { +module.exports.getOAuthToken = async () => { const keyPath = path.join(__dirname, "oauth2.keys.json"); let keys = {}; if (fs.existsSync(keyPath)) { @@ -60,25 +60,23 @@ async function getOAuthToken() { input: process.stdin, output: process.stdout, }); - return new Promise((resolve) => rl.question("入力: ", resolve)) - .then((authorizationCode) => { + return new Promise(resolve => { + rl.question("入力: ", async authorizationCode => { rl.close(); - return oAuth2Client.getToken(authorizationCode); - }) - .then(value => { + const value = await oAuth2Client.getToken(authorizationCode); const token = value.tokens; oAuth2Client.setCredentials(token); fs.writeFileSync(tokenPath, JSON.stringify(token)); - }).then(() => { - return oAuth2Client; - }); -} + resolve(oAuth2Client); + }) + }); +}; /** * @param {OAuth2Client} oAuth2Client * @returns {Promise>} */ -async function getAlbumList(oAuth2Client) { +module.exports.getAlbumList = async (oAuth2Client) => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/albums"; const headers = { @@ -90,7 +88,7 @@ async function getAlbumList(oAuth2Client) { headers: headers }); return response["albums"] -} +}; /** * @param {OAuth2Client} oAuth2Client @@ -98,7 +96,7 @@ async function getAlbumList(oAuth2Client) { * @param {string} filename * @returns {Promise} */ -async function uploadPhoto(oAuth2Client, photo, filename) { +module.exports.uploadPhoto = async (oAuth2Client, photo, filename) => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/uploads"; const headers = { @@ -112,7 +110,7 @@ async function uploadPhoto(oAuth2Client, photo, filename) { headers: headers, body: photo }); -} +}; /** * @param {OAuth2Client} oAuth2Client @@ -120,7 +118,7 @@ async function uploadPhoto(oAuth2Client, photo, filename) { * @param {string} description * @returns {Promise>} */ -async function createMediaItem(oAuth2Client, uploadToken, description) { +module.exports.createMediaItem = async (oAuth2Client, uploadToken, description) => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"; const headers = { @@ -143,7 +141,7 @@ async function createMediaItem(oAuth2Client, uploadToken, description) { body: JSON.stringify(body) }); return response["newMediaItemResults"]; -} +}; /** * @param {OAuth2Client} oAuth2Client @@ -152,7 +150,7 @@ async function createMediaItem(oAuth2Client, uploadToken, description) { * @param {string} description * @returns {Promise} */ -async function createAlbumMediaItem(oAuth2Client, albumID, uploadToken, description) { +module.exports.createAlbumMediaItem = async (oAuth2Client, albumID, uploadToken, description) => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"; const headers = { @@ -176,14 +174,14 @@ async function createAlbumMediaItem(oAuth2Client, albumID, uploadToken, descript body: JSON.stringify(body) }); return response["newMediaItemResults"][0]; -} +}; /** * @param {OAuth2Client} oAuth2Client * @param {string} title * @returns {Promise} */ -async function createAlbum(oAuth2Client, title) { +module.exports.createAlbum = async (oAuth2Client, title) => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/albums"; const headers = { @@ -200,14 +198,14 @@ async function createAlbum(oAuth2Client, title) { headers: headers, body: JSON.stringify(body) }); -} +}; /** * @param {OAuth2Client} oAuth2Client * @param {string} albumID * @returns {Promise} */ -async function shareAlbum(oAuth2Client, albumID) { +module.exports.shareAlbum = async (oAuth2Client, albumID) => { const accessToken = await oAuth2Client.getAccessToken(); const url = `https://photoslibrary.googleapis.com/v1/albums/${albumID}:share`; const headers = { @@ -225,14 +223,14 @@ async function shareAlbum(oAuth2Client, albumID) { headers: headers, body: JSON.stringify(body) }); -} +}; /** * @param {OAuth2Client} oAuth2Client * @param {string} mediaItemID * @returns {Promise} */ -async function getMediaItem(oAuth2Client, mediaItemID) { +module.exports.getMediaItem = async (oAuth2Client, mediaItemID) => { const accessToken = await oAuth2Client.getAccessToken(); const url = `https://photoslibrary.googleapis.com/v1/mediaItems/${mediaItemID}`; const headers = { @@ -243,26 +241,27 @@ async function getMediaItem(oAuth2Client, mediaItemID) { method: "GET", headers: headers, }); -} +}; async function main() { - const oAuth2Client = await getOAuthToken(); + const oAuth2Client = await module.exports.getOAuthToken(); const albumTitle = "bushitsuchan_test_album"; - const albums = await getAlbumList(oAuth2Client); + const albums = await module.exports.getAlbumList(oAuth2Client); let album = albums.filter((album) => album.title === albumTitle); if (!album.length) { - album = await createAlbum(oAuth2Client, albumTitle); - await shareAlbum(oAuth2Client, album.id); + album = await module.exports.createAlbum(oAuth2Client, albumTitle); + await module.exports.shareAlbum(oAuth2Client, album.id); } - const filename = "sample.png"; - const uploadToken = await uploadPhoto(oAuth2Client, fs.createReadStream(filename), filename); - const {mediaItem} = await createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); - const {baseUrl} = await getMediaItem(oAuth2Client, mediaItem.id); + const filename = "figure_personal_space.png"; + const uploadToken = await module.exports.uploadPhoto(oAuth2Client, fs.createReadStream(filename), filename); + const {mediaItem} = await module.exports.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); + const {baseUrl} = await module.exports.getMediaItem(oAuth2Client, mediaItem.id); console.log(`共有リンク: ${baseUrl}`); } + if (require.main === module) { main().catch(console.error); } \ No newline at end of file diff --git a/slack.js b/slack.js new file mode 100644 index 0000000..2d8efe4 --- /dev/null +++ b/slack.js @@ -0,0 +1,6 @@ +"use strict"; + + +module.exports.send = (value, value2) => { + console.log(`未実装ですが以下を投稿したことになりました ${value}`) +}; \ No newline at end of file From f9c4421d48b1a5bd3382f55a005fee82f83ab1e9 Mon Sep 17 00:00:00 2001 From: ilim Date: Sat, 8 Dec 2018 18:27:41 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=E7=9F=AD=E7=B8=AEURL=E3=82=92=E5=87=BA?= =?UTF-8?q?=E5=8A=9B=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- caputure.js | 9 ++++----- photoAPI.js | 5 +++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/caputure.js b/caputure.js index 316eff1..4bfe986 100644 --- a/caputure.js +++ b/caputure.js @@ -23,10 +23,9 @@ const Webcam = NodeWebcam.create({ */ /** - * @param {OAuth2Client} oAuth2Client - * @returns {Promise} + * @param {OAuth2Client}oAuth2Client + * @param {Object} album */ - module.exports.capture = (oAuth2Client, album) => { return new Promise((resolve, reject) => { Webcam.capture("", async (err, photo) => { @@ -36,7 +35,7 @@ module.exports.capture = (oAuth2Client, album) => { const uploadToken = await photoapi.uploadPhoto(oAuth2Client, photo, Date().toLocaleString()); const {mediaItem} = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.id); - resolve(baseUrl); + resolve(photoapi.getShortURL(baseUrl)); }) }) }; @@ -51,7 +50,7 @@ async function main() { album = await photoapi.createAlbum(oAuth2Client, albumTitle); await photoapi.shareAlbum(oAuth2Client, album.id); } - setInterval(() => module.exports.capture(oAuth2Client, album).then(slack.send), 3000); + setInterval(() => module.exports.capture(oAuth2Client, album).then(slack.send), 5000); } if (require.main === module) { diff --git a/photoAPI.js b/photoAPI.js index dfcb21b..31a37c6 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -243,6 +243,11 @@ module.exports.getMediaItem = async (oAuth2Client, mediaItemID) => { }); }; +module.exports.getShortURL = async url => { + const ret = await rpap.get(`http://is.gd/create.php?format=simple&format=json&url=${url}`); + return JSON.parse(ret)["shorturl"]; +}; + async function main() { const oAuth2Client = await module.exports.getOAuthToken(); From 87002e0f1cc17f6a6ecc46f964560de56fa88be5 Mon Sep 17 00:00:00 2001 From: ilim Date: Sat, 8 Dec 2018 18:41:44 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=E5=AE=9F=E9=9A=9B=E3=81=AB=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=81=99=E3=82=8B=E4=BB=AE=E3=81=AE=E9=96=A2=E6=95=B0?= =?UTF-8?q?=E3=82=92=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++++- app.js | 27 ++++++++++++++++++++++++++- package-lock.json | 41 +++++++++++++++++++++++++++++++++++++++++ slack.js | 2 +- 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6dc4b0..34ca9f7 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,9 @@ brew install imagesnap Ubuntuは ```shell sudo apt-get install fswebcam -``` \ No newline at end of file +``` + +## Usage +1. `npm install` +1. `npm start` +を実行 \ No newline at end of file diff --git a/app.js b/app.js index a726efc..d47a2cc 100644 --- a/app.js +++ b/app.js @@ -1 +1,26 @@ -'use strict'; \ No newline at end of file +"use strict"; + +const photoapi = require("./photoAPI"); +const {capture} = require("./caputure"); +const slack = require("./slack"); + +const main = async () => { + const oAuth2Client = await photoapi.getOAuthToken(); + + const albumTitle = "bushitsuchan_album"; + const albums = await photoapi.getAlbumList(oAuth2Client); + let album = albums.filter((album) => album.title === albumTitle); + if (!album.length) { + album = await photoapi.createAlbum(oAuth2Client, albumTitle); + await photoapi.shareAlbum(oAuth2Client, album.id); + } + setInterval(async () => { + const url = await capture(oAuth2Client, album); + slack.send(url); // ここをカスタマイズしてください + }, 5000); +}; + + +if (require.main === module) { + main().catch(console.error); +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e2b898c..d3e6f1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "agent-base": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", @@ -423,11 +428,47 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" }, + "node-webcam": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/node-webcam/-/node-webcam-0.4.6.tgz", + "integrity": "sha512-TSiTag0jhTlWralSuX3MDbQtagQN/covkZI6S8Ie2gT/xthsmVdBA+GnJVeVLDIeqTKVsl90lsy8vYiLWMVx4w==", + "requires": { + "nopt": "*" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, + "os-homedir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", diff --git a/slack.js b/slack.js index 2d8efe4..eb92dbc 100644 --- a/slack.js +++ b/slack.js @@ -1,6 +1,6 @@ "use strict"; -module.exports.send = (value, value2) => { +module.exports.send = value => { console.log(`未実装ですが以下を投稿したことになりました ${value}`) }; \ No newline at end of file From 6407d188eed8d3bd2483a0dc66b3c8c9765ef4db Mon Sep 17 00:00:00 2001 From: ilim Date: Wed, 12 Dec 2018 22:47:21 +0900 Subject: [PATCH 09/11] =?UTF-8?q?direnv=E3=81=A7id=E7=AD=89=E3=82=92?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?&=E9=9D=9E=E5=90=8C=E6=9C=9F=E5=87=A6=E7=90=86=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 ++++++++------- app.js | 36 ++++++++++++++++++++++++++------ caputure.js | 31 +++++++++++++++++++-------- photoAPI.js | 60 ++++++++++++++++++++++++++--------------------------- 4 files changed, 90 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 34ca9f7..079fa9e 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,16 @@ OSKの部室の様子を様子をオンラインで確認できるプロジェ ## Google Photos APIs を使えようにする 1. [Photos Library API](https://console.developers.google.com/apis/library/photoslibrary.googleapis.com)を有効にする. 1. [認証情報](https://console.developers.google.com/apis/credentials)でOAuth クライアント IDを作成する (アプリケーションの種類 は その他) -1. 作成した`クライアント ID`と`クライアント シークレット`を`oauth2.keys.json`に以下のように保存する +1. 作成した`クライアント ID`と`クライアント シークレット`を`.envrc`に以下のように保存する -```json:oauth2.keys.json -{ - "web": { - "client_id": "477...oav.apps.googleusercontent.com", - "client_secret": "yEP..." - } -} +```shell +export client_id="477...oav.apps.googleusercontent.com" +export client_secret="yEP..." +``` +4. `direnv`の有効化方法に従う` +Macでbashなら +```shell +direnv allow ``` ## カメラを使えるようにする diff --git a/app.js b/app.js index d47a2cc..90c0b3e 100644 --- a/app.js +++ b/app.js @@ -5,19 +5,43 @@ const {capture} = require("./caputure"); const slack = require("./slack"); const main = async () => { - const oAuth2Client = await photoapi.getOAuthToken(); + const {client_id, client_secret} = process.env; + if (client_id === undefined || client_secret === undefined) { + console.log("READMEに従ってGoogle Photos APIsの認証鍵を設定してください"); + process.exit(1); + } + const oAuth2Client = await photoapi.getOAuthToken(client_id, client_secret); const albumTitle = "bushitsuchan_album"; const albums = await photoapi.getAlbumList(oAuth2Client); - let album = albums.filter((album) => album.title === albumTitle); - if (!album.length) { + let album = albums.filter((album) => album.title === albumTitle)[0]; + + if (album === undefined) { album = await photoapi.createAlbum(oAuth2Client, albumTitle); await photoapi.shareAlbum(oAuth2Client, album.id); } + //https://developers.google.com/photos/library/guides/api-limits-quotas に抵触しないように!! + const interval = 10 * 1000; + if (60 * 60 * 24 * 1000 / 10000 * 3 > interval) { + console.log(`注意: 1日あたり${(60 * 60 * 24 * 3 / interval * 1000).toLocaleString()}回PhotoAPIを叩く設定で,1日の上限10,000回を越してしまいます`); + } setInterval(async () => { - const url = await capture(oAuth2Client, album); - slack.send(url); // ここをカスタマイズしてください - }, 5000); + const url = await capture(oAuth2Client, album).catch(e => { + console.error(e.name); + if (e.name === "StatusCodeError") { + console.error(JSON.parse(e.error).error.message); + return; + } + console.error(e.message); + // console.error(e); + }); + + if (!url) { + return; + } + const shortURL = await photoapi.getShortURL(url); + slack.send(shortURL); // ここをカスタマイズしてください + }, interval); }; diff --git a/caputure.js b/caputure.js index 4bfe986..57ec084 100644 --- a/caputure.js +++ b/caputure.js @@ -26,18 +26,31 @@ const Webcam = NodeWebcam.create({ * @param {OAuth2Client}oAuth2Client * @param {Object} album */ -module.exports.capture = (oAuth2Client, album) => { - return new Promise((resolve, reject) => { - Webcam.capture("", async (err, photo) => { +module.exports.capture = async (oAuth2Client, album) => { + const photo = await new Promise((resolve, reject) => { + Webcam.capture("capture", (err, photo) => { if (err) { reject(err); } - const uploadToken = await photoapi.uploadPhoto(oAuth2Client, photo, Date().toLocaleString()); - const {mediaItem} = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); - const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.id); - resolve(photoapi.getShortURL(baseUrl)); + resolve(photo); }) - }) + }).catch(e => { + console.error(e); + console.error( + "READMEに従ってカメラを使えるようにしてください\n" + + "また,OSやセキュリティソフトでカメラへのアクセスをブロックしている可能性もあります 解除してください\n"); + process.exit(1); + }); + const uploadToken = await photoapi.uploadPhoto(oAuth2Client, photo, Date().toLocaleString()); + const mediaItem = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); + if (mediaItem === undefined) { + console.error() + } + const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.mediaItem.id); + if (baseUrl === undefined || baseUrl === "") { + console.error() + } + return baseUrl; }; async function main() { @@ -45,7 +58,7 @@ async function main() { const albumTitle = "bushitsuchan_test_album"; const albums = await photoapi.getAlbumList(oAuth2Client); - let album = albums.filter((album) => album.title === albumTitle); + let album = albums.filter((album) => album.title === albumTitle)[0]; if (!album.length) { album = await photoapi.createAlbum(oAuth2Client, albumTitle); await photoapi.shareAlbum(oAuth2Client, album.id); diff --git a/photoAPI.js b/photoAPI.js index 31a37c6..595c748 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -29,15 +29,10 @@ const rpap = rp.defaults({ /** * @returns {Promise} */ -module.exports.getOAuthToken = async () => { - const keyPath = path.join(__dirname, "oauth2.keys.json"); - let keys = {}; - if (fs.existsSync(keyPath)) { - keys = require(keyPath).web; - } +module.exports.getOAuthToken = (client_id, client_secret) => { const oAuth2Client = new google.auth.OAuth2( - keys["client_id"], - keys["client_secret"], + client_id, + client_secret, "urn:ietf:wg:oauth:2.0:oob" ); const scopes = [ @@ -63,10 +58,13 @@ module.exports.getOAuthToken = async () => { return new Promise(resolve => { rl.question("入力: ", async authorizationCode => { rl.close(); - const value = await oAuth2Client.getToken(authorizationCode); - const token = value.tokens; - oAuth2Client.setCredentials(token); - fs.writeFileSync(tokenPath, JSON.stringify(token)); + if (authorizationCode === "") { + console.error("入力が無効です 再実行してください"); + process.exit(1); + } + const {tokens} = await oAuth2Client.getToken(authorizationCode); + oAuth2Client.setCredentials(tokens); + fs.writeFileSync(tokenPath, JSON.stringify(tokens)); resolve(oAuth2Client); }) }); @@ -76,18 +74,18 @@ module.exports.getOAuthToken = async () => { * @param {OAuth2Client} oAuth2Client * @returns {Promise>} */ -module.exports.getAlbumList = async (oAuth2Client) => { +module.exports.getAlbumList = async oAuth2Client => { const accessToken = await oAuth2Client.getAccessToken(); const url = "https://photoslibrary.googleapis.com/v1/albums"; const headers = { "Content-type": "application/json", Authorization: `Bearer ${accessToken.token}` }; - const response = await rpap(url, { + return rpap(url, { method: "GET", headers: headers - }); - return response["albums"] + }) + .then(response => response["albums"]); }; /** @@ -105,7 +103,7 @@ module.exports.uploadPhoto = async (oAuth2Client, photo, filename) => { "X-Goog-Upload-File-Name": filename, "X-Goog-Upload-Protocol": "raw" }; - return await rpap(url, { + return rpap(url, { method: "POST", headers: headers, body: photo @@ -135,12 +133,12 @@ module.exports.createMediaItem = async (oAuth2Client, uploadToken, description) } ] }; - const response = await rpap(url, { + return rpap(url, { method: "POST", headers: headers, body: JSON.stringify(body) - }); - return response["newMediaItemResults"]; + }) + .then(response => response["newMediaItemResults"]); }; /** @@ -168,12 +166,12 @@ module.exports.createAlbumMediaItem = async (oAuth2Client, albumID, uploadToken, } ] }; - const response = await rpap(url, { + return rpap(url, { method: "POST", headers: headers, body: JSON.stringify(body) - }); - return response["newMediaItemResults"][0]; + }) + .then(response => response["newMediaItemResults"][0]) }; /** @@ -193,7 +191,7 @@ module.exports.createAlbum = async (oAuth2Client, title) => { title: title } }; - return await rpap(url, { + return rpap(url, { method: "POST", headers: headers, body: JSON.stringify(body) @@ -218,7 +216,7 @@ module.exports.shareAlbum = async (oAuth2Client, albumID) => { "isCommentable": "true" } }; - return await rpap(url, { + return rpap(url, { method: "POST", headers: headers, body: JSON.stringify(body) @@ -237,15 +235,15 @@ module.exports.getMediaItem = async (oAuth2Client, mediaItemID) => { "Constent-type": "application/json", Authorization: `Bearer ${accessToken.token}` }; - return await rpap(url, { + return rpap(url, { method: "GET", headers: headers, }); }; -module.exports.getShortURL = async url => { - const ret = await rpap.get(`http://is.gd/create.php?format=simple&format=json&url=${url}`); - return JSON.parse(ret)["shorturl"]; +module.exports.getShortURL = url => { + return rpap.get(`http://is.gd/create.php?format=simple&format=json&url=${url}`) + .then(result => JSON.parse(result)["shorturl"]); }; async function main() { @@ -253,8 +251,8 @@ async function main() { const albumTitle = "bushitsuchan_test_album"; const albums = await module.exports.getAlbumList(oAuth2Client); - let album = albums.filter((album) => album.title === albumTitle); - if (!album.length) { + let album = albums.filter((album) => album.title === albumTitle)[0]; + if (album === undefined) { album = await module.exports.createAlbum(oAuth2Client, albumTitle); await module.exports.shareAlbum(oAuth2Client, album.id); } From d7df4da1f976cddef83865aa3ef968bff8a50405 Mon Sep 17 00:00:00 2001 From: ilim Date: Wed, 12 Dec 2018 22:50:56 +0900 Subject: [PATCH 10/11] =?UTF-8?q?gitignore=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index bbfaaa7..1af3be6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules -token.json -oauth2.keys.json -sample.png \ No newline at end of file +capture.jpg +.envrc +token.json \ No newline at end of file From 158b5f8bb3beadcdf42d74b2414bf3ff22f6192a Mon Sep 17 00:00:00 2001 From: ilim Date: Thu, 13 Dec 2018 00:18:05 +0900 Subject: [PATCH 11/11] =?UTF-8?q?JSDoc=E3=82=92=E4=BF=AE=E6=AD=A3&?= =?UTF-8?q?=E6=95=B4=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 33 +++++++++++------ caputure.js | 46 +++++------------------ photoAPI.js | 104 +++++++++++++++++++++++++++++++++------------------- 3 files changed, 98 insertions(+), 85 deletions(-) diff --git a/app.js b/app.js index 90c0b3e..5d1af7c 100644 --- a/app.js +++ b/app.js @@ -5,46 +5,55 @@ const {capture} = require("./caputure"); const slack = require("./slack"); const main = async () => { + //認証鍵の設定 const {client_id, client_secret} = process.env; - if (client_id === undefined || client_secret === undefined) { + if (!client_id || !client_secret) { console.log("READMEに従ってGoogle Photos APIsの認証鍵を設定してください"); - process.exit(1); + process.exit(1) } const oAuth2Client = await photoapi.getOAuthToken(client_id, client_secret); + //共有するためアルバムを指定 const albumTitle = "bushitsuchan_album"; const albums = await photoapi.getAlbumList(oAuth2Client); let album = albums.filter((album) => album.title === albumTitle)[0]; if (album === undefined) { album = await photoapi.createAlbum(oAuth2Client, albumTitle); - await photoapi.shareAlbum(oAuth2Client, album.id); + await photoapi.shareAlbum(oAuth2Client, album.id) } + + //定期的に撮影した写真の共有リンクをslackbotで送信 //https://developers.google.com/photos/library/guides/api-limits-quotas に抵触しないように!! + /** + * 何msに一回実行するか あまり小さくしすぎるとエラーが発生します + * @type {number} + */ const interval = 10 * 1000; if (60 * 60 * 24 * 1000 / 10000 * 3 > interval) { - console.log(`注意: 1日あたり${(60 * 60 * 24 * 3 / interval * 1000).toLocaleString()}回PhotoAPIを叩く設定で,1日の上限10,000回を越してしまいます`); + console.log(`注意: 1日あたり${(60 * 60 * 24 * 3 / interval * 1000).toLocaleString()}回PhotoAPIを叩く設定で,1日の上限10,000回を越してしまいます`) } setInterval(async () => { const url = await capture(oAuth2Client, album).catch(e => { console.error(e.name); if (e.name === "StatusCodeError") { console.error(JSON.parse(e.error).error.message); - return; + return } - console.error(e.message); - // console.error(e); + console.error(e.message) + // console.error(e) }); - if (!url) { - return; + return } const shortURL = await photoapi.getShortURL(url); - slack.send(shortURL); // ここをカスタマイズしてください - }, interval); + + // ここをカスタマイズしてください + slack.send(shortURL) + }, interval) }; if (require.main === module) { - main().catch(console.error); + main().catch(console.error) } \ No newline at end of file diff --git a/caputure.js b/caputure.js index 57ec084..406d0db 100644 --- a/caputure.js +++ b/caputure.js @@ -18,54 +18,28 @@ const Webcam = NodeWebcam.create({ }); /** - @typedef {Object} OAuth2Client - @property {Function} getAccessToken - */ - -/** - * @param {OAuth2Client}oAuth2Client + * 写真を撮影しGooglePhotoへとアップロード,その共有リンクを取得します + * @param {oAuth2Client} oAuth2Client - photoapi.getOAuthToken関数で取得します * @param {Object} album + * @returns {Promise} */ module.exports.capture = async (oAuth2Client, album) => { const photo = await new Promise((resolve, reject) => { Webcam.capture("capture", (err, photo) => { if (err) { - reject(err); + reject(err) } - resolve(photo); + resolve(photo) }) }).catch(e => { console.error(e); console.error( "READMEに従ってカメラを使えるようにしてください\n" + "また,OSやセキュリティソフトでカメラへのアクセスをブロックしている可能性もあります 解除してください\n"); - process.exit(1); + process.exit(1) }); const uploadToken = await photoapi.uploadPhoto(oAuth2Client, photo, Date().toLocaleString()); - const mediaItem = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); - if (mediaItem === undefined) { - console.error() - } - const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.mediaItem.id); - if (baseUrl === undefined || baseUrl === "") { - console.error() - } - return baseUrl; -}; - -async function main() { - const oAuth2Client = await photoapi.getOAuthToken(); - - const albumTitle = "bushitsuchan_test_album"; - const albums = await photoapi.getAlbumList(oAuth2Client); - let album = albums.filter((album) => album.title === albumTitle)[0]; - if (!album.length) { - album = await photoapi.createAlbum(oAuth2Client, albumTitle); - await photoapi.shareAlbum(oAuth2Client, album.id); - } - setInterval(() => module.exports.capture(oAuth2Client, album).then(slack.send), 5000); -} - -if (require.main === module) { - main().catch(console.error); -} \ No newline at end of file + const {mediaItem} = await photoapi.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); + const {baseUrl} = await photoapi.getMediaItem(oAuth2Client, mediaItem.id); + return baseUrl +}; \ No newline at end of file diff --git a/photoAPI.js b/photoAPI.js index 595c748..79d9d36 100644 --- a/photoAPI.js +++ b/photoAPI.js @@ -9,25 +9,28 @@ const rp = require("request-promise"); const rpap = rp.defaults({ - transform: (body, response, resolveWithFullResponse) => { - const constentType = response.headers["content-type"].split(";")[0]; + "transform": (body, response) => { + const constentType = response.headers["content-type"].split("")[0]; if (constentType === "application/json") { - return JSON.parse(body); + return JSON.parse(body) } else if (constentType === "text/plain") { - return body; + return body } else { - return body; + return body } } }); /** - @typedef {Object} OAuth2Client - @property {Function} getAccessToken + * @typedef {Object} oAuth2Client + * @property {function: string} getAccessToken */ /** - * @returns {Promise} + * 認証鍵を取得します + * @param {string} client_id - GCPで取得したクライアントID + * @param {string} client_secret - GCPで取得したクライアントシークレット + * @returns {Promise} */ module.exports.getOAuthToken = (client_id, client_secret) => { const oAuth2Client = new google.auth.OAuth2( @@ -43,7 +46,7 @@ module.exports.getOAuthToken = (client_id, client_secret) => { const tokenPath = path.join(__dirname, "token.json"); if (fs.existsSync(tokenPath)) { oAuth2Client.setCredentials(require(tokenPath)); - return oAuth2Client; + return oAuth2Client } const authURL = oAuth2Client.generateAuthUrl({ access_type: "offline", @@ -60,19 +63,21 @@ module.exports.getOAuthToken = (client_id, client_secret) => { rl.close(); if (authorizationCode === "") { console.error("入力が無効です 再実行してください"); - process.exit(1); + process.exit(1) } const {tokens} = await oAuth2Client.getToken(authorizationCode); oAuth2Client.setCredentials(tokens); fs.writeFileSync(tokenPath, JSON.stringify(tokens)); - resolve(oAuth2Client); + resolve(oAuth2Client) }) - }); + }) }; + /** - * @param {OAuth2Client} oAuth2Client - * @returns {Promise>} + * アルバム一覧の取得 + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します + * @returns {Promise>} */ module.exports.getAlbumList = async oAuth2Client => { const accessToken = await oAuth2Client.getAccessToken(); @@ -85,14 +90,16 @@ module.exports.getAlbumList = async oAuth2Client => { method: "GET", headers: headers }) - .then(response => response["albums"]); + .then(response => response["albums"]) }; + /** - * @param {OAuth2Client} oAuth2Client - * @param {ReadStream} photo + * 画像のバイナリデータを送信します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します + * @param photo * @param {string} filename - * @returns {Promise} + * @returns {Promise} uploadToken */ module.exports.uploadPhoto = async (oAuth2Client, photo, filename) => { const accessToken = await oAuth2Client.getAccessToken(); @@ -107,14 +114,16 @@ module.exports.uploadPhoto = async (oAuth2Client, photo, filename) => { method: "POST", headers: headers, body: photo - }); + }) }; + /** - * @param {OAuth2Client} oAuth2Client - * @param {string} uploadToken + * アップロードした画像を単なる写真として保存します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します + * @param {string} uploadToken - uploadPhoto関数で取得します * @param {string} description - * @returns {Promise>} + * @returns {Promise>} */ module.exports.createMediaItem = async (oAuth2Client, uploadToken, description) => { const accessToken = await oAuth2Client.getAccessToken(); @@ -138,13 +147,15 @@ module.exports.createMediaItem = async (oAuth2Client, uploadToken, description) headers: headers, body: JSON.stringify(body) }) - .then(response => response["newMediaItemResults"]); + .then(response => response["newMediaItemResults"]) }; + /** - * @param {OAuth2Client} oAuth2Client + * アップロードした画像をアルバムに追加します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します * @param {string} albumID - * @param {string} uploadToken + * @param {string} uploadToken - uploadPhoto関数で取得します * @param {string} description * @returns {Promise} */ @@ -174,8 +185,10 @@ module.exports.createAlbumMediaItem = async (oAuth2Client, albumID, uploadToken, .then(response => response["newMediaItemResults"][0]) }; + /** - * @param {OAuth2Client} oAuth2Client + * アルバムを作成します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します * @param {string} title * @returns {Promise} */ @@ -195,11 +208,12 @@ module.exports.createAlbum = async (oAuth2Client, title) => { method: "POST", headers: headers, body: JSON.stringify(body) - }); + }) }; /** - * @param {OAuth2Client} oAuth2Client + * アルバムを共有します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します * @param {string} albumID * @returns {Promise} */ @@ -220,11 +234,13 @@ module.exports.shareAlbum = async (oAuth2Client, albumID) => { method: "POST", headers: headers, body: JSON.stringify(body) - }); + }) }; + /** - * @param {OAuth2Client} oAuth2Client + * アップロード済みの写真に関する情報を取得します + * @param {oAuth2Client} oAuth2Client - getOAuthToken関数で取得します * @param {string} mediaItemID * @returns {Promise} */ @@ -238,33 +254,47 @@ module.exports.getMediaItem = async (oAuth2Client, mediaItemID) => { return rpap(url, { method: "GET", headers: headers, - }); + }) }; +/** + * 与えられたURLの短縮URLを取得します + * @param {string} url + * @returns {Promise} 短縮URL + */ module.exports.getShortURL = url => { return rpap.get(`http://is.gd/create.php?format=simple&format=json&url=${url}`) - .then(result => JSON.parse(result)["shorturl"]); + .then(result => JSON.parse(result)["shorturl"]) }; async function main() { - const oAuth2Client = await module.exports.getOAuthToken(); + const {client_id, client_secret} = process.env; + if (!client_id || !client_secret) { + console.log("READMEに従ってGoogle Photos APIsの認証鍵を設定してください"); + process.exit(1) + } + const oAuth2Client = await module.exports.getOAuthToken(client_id, client_secret); const albumTitle = "bushitsuchan_test_album"; const albums = await module.exports.getAlbumList(oAuth2Client); let album = albums.filter((album) => album.title === albumTitle)[0]; if (album === undefined) { album = await module.exports.createAlbum(oAuth2Client, albumTitle); - await module.exports.shareAlbum(oAuth2Client, album.id); + await module.exports.shareAlbum(oAuth2Client, album.id) } - const filename = "figure_personal_space.png"; + const filename = "example.png"; + if (!fs.existsSync(filename)) { + console.error(`${filename}が存在しないのでアップロードできません`); + process.exit(1) + } const uploadToken = await module.exports.uploadPhoto(oAuth2Client, fs.createReadStream(filename), filename); const {mediaItem} = await module.exports.createAlbumMediaItem(oAuth2Client, album.id, uploadToken, ""); const {baseUrl} = await module.exports.getMediaItem(oAuth2Client, mediaItem.id); - console.log(`共有リンク: ${baseUrl}`); + console.log(`共有リンク: ${baseUrl}`) } if (require.main === module) { - main().catch(console.error); + main().catch(console.error) } \ No newline at end of file