Skip to content

Commit

Permalink
Added image upload support for NeoCities with a local storage as a ba…
Browse files Browse the repository at this point in the history
…ckup.
  • Loading branch information
Glitch (glitch-fediverse-bot) committed Oct 4, 2018
1 parent 4e87f14 commit 7c7f4f2
Show file tree
Hide file tree
Showing 26 changed files with 300 additions and 103 deletions.
1 change: 1 addition & 0 deletions .glitch-assets
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
{"name":"glitch-fediverse-bot-small-1024px.png","date":"2018-09-29T12:49:07.895Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-small-1024px.png","type":"image/png","size":60397,"imageWidth":1024,"imageHeight":509,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot-small-1024px.png","thumbnailWidth":330,"thumbnailHeight":165,"dominantColor":"rgb(252,252,252)","uuid":"iLCHg6pDTsAX7jkg"}
{"name":"glitch-fediverse-bot.png","date":"2018-09-29T12:49:07.963Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot.png","type":"image/png","size":58653,"imageWidth":1920,"imageHeight":1079,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot.png","thumbnailWidth":330,"thumbnailHeight":186,"dominantColor":"rgb(252,252,252)","uuid":"0KNy0WXAgI1pZ0fd"}
{"name":"glitch-fediverse-bot-960px.png","date":"2018-09-29T12:49:08.030Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-960px.png","type":"image/png","size":50867,"imageWidth":960,"imageHeight":540,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot-960px.png","thumbnailWidth":330,"thumbnailHeight":186,"dominantColor":"rgb(252,252,252)","uuid":"8tHyMsnvvVKkjFXF"}
{"name":"glitch-fediverse-bot-with-image.png","date":"2018-10-03T21:11:53.744Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-with-image.png","type":"image/png","size":469823,"imageWidth":2880,"imageHeight":1465,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot-with-image.png","thumbnailWidth":330,"thumbnailHeight":168,"dominantColor":"rgb(252,252,252)","uuid":"oHDFFpP6XyCauPmh"}
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
*WORK IN PROGRESS*

![Glitch Fediverse bot](https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-small-1024px.png?1538225347895)


Expand Down Expand Up @@ -40,7 +38,7 @@ You can use [ES6](http://es6-features.org/#Constants), you script files will be
- https://neocities.org/api, https://neocities.org/supporter, https://github.com/neocities/neocities-node
- https://www.digitalocean.com/products/spaces/, https://glitch.com/~digitalocean-spaces-example
- Flickr API
- as a fallback, use the `.data/img` folder
- ~~as a fallback, use the `.data/img` folder~~
- reply to messages
- add link to `/admin`
- delete multiple posts at once (on the `/admin` page)
Expand Down
64 changes: 38 additions & 26 deletions bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,49 +77,61 @@ else{
create_post: function(options, cb){
var bot = this;

if ((!options.content || options.content.trim().length === 0 ) && (!options.thumbnail_url)){
console.log('error: missing post content')
if ((!options.content || options.content.trim().length === 0 ) && !options.attachment ){
console.log('error: no post content or attachments');
return false;
}

var type = options.type || 'Note',
var post_type = options.type || 'Note',
post_description = options.description,
post_date = moment().format(),
post_in_reply_to = options.in_reply_to || null,
post_content = options.content || '',
post_thumbnail_url = options.thumbnail_url || '';
post_content = options.content || options.url || '',
post_attachment = JSON.stringify(options.attachment) || '[]';

db.save_post({
type: type,
type: post_type,
content: post_content,
thumbnail_url: post_thumbnail_url
attachment: post_attachment
}, function(err, data){
var post_id = data.lastID;

var obj = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': `${bot_url}/post/${post_id}`,
'type': 'Create',
'actor': `${bot_url}/bot`,
'object': {

var post_object;

if ( post_type === 'Note' ){
post_object = {
'id': `${bot_url}/post/${post_id}`,
'type': type,
'type': post_type,
'published': post_date,
'attributedTo': `${bot_url}/bot`,
'content': post_content,
'to': 'https://www.w3.org/ns/activitystreams#Public'
};

if (options.attachment){
var attachments = [];

options.attachment.forEach(function(attachment){
attachments.push({
'type': 'Image',
'content': attachment.content,
'url': attachment.url
});
});
post_object.attachment = attachments;
}
}

if (options.thumbnail_url){
obj.preview = {
'type': 'Link',
'href': options.thumbnail_url,
'mediaType': 'image/png'
};
}

var post = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': `${bot_url}/post/${post_id}`,
'type': 'Create',
'actor': `${bot_url}/bot`,
'object': post_object
}

if (options.post_in_reply_to){
obj.object.inReplyTo = post_in_reply_to;
post.object.inReplyTo = post_in_reply_to;
}

db.get_followers(function(err, followers){
Expand All @@ -130,7 +142,7 @@ else{
if (follower.url){
bot.sign_and_send({
follower: follower,
message: obj
message: post
}, function(err, data){

});
Expand All @@ -140,7 +152,7 @@ else{
});

if (cb){
cb(null, obj);
cb(null, post);
}
});
},
Expand Down
14 changes: 14 additions & 0 deletions examples/generative-art-bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
![An example of a bot posting generated image](https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-with-image.png)

# Generative art bot

This is an example of a bot that generates images. It uses an image generator from [generative-art-bot](https://glitch.com/edit/#!/generative-art-bot).

(Note that the code needed to be slightly modified to work with this project.)

To try this example, copy the content of `examples/generative-art-bot/routes/bot-endpoint.js` to `routes/bot-endpoint.js` file and run your bot using its endpoint.

By default, the images are stored in the `.data/img` folder. Glitch only provides ~128MB of storage (there are technical limitations to using the `assets` folder, which gives you additional ~500MB), but you can upload your images to NeoCities, which comes with a free 1GB of space, and has a paid plan ([$5/month](https://neocities.org/supporter)) that offers 50GB.

Simply sign up for an account at [neocities.org](https://neocities.org/), and save your login information to the `.env` file as `NEOCITIES_USERNAME` and `NEOCITIES_PASSWORD`.

57 changes: 57 additions & 0 deletions examples/generative-art-bot/routes/bot-endpoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
var express = require('express'),
router = express.Router(),
ColorScheme = require('color-scheme'),
generators = {
triangular_mesh: require(__dirname + '/../generators/triangular-mesh.js')
},
grammar = require(__dirname + '/../tracery/tracery.js').grammar,
helpers = require(__dirname + '/../helpers/general.js'),
image_uploader = require(__dirname + '/../helpers/image-uploader.js'),
bot = require(__dirname + '/../bot.js');

router.get('/', function (req, res) {
var content = grammar.flatten("#origin#"),
scheme = new ColorScheme;

/*
See https://www.npmjs.com/package/color-scheme#schemes on how to use ColorScheme.
*/

scheme.from_hex(helpers.get_random_hex().replace('#',''))
.scheme('mono')
.variation('hard');

generators.triangular_mesh({
width: 800,
height: 360,
colors: scheme.colors()
}, function(err, img_data){
// console.log({img_url: `${bot.bot_url}/${img_data.path}`});

var img_name = img_data.path.replace('img/', '');

image_uploader.upload_image(img_data, function(err, img_url, data){
if (err){
console.log(err);
} else {
// console.log(img_url);

bot.create_post({
type: 'Note',
content: content,
attachment: [
{
url: img_url,
content: content // Image description here.
}
]
}, function(err, message){
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(message));
});
}
});
});
});

module.exports = router;
1 change: 0 additions & 1 deletion examples/images/README.md

This file was deleted.

40 changes: 0 additions & 40 deletions examples/images/routes/bot-endpoint.js

This file was deleted.

1 change: 1 addition & 0 deletions examples/tracery/routes/bot-endpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ router.get('/', function (req, res) {
var content = grammar.flatten("#origin#");

bot.create_post({
type: 'Note', // See www.w3.org/ns/activitystreams#objects
content: content
}, function(err, message){
res.setHeader('Content-Type', 'application/json');
Expand Down
13 changes: 8 additions & 5 deletions helpers/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ id INT NOT NULL AUTO_INCREMENT
date DATETIME DEFAULT current_timestamp
type VARCHAR(255)
content TEXT
thumbnail_url TEXT
attachment TEXT [this is a stringified JSON, see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment]
Followers table
Expand All @@ -28,7 +28,7 @@ module.exports = {
/*
TODO: Rewrite this with promises.
*/
db.run('CREATE TABLE IF NOT EXISTS Posts (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATETIME DEFAULT current_timestamp, type VARCHAR(255), content TEXT, thumbnail_url TEXT)', function(err, data){
db.run('CREATE TABLE IF NOT EXISTS Posts (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATETIME DEFAULT current_timestamp, type VARCHAR(255), content TEXT, attachment TEXT)', function(err, data){
if (err){
console.log(err);
}
Expand Down Expand Up @@ -92,11 +92,14 @@ module.exports = {
save_post: function(post_data, cb){
var post_type = post_data.type || 'Note',
post_content = post_data.content || '',
post_thumbnail_url = post_data.thumbnail_url || '';
post_attachment = post_data.attachment.toString() || '[]';


db.serialize(function() {
db.run(`INSERT INTO Posts (type, content, thumbnail_url) VALUES ("${post_type}", "${post_content}", "${post_thumbnail_url}")`, function(err, data){
// db.run(`INSERT INTO Posts (type, content, attachment) VALUES ("${post_type}", "${post_content}", "${post_attachment}")`, function(err, data){
db.run(`INSERT INTO Posts (type, content, attachment) VALUES ('${post_type}', '${post_content}', '${post_attachment}')`, function(err, data){
if (err){
console.log(err);
}
if (cb){
cb(err, this);
}
Expand Down
67 changes: 67 additions & 0 deletions helpers/general.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
if (typeof module !== 'undefined'){
var fs = require('fs'),
path = require('path'),
request = require('request');
}

var helpers = {
get_timestamp: function(){
return Math.round((new Date()).getTime() / 1000);
Expand All @@ -18,6 +24,67 @@ var helpers = {
// https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
var f = parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
return `#${(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1)}`;
},
load_image_assets: function(cb){
/* Load images from the assets folder */
console.log('reading assets folder...')
var that = this;
fs.readFile('./.glitch-assets', 'utf8', function (err, data) {
if (err) {
console.log('error:', err);
return false;
}
data = data.split('\n');
var data_json = JSON.parse('[' + data.join(',').slice(0, -1) + ']'),
deleted_images = data_json.reduce(function(filtered, data_img) {
if (data_img.deleted) {
var someNewValue = { name: data_img.name, newProperty: 'Foo' }
filtered.push(data_img.uuid);
}
return filtered;
}, []),
img_urls = [];

for (var i = 0, j = data.length; i < j; i++){
if (data[i].length){
var img_data = JSON.parse(data[i]),
image_url = img_data.url;

if (image_url && deleted_images.indexOf(img_data.uuid) === -1 && that.extension_check(image_url)){
var file_name = that.get_filename_from_url(image_url).split('%2F')[1];
// console.log(`- ${file_name}`);
img_urls.push(image_url);
}
}
}
cb(null, img_urls);
});
},
extension_check: function(url) {
var file_extension = path.extname(url).toLowerCase(),
extensions = ['.png', '.jpg', '.jpeg', '.gif'];
return extensions.indexOf(file_extension) !== -1;
},
get_filename_from_url: function(url) {
return url.substring(url.lastIndexOf('/') + 1);
},
load_image: function(url, cb) {
console.log(`loading remote image: ${url} ...`);
request({url: url, encoding: null}, function (err, res, body) {
if (!err && res.statusCode == 200) {
var b64content = 'data:' + res.headers['content-type'] + ';base64,';
console.log('image loaded...');
cb(null, body.toString('base64'));
} else {
console.log('ERROR:', err);
cb(err);
}
});
},
download_file: function(uri, filename, cb){
request.head(uri, function(err, res, body){
request(uri).pipe(fs.createWriteStream(filename)).on('close', cb);
});
}
};

Expand Down
Loading

0 comments on commit 7c7f4f2

Please sign in to comment.