Publish prototype for bot
Signed-off-by: Sam Therapy <sam@samtherapy.net>
This commit is contained in:
parent
d922bb67ce
commit
c97f1955de
5 changed files with 142 additions and 25 deletions
|
@ -13,11 +13,9 @@ steps:
|
|||
- name: build
|
||||
image: node
|
||||
commands:
|
||||
- yarn
|
||||
- yarn build
|
||||
|
||||
- name: test
|
||||
image: node
|
||||
commands:
|
||||
- yarn
|
||||
- yarn test
|
||||
|
|
47
README.md
47
README.md
|
@ -1,3 +1,48 @@
|
|||
# fediverse-imagebot
|
||||
|
||||
A bot that posts images to the Fediverse
|
||||
[![Build Status](https://ci.rint.osaka/api/badges/NotSam/fediverse-imagebot/status.svg)](https://ci.rint.osaka/NotSam/fediverse-imagebot)
|
||||
|
||||
A bot that posts images to the Fediverse.
|
||||
|
||||
Should be compatible with Mastodon, Misskey and Pleroma!
|
||||
|
||||
## Quick start guide
|
||||
1. You need to have `npm` and `nodejs` installed.
|
||||
|
||||
2. Install `yarn`: \
|
||||
`npm install --global yarn`
|
||||
- This may be need to ran with `sudo` depending on your installation.
|
||||
|
||||
3. Clone the repository: \
|
||||
`git clone https://git.freecumextremist.com/NotSam/fediverse-imagebot.git`
|
||||
|
||||
4. Install dependencies: \
|
||||
`yarn`
|
||||
|
||||
5. Build: \
|
||||
`yarn build`
|
||||
|
||||
6. Obtain a token. This can be done with an external tool or obtained by running `yarn token` and following the directions.
|
||||
- `yarn token` will generate a configuration file located at `config.json`
|
||||
|
||||
7. Put images in the `images` folder.
|
||||
- By default the bot will look for SFW images at `images/sfw` and NSFW images at `images/nsfw`. This can be configured.
|
||||
|
||||
8. Run the bot: \
|
||||
`yarn bot`
|
||||
|
||||
You're done! The bot should post an image to the fediverse instance of your choosing!
|
||||
|
||||
## Automating the bot
|
||||
*TODO: Elaborate more*
|
||||
|
||||
The bot can be automated to post images at set times using a cronjob. \
|
||||
Example cron configuration:
|
||||
```
|
||||
0 * * * * cd /path/to/fediverse-imagebot && yarn bot -m "Message"
|
||||
```
|
||||
This example will run the bot every hour on the hour with the post message `Message`.
|
||||
## Additional information
|
||||
Additional help can be found by running `yarn bot -h` or `yarn token -h`.
|
||||
|
||||
|
||||
|
|
10
package.json
10
package.json
|
@ -12,14 +12,16 @@
|
|||
},
|
||||
"name": "fediverse-imagebot",
|
||||
"version": "0.1.0",
|
||||
"description": "Imagebot for the fediverse (Pleroma, Mastodon, Misskey)",
|
||||
"description": "Image bot for the fediverse (Pleroma, Mastodon, Misskey)",
|
||||
"main": "dist/bot.js",
|
||||
"scripts": {
|
||||
"build": "npm run clean && tsc",
|
||||
"build": "yarn run clean && tsc",
|
||||
"clean": "rm -rf dist",
|
||||
"token": "node ./dist/gen-token.js",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"test": "echo \"No tests yet!\" && exit 0",
|
||||
"gen-token": "node ./dist/gen-token.js"
|
||||
"bot": "node ./dist/bot.js",
|
||||
"test": "echo \"No tests yet!\" && exit 0"
|
||||
|
||||
},
|
||||
"repository": "https://git.freecumextremist.com/NotSam/fediverse-imagebot.git",
|
||||
"author": "Sam Therapy <sam@samtherapy.net>",
|
||||
|
|
87
src/bot.ts
87
src/bot.ts
|
@ -1,6 +1,8 @@
|
|||
#!/usr/bin/env node
|
||||
import commandLineArgs from "command-line-args";
|
||||
import commandLineUsage from "command-line-usage";
|
||||
import * as fs from "fs";
|
||||
import generator, { Entity, Response } from "megalodon";
|
||||
import { exit } from "process";
|
||||
|
||||
|
||||
|
@ -19,13 +21,37 @@ const optionDefinitions = [
|
|||
description: "Print debugging output."
|
||||
},
|
||||
{
|
||||
name: "directory",
|
||||
name: "config",
|
||||
type: String,
|
||||
alias: "d",
|
||||
description: "The directory of images for the bot to post.",
|
||||
defaultValue: "./images",
|
||||
typeLabel: "<files>"
|
||||
alias: "c",
|
||||
description: "Path to the configuration file.",
|
||||
defaultValue: "./config.json",
|
||||
typeLabel: "<file>"
|
||||
},
|
||||
{
|
||||
name: "sfw_directory",
|
||||
type: String,
|
||||
alias: "s",
|
||||
description: "The directory of (SFW) images for the bot to post.",
|
||||
defaultValue: "./images/sfw",
|
||||
typeLabel: "<folder>"
|
||||
},
|
||||
{
|
||||
name: "nsfw_directory",
|
||||
type: String,
|
||||
alias: "n",
|
||||
description: "The directory of (NSFW) images for the bot to post. If it chooses these, they will be marked sensitive.",
|
||||
defaultValue: "./images/nsfw",
|
||||
typeLabel: "<folder>"
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
type: String,
|
||||
alias: "m",
|
||||
description: "The message to post with the image.",
|
||||
defaultValue: "",
|
||||
typeLabel: "<message>"
|
||||
}
|
||||
];
|
||||
|
||||
const args = commandLineArgs(optionDefinitions);
|
||||
|
@ -47,6 +73,53 @@ if (args.help) {
|
|||
console.log(usage);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// JSON object read from config file
|
||||
const data = JSON.parse(fs.readFileSync("./config.json", "utf8"));
|
||||
console.log(data);
|
||||
|
||||
const sfw_files = fs.readdirSync(args.sfw_directory);
|
||||
const nsfw_files = fs.readdirSync(args.nsfw_directory);
|
||||
const random = Math.floor(Math.random() * (sfw_files.length + nsfw_files.length));
|
||||
|
||||
// Get image from directory and mark it as sensitive if it's in the nsfw directory
|
||||
let image: fs.ReadStream;
|
||||
let sensitive: boolean;
|
||||
if (random >= sfw_files.length) {
|
||||
// Random Image is NSFW, mark it sensitive
|
||||
image = fs.createReadStream(args.nsfw_directory + "/" + nsfw_files[ random - sfw_files.length ]);
|
||||
sensitive = true;
|
||||
}
|
||||
else {
|
||||
// Image is SFW, mark it not sensitive
|
||||
image = fs.createReadStream(args.sfw_directory + "/" + sfw_files[ random ]);
|
||||
sensitive = false;
|
||||
}
|
||||
|
||||
const client = generator(data.type, data.instance, data.accessToken);
|
||||
client.uploadMedia(image).then((res: Response<Entity.Attachment>) => {
|
||||
client.postStatus(args.message, {
|
||||
media_ids: [ res.data.id ],
|
||||
visibility: "unlisted",
|
||||
sensitive: sensitive
|
||||
}
|
||||
).then((res: Response<Entity.Status>) => {
|
||||
console.log("Successfully posted to " + data.instance);
|
||||
if (args.verbose)
|
||||
console.log(console.log(res.data));
|
||||
exit(0);
|
||||
}
|
||||
).catch((err: Error) => {
|
||||
console.error("Error posting to " + data.instance);
|
||||
console.error("Run with -v to see the full error.");
|
||||
if (args.verbose)
|
||||
console.error(err);
|
||||
exit(1);
|
||||
}
|
||||
);
|
||||
}).catch((err: Error) => {
|
||||
console.error("Error uploading image to " + data.instance);
|
||||
console.error("Run with -v to see the full error.");
|
||||
if (args.verbose)
|
||||
console.error(err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@ const optionDefinitions = [
|
|||
description: "Print debugging output."
|
||||
}
|
||||
];
|
||||
|
||||
const args = commandLineArgs(optionDefinitions);
|
||||
|
||||
if (args.help) {
|
||||
const usage = commandLineUsage([
|
||||
{
|
||||
|
@ -46,20 +44,23 @@ if (args.verbose) {
|
|||
console.log("Running in verbose mode.");
|
||||
console.log();
|
||||
}
|
||||
|
||||
|
||||
const instance: string = question("Instance URL: ");
|
||||
callDetector(instance).then(type => {
|
||||
let clientId!: string;
|
||||
let clientSecret!: string;
|
||||
const client = generator(type, instance);
|
||||
client.registerApp("Node Imagebot", { scopes: [ "write" ] })
|
||||
client.registerApp("Node Imagebot", { website: "https://git.freecumextremist.com/NotSam/fediverse-imagebot" })
|
||||
.then((appData) => {
|
||||
clientId = appData.clientId;
|
||||
clientSecret = appData.clientSecret;
|
||||
const clientId = appData.clientId;
|
||||
const clientSecret = appData.clientSecret;
|
||||
console.log("Please open this URL in your browser for the authorization code.");
|
||||
console.log(appData.url);
|
||||
const code = question("Authorization Code: ");
|
||||
let code: string;
|
||||
if (type === "misskey") {
|
||||
code = appData.session_token || "";
|
||||
question("Authenticate with Misskey, then hit return.");
|
||||
} else {
|
||||
code = question("Authorization Code: ");
|
||||
}
|
||||
client.fetchAccessToken(clientId, clientSecret, code)
|
||||
.then((tokenData: OAuth.TokenData) => {
|
||||
if (args.verbose) {
|
||||
|
@ -82,7 +83,6 @@ callDetector(instance).then(type => {
|
|||
console.error(err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
})
|
||||
.catch((err: Error) => { // catch for registerApp
|
||||
console.error("App registration failure!");
|
||||
|
@ -92,7 +92,6 @@ callDetector(instance).then(type => {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
async function callDetector(instance: string) {
|
||||
const type = await detector(instance).catch( (err) => {
|
||||
console.error("This does not seem to be a valid instance!");
|
||||
|
|
Reference in a new issue