feat(fedi): allow media uploads

This commit is contained in:
vulet 2020-07-03 17:10:55 +08:00
parent 402594f109
commit 2d714943e7
5 changed files with 71 additions and 2 deletions

61
commands/media.js Normal file
View file

@ -0,0 +1,61 @@
const qs = require('qs');
const axios = require('axios');
const FormData = require('form-data');
const mediaDownload = async (url, types) => {
const media = await axios({ method: 'GET', url, responseType: 'arraybuffer' });
if (media.statusText !== 'OK' || !types.includes(media.headers['content-type'])) throw media;
return {
data: media.data,
//filename: //TODO,
mimetype: media.headers['content-type']
};
};
const mediaUpload = async ({ domain, token }, { data, mimetype }) => {
const form = new FormData();
form.append('file', data, {
filename: 'upload',
contentType: mimetype,
});
const upload = await axios({
method: 'POST',
url: `${domain}/api/v1/media`,
headers: form.getHeaders({ Authorization: `Bearer ${token}` }),
data: form,
});
if(upload.statusText !== 'OK') throw upload;
return upload.data.id;
};
const run = async (matrixClient, { roomId }, mediaURL, content, registrar) => {
const fediverse = registrar.config.fediverse;
const media = await mediaDownload(mediaURL, registrar.config.matrix.mimetypes);
const mediaId = await mediaUpload(fediverse, media);
const response = await axios({
method: 'POST',
url: `${fediverse.domain}/api/v1/statuses`,
headers: { Authorization: `Bearer ${fediverse.token}`, 'Content-Type': 'application/x-www-form-urlencoded' },
data : qs.stringify({
status: content,
content_type: `text/markdown`,
media_ids: [ mediaId ],
}, { arrayFormat: 'brackets' })
});
return matrixClient.sendHtmlNotice(roomId, '', `<a href="${response.data.url}">${response.data.id}</a>`);
}
exports.runQuery = async (client, room, userInput, registrar) => {
try {
let chunks = userInput.trim().split(' ');
if(chunks.length < 2) throw '';
const url = new URL(chunks[0]);
chunks.shift();
if(url.protocol !== 'https:') throw '';
if(!registrar.config.matrix.domains.includes(url.hostname)) throw '';
if(!/^\/_matrix\/media\/r0\/download\/[^/]+\/[^/]+\/?$/.test(url.pathname)) throw '';
return await run(client, room, url.toString(), chunks.join(' '), registrar);
} catch(e) {
return client.sendHtmlNotice(room.roomId, 'Sad!', `<strong>Sad!</strong>`).catch(()=>{});
}
};

View file

@ -3,6 +3,8 @@ module.exports = {
domain: 'https://your_homeserver.com', domain: 'https://your_homeserver.com',
user: 'your_user', user: 'your_user',
password: 'your_password', password: 'your_password',
domains: [ 'your_homeserver.com' ],
mimetypes: [ 'image/png', 'image/jpeg' ]
}, },
fediverse: { fediverse: {
domain: 'https://your_federation.com', domain: 'https://your_federation.com',

View file

@ -127,6 +127,10 @@ let CreateClient = (token, user_id) => {
if (command === 'invidious') { if (command === 'invidious') {
registrar.invidious.runQuery(matrixClient, room, userInput, registrar); registrar.invidious.runQuery(matrixClient, room, userInput, registrar);
} }
if (command === 'media') {
registrar.media.runQuery(matrixClient, room, userInput, registrar);
}
} }
}); });

View file

@ -21,7 +21,8 @@
"axios": "^0.19.2", "axios": "^0.19.2",
"file-system": "^2.2.2", "file-system": "^2.2.2",
"matrix-js-sdk": "^2.4.6", "matrix-js-sdk": "^2.4.6",
"jsdom": "^16.2.2" "jsdom": "^16.2.2",
"form-data": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^5.16.0", "eslint": "^5.16.0",

View file

@ -19,4 +19,5 @@ module.exports = {
archive: require('./commands/archive.js'), archive: require('./commands/archive.js'),
nitter: require('./commands/nitter.js'), nitter: require('./commands/nitter.js'),
invidious: require('./commands/invidious.js'), invidious: require('./commands/invidious.js'),
media: require('./commands/media.js')
}; };