是否聽說過程序員鼓勵師,不久前出了一款vscode的插件rainbow-fart,可以在寫代碼的時候,匹配到特定關鍵詞就瘋狂的拍你馬屁。
vscode的下載嘗試過,但是作爲日常將IDEA作爲主力生產工具的同學來說,如何體驗呢? 於是假期花了一點時間,寫了一個idea版本的插件idea-rainbow-fart。
安裝方法
先到下載最新的插件。關注公衆號Java精選,掃描下方二維碼,回覆彩虹屁,即可獲取下載文件。直接放到對應目錄即可應用,試一試被瘋狂拍你馬屁的插件吧!!!
下載rainbow-fart-1.0-SNAPSHOT.zip,然後打開Idea的插件目錄,比如筆者的目錄是C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\plugins
將rainbow-fart-1.0-SNAPSHOT.zip解壓到plugins目錄,如圖所示:
解壓
然後重啓IDEA即可。
使用內置語音包
打開設置:
將voice package type設置爲builtin
可以選擇內置語音包,共三個,一個官方的中文和英文,一個tts合成的(玲姐姐)
使用第三方語音包
將voice package type設置爲custom
可以到 https://github.com/topics/vscode-rainbow-fart 查找語音包。
點擊確定生效。
使用TTS(推薦)
本插件特色功能,支持自定義關鍵詞和文本,鼠標點擊表格可以修改關鍵詞和回覆語,修改時enter回車換行,一行代表一個
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( 1 , 1 , 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