一個在編程時“玲姐”語音各種稱讚你的 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章