首先,需要自己去discord或者slack申请账号,我使用的翻译api是用的牛津词典的,但是它对词组或者语句的支持不好(可能是不调用的api不对吧),所以又申请了俄罗斯的yandex的翻译接口,这个接口的翻译结果很简短。
本来是想用discord的,后来发现slack的开发生态貌似好点,并且开发文档也详细些,所以最好我是主打slack了。哈哈哈。

// index.js
const Discord = require('discord.js');
require('env2')('./.env')

const dictionaryCtrl = require('./modules/dictionary/control');
const translateCtrl = require('./modules/translate/control');
const slackHook = require('./hooks/slack');
const utils = require('./utils');

const server = require('./server'); // load express server

const client = new Discord.Client()
client.on('ready', () => {
  console.log("Connected as " + client.user.tag)
})

const replyHook = (word) => {
  slackHook(word); // alway call the slack hook
  return (msg)=> {
    return msg.reply.bind(msg); // keep this in msg
  }
};

client.on('message', msg => {
  replyHook(msg.toString().replace(/^< @[0-9]+>,/g, ''));
  if(/^t\s/.test(msg)){
    const word = msg.toString().replace(/^t\s/, '');
    const hook = replyHook(word)(msg);
    const replyText = utils.recurseCb(hook);

    const isSingleWord = word.split(' ').length === 1;
    if(isSingleWord){
      dictionaryCtrl.discord(replyText)(word);
    }else{
      translateCtrl(replyText)(word);
    }
  }
})

const token = process.env.BOT_TOKEN;
client.login(token)

replyHook里面可以看到我放了一个slackHook,所以我发送的discord的消息都会调用这个钩子,所以发的消息都会发到slack,如果只是建立discord的客户端连接的话,是不用express,这里用到了express是为了使用slack的webHook。

// /server/index.js
const express = require( "express" );
const bodyParser = require('body-parser');

// create an express object: a Web server
const app = express();
const dictionaryCtrl = require('../modules/dictionary/control');

app.use(bodyParser.json()); 
app.use(bodyParser.urlencoded({
  extended: false
}));

app.get( "/", function( request, response ) {
  response.send( "<h1>Hello :)</h1><p><a href='/about'>About</a></p>" ); 
});


app.post('/slackEvent', (req, res) => {
  const {challenge, type, subtype} = req.body;
  console.log('/slackEvent', type, subtype);
  res.send({challenge})
});

app.post('/slackInteract', (req, res) => {
  console.log('/slackInteract', req.body);
  res.send({
    "response_type": "ephemeral",
    "replace_original": false,
    "text": "I got it"
  }); // 避免原有的内容消失
});

app.post('/slackMsgMenu', (req, res) => {
  console.log('/slackMsgMenu', req.body);
  res.send('slackMsgMenu');
});

app.post('/translate', (req, res) => {
  const {text, response_url} = req.body;
  dictionaryCtrl.slack(res.send.bind(res))(text);
});

app.get( "*", function( request, response ) {
  response.send( "no special" );
});


const port = process.env.PORT;
app.listen( port );
console.log('express server on ' + port);
module.exports = app;

接下来是translate的dictionary control

// /modules/dictionary/control.js
const main = require('./index');
module.exports = {
  discord: (replyFn) => (word) => main(word).then(res => {
    if(res.status === 200){
      const {results} = res.data;
      results.forEach((result, index) => {
        replyFn(index, '+');
        result.lexicalEntries.forEach((lexicalEntry, index2) => {
          replyFn(index2, '+');
          replyFn(lexicalEntry, 'lexicalCategory');
          replyFn(lexicalEntry.pronunciations, 'phoneticSpelling');
          lexicalEntry.entries && lexicalEntry.entries.forEach(entry => {
            entry.senses && entry.senses.forEach(sense => {
              replyFn(sense, 'definitions');
              sense.examples && sense.examples.forEach(example => {
                replyFn(example, 'text', 'Example');
              });
            });
          });
          replyFn(index, '=');
        });
        replyFn(index, '=');
      });
    }
  }).catch(err => {
    console.log('err ', err);
  }),
  slack: (replyFn) =>(word) => main(word).then(res => {
    const resultJson = {
      text: word,
      attachments: []
    };

    if(res.status === 200){
      const {results} = res.data;
      results.forEach((result) => {
        let attachment = {
          color: "#3366FF",
          fields: [],
        };
        resultJson.attachments.push(attachment);
        result.lexicalEntries.forEach((lexicalEntry) => {
          attachment.fields.push({
            title: lexicalEntry.lexicalCategory,
            value: (lexicalEntry.pronunciations || []).map(item => `${(item.dialects || []).join(' ')} -> ${item.phoneticSpelling}`)  .join(','),
            short: true,
          });
          lexicalEntry.entries && lexicalEntry.entries.forEach(entry => {
            entry.senses && entry.senses.forEach(sense => {
              let att = {
                title: 'Definition',
                text: (sense.definitions || []).join(','),
                color: "#66C947",
                fields: [],
              };
              sense.examples && sense.examples.forEach(example => {
                att.fields.push({
                  title: 'Example',
                  value: example.text,
                  short: true,
                });
              });
              resultJson.attachments.push(att);
            });
          }); 
        });
      });
      const lastAttachment = resultJson.attachments[resultJson.attachments.length-1];
      lastAttachment.footer = 'from Dictionary Api';
      lastAttachment.color = '#FF9333';
      lastAttachment.ts = Date.now();
      lastAttachment.callback_id = 'word_remembered';
      lastAttachment.actions = [ {
        "name": "game",
        "text": "Remembered",
        "type": "button",
        "value": "1",
        "style": "primary"
      },
      {
        "name": "game",
        "text": "Not...",
        "type": "button",
        "value": "0",
        "style": "danger"
      },
      {
        "name": "game",
        "text": "I don't know .",
        "type": "button",
        "value": "-1",
        "style": "danger",
        "confirm": {
          "title": "Are you sure?",
          "text": "Wouldn't you prefer to give up?",
          "ok_text": "Yes",
          "dismiss_text": "No"
        }
      }];

      console.log('resultJson ', resultJson);
      replyFn(resultJson);
    }
  }).catch(err => {
    console.log('err ', err);
  }),
};

剩下的代码请再我的github上查看


发表评论