是否聽說過程序員鼓勵師,不久前出了一款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