一个在编程时“玲姐”语音各种称赞你的 IDEA 扩展插件,萝莉音带耳机!IDEA 彩虹屁插件!

是否听说过程序员鼓励师,不久前出了一款vscode的插件rainbow-fart,可以在写代码的时候,匹配到特定关键词就疯狂的拍你马屁。

vscode的下载尝试过,但是作为日常将IDEA作为主力生产工具的同学来说,如何体验呢? 于是假期花了一点时间,写了一个idea版本的插件idea-rainbow-fart。

安装方法

先到下载最新的插件。关注公众号Java精选,扫描下方二维码,回复彩虹屁,即可获取下载文件。直接放到对应目录即可应用,试一试被疯狂拍你马屁的插件吧!!!

qrcode.jpg

image.png

下载rainbow-fart-1.0-SNAPSHOT.zip,然后打开Idea的插件目录,比如笔者的目录是C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\plugins

将rainbow-fart-1.0-SNAPSHOT.zip解压到plugins目录,如图所示:

image.png

解压

然后重启IDEA即可。

使用内置语音包

打开设置:

将voice package type设置为builtin

可以选择内置语音包,共三个,一个官方的中文和英文,一个tts合成的(玲姐姐)

image.png

使用第三方语音包

image.png

将voice package type设置为custom

可以到 https://github.com/topics/vscode-rainbow-fart 查找语音包。

点击确定生效。

使用TTS(推荐)

本插件特色功能,支持自定义关键词和文本,鼠标点击表格可以修改关键词和回复语,修改时enter回车换行,一行代表一个

image.png

TTS 使用科大讯飞提供的流式API。

原理

没啥原理,就是一款简单的idea插件,对没写过插件的我来说,需要先看下官方文档,基本上看下面这一篇就OK:

https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started.html

读取语音包

先来看下语音包的设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "name""KugimiyaRie",
  "display-name""KugimiyaRie 钉宫理惠 (Japanese)",
  "avatar""louise.png",
  "avatar-dark""shana.png",
  "version""0.0.1",
  "description""傲娇钉宫,鞭写鞭骂",
  "languages": [
    "javascript"
  ],
  "author""zthxxx",
  "gender""female",
  "locale""jp",
  "contributes": [
    {
      "keywords": [
        "function",
        "=>"
      ],
      "voices": [
        "function_01.mp3",
        "function_02.mp3",
        "function_03.mp3"
      ]
    },
...
]
}

对Java来说,定义两个bean类,解析json即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
     * 加载配置
     */
    public static void loadConfig() {
        try {
            //
            FartSettings settings = FartSettings.getInstance();
            if (!settings.isEnable()) {
                return;
            }
            String json = readVoicePackageJson("manifest.json");
            Gson gson = new Gson();
            Manifest manifest = gson.fromJson(json, Manifest.class);
            // load contributes.json
            if (manifest.getContributes() == null) {
                String contributesText = readVoicePackageJson("contributes.json");
                Manifest contributes = gson.fromJson(contributesText, Manifest.class);
                if (contributes.getContributes() != null) {
                    manifest.setContributes(contributes.getContributes());
                }
            }
            Context.init(manifest);
        catch (IOException e) {
        }
    }

监控用户输入

自定义一个Handler类继承TypedActionHandlerBase即可,需要实现的方法原型是:

1
public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext)

chartTyped就是输入的字符,我们可以简单粗暴的将这些组合到一起即可,用一个list缓存,然后将拼接后的字符串匹配关键词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 private List<String> candidates = new ArrayList<>();
    @Override
    public void execute(@NotNull Editor editor, char charTyped, @NotNull DataContext dataContext) {
        candidates.add(String.valueOf(charTyped));
        String str = StringUtils.join(candidates, "");
        try {
            List<String> voices = Context.getCandidate(str);
            if (!voices.isEmpty()) {
                Context.play(voices);
                candidates.clear();
            }
        }catch (Exception e){
            // TODO
            candidates.clear();
        }
        if (this.myOriginalHandler != null) {
            this.myOriginalHandler.execute(editor, charTyped, dataContext);
        }
    }

匹配关键词更简单,将读取出来的json,放到hashmap中,然后遍历map,如果包含关键词就作为语音候选:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static List<String> getCandidate(String inputHistory) {
        final List<String> candidate = new ArrayList<>();
        FartSettings settings = FartSettings.getInstance();
        if (!settings.isEnable()) {
            return candidate;
        }
        if (keyword2Voices != null) {
            keyword2Voices.forEach((keyword, voices) -> {
                if (inputHistory.contains(keyword)) {
                    candidate.addAll(voices);
                }
            });
        }
        if (candidate.isEmpty()) {
            candidate.addAll(findSpecialKeyword(inputHistory));
        }
        return candidate;
    }

如果找到候选,就播放。

播放

为了防止同时播放多个语音,我们用一个单线程线程池来搞定。播放器使用javazoom.jl.player.Player

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
     * play in a single thread pool
     */
    static ExecutorService playerTheadPool;
static {
        ThreadFactory playerFactory = new ThreadFactoryBuilder()
                .setNameFormat("player-pool-%d").build();
        playerTheadPool = new ThreadPoolExecutor(11,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1024), playerFactory, new ThreadPoolExecutor.AbortPolicy());
    }
public static void play(List<String> voices) {
        FartSettings settings = FartSettings.getInstance();
        if (!settings.isEnable()) {
            return;
        }
        // play in single thread
        playerTheadPool.submit(() -> {
            String file = voices.get(new Random().nextInt() % voices.size());
            try {
                InputStream inputStream = null;
                if (StringUtils.isEmpty(settings.getCustomVoicePackage())) {
                    inputStream = Context.class.getResourceAsStream("/build-in-voice-chinese/" + file);
                else {
                    File mp3File = Paths.get(settings.getCustomVoicePackage(), file).toFile();
                    if (mp3File.exists()) {
                        try {
                            inputStream = new FileInputStream(mp3File);
                        catch (FileNotFoundException e) {
                        }
                    else {
                        return;
                    }
                }
                if (inputStream != null) {
                    Player player = new Player(inputStream);
                    player.play();
                    player.close();
                }
            catch (JavaLayerException e) {
            }
        });
    }

开源地址: https://github.com/jadepeng/idea-rainbow-fart,欢迎fork代码,贡献代码。

插件参考,感谢原作者的贡献

插件开发参考 https://github.com/izhangzhihao/intellij-rainbow-fart

语音包和插件icon源于 https://github.com/SaekiRaku/vscode-rainbow-fart

作者:jqpeng的技术记事本

来源:https://www.cnblogs.com/xiaoqi/p/idea-rainbow-fart.html

posted @ 2021-09-09 15:17  yoodb  阅读(925)  评论(0编辑  收藏  举报