├── .fonts ├── mplus-1m-bold.ttf ├── mplus-1m-light.ttf ├── mplus-1m-medium.ttf ├── mplus-1m-regular.ttf └── mplus-1m-thin.ttf ├── README.md ├── app.js └── package.json /.fonts/mplus-1m-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlwr/things-of-internet/64a30791e39534344569008aa70b95b90eea9fe6/.fonts/mplus-1m-bold.ttf -------------------------------------------------------------------------------- /.fonts/mplus-1m-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlwr/things-of-internet/64a30791e39534344569008aa70b95b90eea9fe6/.fonts/mplus-1m-light.ttf -------------------------------------------------------------------------------- /.fonts/mplus-1m-medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlwr/things-of-internet/64a30791e39534344569008aa70b95b90eea9fe6/.fonts/mplus-1m-medium.ttf -------------------------------------------------------------------------------- /.fonts/mplus-1m-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlwr/things-of-internet/64a30791e39534344569008aa70b95b90eea9fe6/.fonts/mplus-1m-regular.ttf -------------------------------------------------------------------------------- /.fonts/mplus-1m-thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlwr/things-of-internet/64a30791e39534344569008aa70b95b90eea9fe6/.fonts/mplus-1m-thin.ttf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ToI(Things of Internet) 2 | 3 | ![アイキャッチ](https://i.gyazo.com/a81ffca66bfa76021f5bf9981074c37e.png) 4 | 5 | > インターネットのモノ(Things of Internet,ToI)は、一意に識別可能な「インターネットのページ」が[SUZURI](https://suzuri.jp/)に接続され、API POSTすることにより物質化する仕組みである 6 | 7 | > (出展 [Wikipedia 「インターネットのモノ」](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8E%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88)) 8 | 9 | このリポジトリは、インターネットのページを定期的に[SUZURI](https://suzuri.jp/)に投稿する、いわゆる*SUZURI bot*制作するためのスケルトンです。 10 | 11 | 例えば、[誰かが書いた日記](https://suzuri.jp/darekagakaita)のようなbotを作ることができます。 12 | 13 | ### 使用法 14 | 15 | 比較的新しめのnodeで動きます 16 | 17 | #### `app.js` を編集して、以下の定数を変更して下さい 18 | 19 | ##### `API_KEY` 20 | 21 | [SUZURI API](https://suzuri.jp/developer)を利用するためのキーです。SUZURIアカウント取得後、 https://suzuri.jp/developer/apps で取得できます。 22 | 23 | ##### `URL` 24 | モノに変えたいURLです。 25 | 26 | ##### `SELECTOR` 27 | モノにプリントしたい部分のセレクタです。 28 | 29 | ##### `CRON_TIME` 30 | モノにプリントするスケジュールです。 31 | 32 | #### 以下のコマンドを実行してください 33 | 34 | ```bash 35 | npm install 36 | node app.js 37 | ``` 38 | 39 | ### Heroku 40 | 41 | Herokuで動かすことができます。 42 | 43 | ```bash 44 | heroku create 45 | git push heroku master 46 | ``` 47 | 48 | ただし、無料だと一日7時間以上稼働し続けられないなどの制限があるため、少しお金を払う必要があるかもしれないです。 49 | 50 | ### refs. 51 | 52 | [dlwr/darekagakaita](https://github.com/dlwr/darekagakaita) 53 | 54 | [sindresorhus/pageres](https://github.com/sindresorhus/pageres) 55 | 56 | [SUZURI](https://suzuri.jp) 57 | 58 | [誰かが書いた日記](https://suzuri.jp/darekagakaita) 59 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const Pageres = require('pageres') 2 | const fetch = require('node-fetch') 3 | const cheerio = require('cheerio') 4 | const cronJob = require('cron').CronJob 5 | const http = require('http') 6 | 7 | // get from https://suzuri.jp/developer/apps 8 | const API_KEY = "YOUR_SUZURI_API_KEY" 9 | // page url you want to archive 10 | const URL = 'http://page.to.archive/page/to/archive' 11 | // target DOM to archive. (if you want to all of page, set to 'body') 12 | const SELECTOR = '#content.you-want-to-archive' 13 | // cron time. '0 0 0 * * *' is means that this app archive target page on 00:00 every day 14 | const CRON_TIME = '0 0 0 * * *' 15 | 16 | const options = { 17 | selector: SELECTOR 18 | } 19 | 20 | var content = '' 21 | var prevContent = '' 22 | 23 | function archive() { 24 | var chunks = [] 25 | fetch(URL) 26 | .then(res => res.text()) 27 | .then(text => { 28 | $ = cheerio.load(text) 29 | content = $(SELECTOR).html() 30 | if (content === prevContent || content === '') { 31 | return Promise.reject() 32 | } 33 | return new Pageres(options) 34 | .src(URL, ['1920x1080']) 35 | .run() 36 | }) 37 | .then(result => { 38 | return new Promise((resolve, reject) => { 39 | result[0].on('data', data => { 40 | chunks.push(data) 41 | }) 42 | result[0].on('end', () => { 43 | var result = Buffer.concat(chunks) 44 | resolve('data:image/png;base64,' + result.toString('base64')) 45 | }) 46 | }) 47 | }) 48 | .then(img => { 49 | var date = new Date 50 | var itemId = [1,2,3,5,6,7,9][Math.floor(Math.random() * 7)] 51 | var product = { 52 | itemId: itemId, 53 | published: true, 54 | resizeMode: 'contain', 55 | exemplaryAngle: 'left' 56 | } 57 | if (itemId === 3) { 58 | product.exemplaryAngle = 'left' 59 | } 60 | var params = { 61 | texture: img, 62 | title: date.getFullYear() + '年' + ('0' + (date.getMonth() + 1)).slice(-2) + '月' + date.getDate() + '日' + ('0' + date.getHours()).slice(-2) + '時' + ('0' + date.getMinutes()).slice(-2) + '分', 63 | description: content, 64 | products: [ product ] 65 | } 66 | return fetch('https://suzuri.jp/api/v1/materials', { 67 | headers: { 68 | 'Content-Type': 'application/json', 69 | 'Authorization': 'Bearer ' + API_KEY 70 | }, 71 | method: 'POST', 72 | body: JSON.stringify(params) 73 | }) 74 | }) 75 | .then(res => { 76 | prevContent = content 77 | return res.text() 78 | }) 79 | .then(text => {console.log(text)}) 80 | } 81 | 82 | var job = new cronJob({ 83 | cronTime: CRON_TIME, 84 | onTick: archive, 85 | start: true 86 | }); 87 | 88 | job.start(); 89 | 90 | http.createServer((request, response) => { 91 | if (request.url === '/favicon.ico') { 92 | response.writeHead(200, {'Content-Type': 'image/x-icon'} ); 93 | response.end(); 94 | console.log('favicon requested'); 95 | return; 96 | } 97 | response.writeHead(200, {'Content-Type': 'text/plain'}) 98 | response.end(`${prevContent}\n`) 99 | }).listen(process.env.PORT || 8080) 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darekagakaita", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "dependencies": { 7 | "cheerio": "^0.20.0", 8 | "cron": "^1.1.0", 9 | "node-fetch": "^1.3.3", 10 | "pageres": "^4.1.0" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1", 15 | "start": "node app.js" 16 | }, 17 | "author": "", 18 | "license": "ISC" 19 | } 20 | --------------------------------------------------------------------------------