├── img ├── hiden.png ├── mail.png ├── main.png ├── menu.png ├── talk.png ├── talk2.png ├── talk3.png ├── bangumi.png └── lottery.png ├── lib ├── javax.mail.jar ├── fastjson-1.2.56.jar ├── commons-lang3-3.9.jar ├── httpclient-4.5.8.jar ├── slf4j-api-1.7.25.jar └── Java-WebSocket-1.4.0.jar ├── src └── com │ └── magic │ ├── OptionMenu.java │ ├── mail │ ├── MailInterface.java │ ├── ExQQMail.java │ ├── QQMailPro.java │ ├── SinaMail.java │ ├── Wy163Mail.java │ ├── MailService.java │ ├── QQMail.java │ └── Mail.java │ ├── SingleThreadPool.java │ ├── util │ ├── HttpHelper.java │ └── PropertiesHelper.java │ ├── Simulator.java │ ├── MagicWebSocketClient.java │ ├── AsciiPic.java │ ├── ChatRobotGUI.java │ └── ApiService.java ├── LICENSE └── README.md /img/hiden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/hiden.png -------------------------------------------------------------------------------- /img/mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/mail.png -------------------------------------------------------------------------------- /img/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/main.png -------------------------------------------------------------------------------- /img/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/menu.png -------------------------------------------------------------------------------- /img/talk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/talk.png -------------------------------------------------------------------------------- /img/talk2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/talk2.png -------------------------------------------------------------------------------- /img/talk3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/talk3.png -------------------------------------------------------------------------------- /img/bangumi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/bangumi.png -------------------------------------------------------------------------------- /img/lottery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/img/lottery.png -------------------------------------------------------------------------------- /lib/javax.mail.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/javax.mail.jar -------------------------------------------------------------------------------- /lib/fastjson-1.2.56.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/fastjson-1.2.56.jar -------------------------------------------------------------------------------- /lib/commons-lang3-3.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/commons-lang3-3.9.jar -------------------------------------------------------------------------------- /lib/httpclient-4.5.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/httpclient-4.5.8.jar -------------------------------------------------------------------------------- /lib/slf4j-api-1.7.25.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/slf4j-api-1.7.25.jar -------------------------------------------------------------------------------- /lib/Java-WebSocket-1.4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhiteMagic2014/Live2dChatWidget/HEAD/lib/Java-WebSocket-1.4.0.jar -------------------------------------------------------------------------------- /src/com/magic/OptionMenu.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | public interface OptionMenu { 4 | 5 | String menuName(); 6 | 7 | void execute(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/magic/mail/MailInterface.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | /** 4 | * 邮箱统一关闭方法 5 | * 6 | * @author chenhaoyu 7 | * 8 | */ 9 | public interface MailInterface { 10 | 11 | /** 12 | * 统一的关闭方法 13 | */ 14 | public void close(); 15 | 16 | /** 17 | * 定时检查方法 18 | */ 19 | public void check(); 20 | } 21 | -------------------------------------------------------------------------------- /src/com/magic/mail/ExQQMail.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.List; 4 | import java.util.Properties; 5 | 6 | import com.magic.ApiService; 7 | 8 | /** 9 | * 企业qq邮箱监听 10 | * 11 | * @author chenhaoyu 12 | * 13 | */ 14 | public class ExQQMail extends Mail { 15 | 16 | public ExQQMail(ApiService handler, String userName, String passWord, List folders) { 17 | super(handler, userName, passWord, folders); 18 | } 19 | 20 | @Override 21 | public Properties getProperties() { 22 | 23 | String host = "imap.exmail.qq.com";// QQ企业邮箱的imap服务器 24 | int port = 993;// 端口 25 | 26 | Properties props = new Properties(); 27 | props.put("mail.imap.ssl.enable", "true"); 28 | props.put("mail.imap.host", host); 29 | props.put("mail.imap.port", port); 30 | props.put("mail.transport.protocol", "imap"); 31 | props.put("mail.imap.usesocketchannels", "true"); 32 | 33 | return props; 34 | } 35 | 36 | @Override 37 | public String getMailName() { 38 | return "腾讯企业邮箱"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/magic/mail/QQMailPro.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.List; 4 | import java.util.Properties; 5 | 6 | import com.magic.ApiService; 7 | 8 | /** 9 | * 另一种更快捷的方式实现qqMail 10 | * 11 | * @author chenhaoyu 12 | * 13 | */ 14 | public class QQMailPro extends Mail { 15 | 16 | public QQMailPro(ApiService handler, String userName, String passWord, List folders) { 17 | super(handler, userName, passWord, folders); 18 | } 19 | 20 | @Override 21 | public Properties getProperties() { 22 | String host = "imap.qq.com";// QQ邮箱的imap服务器 23 | int port = 993;// 端口 24 | 25 | Properties props = new Properties(); 26 | props.put("mail.imap.ssl.enable", "true"); 27 | props.put("mail.imap.host", host); 28 | props.put("mail.imap.port", port); 29 | props.put("mail.transport.protocol", "imap"); 30 | props.put("mail.imap.usesocketchannels", "true"); 31 | 32 | return props; 33 | } 34 | 35 | @Override 36 | public String getMailName() { 37 | return "QQ邮箱"; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/magic/mail/SinaMail.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.List; 4 | import java.util.Properties; 5 | 6 | import com.magic.ApiService; 7 | 8 | /** 9 | * 新浪邮箱监听 服务器不支持idle监听 懒得写轮询 先放着吧 10 | * 11 | * @author chenhaoyu 12 | * 13 | */ 14 | public class SinaMail extends Mail { 15 | 16 | public SinaMail(ApiService handler, String userName, String passWord, List folders) { 17 | super(handler, userName, passWord, folders); 18 | } 19 | 20 | @Override 21 | public Properties getProperties() { 22 | String host = "imap.sina.com";// QQ邮箱的imap服务器 23 | int port = 993;// 端口 24 | 25 | Properties props = new Properties(); 26 | props.put("mail.imap.ssl.enable", "true"); 27 | props.put("mail.imap.host", host); 28 | props.put("mail.imap.port", port); 29 | props.put("mail.transport.protocol", "imap"); 30 | props.put("mail.imap.usesocketchannels", "true"); 31 | 32 | return props; 33 | 34 | } 35 | 36 | @Override 37 | public String getMailName() { 38 | return "新浪邮箱"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/magic/mail/Wy163Mail.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.List; 4 | import java.util.Properties; 5 | 6 | import com.magic.ApiService; 7 | 8 | /** 9 | * 网易163邮箱 服务器不支持idle监听 懒得写轮询 先放着吧 10 | * 11 | * @author chenhaoyu 12 | * 13 | */ 14 | public class Wy163Mail extends Mail { 15 | 16 | public Wy163Mail(ApiService handler, String userName, String passWord, List folders) { 17 | super(handler, userName, passWord, folders); 18 | } 19 | 20 | @Override 21 | public Properties getProperties() { 22 | String host = "imap.163.com";// QQ企业邮箱的imap服务器 23 | int port = 993;// 端口 24 | 25 | Properties props = new Properties(); 26 | props.put("mail.imap.ssl.enable", "true"); 27 | props.put("mail.imap.host", host); 28 | props.put("mail.imap.port", port); 29 | props.put("mail.transport.protocol", "imap"); 30 | props.put("mail.imap.usesocketchannels", "true"); 31 | 32 | return props; 33 | } 34 | 35 | @Override 36 | public String getMailName() { 37 | return "网易163邮箱"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 magic chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/com/magic/SingleThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.ScheduledExecutorService; 6 | 7 | /** 8 | * 内部静态类 单例实现全局唯一线程池 9 | * 10 | * @author chenhaoyu 11 | * 12 | */ 13 | public class SingleThreadPool { 14 | 15 | private static class LazyHolder { 16 | private static final SingleThreadPool INSTANCE = new SingleThreadPool(); 17 | } 18 | 19 | private SingleThreadPool() { 20 | System.out.println("构造线程池"); 21 | es = Executors.newCachedThreadPool();//普通线程池 : gui的窗体抖动 ; idleManager (一个邮箱占用一个线程); websocket 断线重连时所需临时新重启线程 22 | ses = Executors.newScheduledThreadPool(10);// 定长周期线程池 : websocket的心跳 ; 邮箱的心跳(一个邮箱占用一个线程) 23 | } 24 | 25 | public static final SingleThreadPool getInstance() { 26 | return LazyHolder.INSTANCE; 27 | } 28 | 29 | private ExecutorService es; 30 | 31 | private ScheduledExecutorService ses; 32 | 33 | public ExecutorService threadPool() { 34 | return es; 35 | } 36 | 37 | public ScheduledExecutorService scheduledThreadPool() { 38 | return ses; 39 | } 40 | 41 | // 关闭所有线程 42 | public void close() { 43 | es.shutdownNow(); 44 | ses.shutdownNow(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/com/magic/util/HttpHelper.java: -------------------------------------------------------------------------------- 1 | package com.magic.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | 9 | public class HttpHelper { 10 | 11 | public static String errInfo = "被玩坏了_(:з」∠)_"; 12 | 13 | public static String sendGet(String req_url) { 14 | StringBuffer buffer = new StringBuffer(); 15 | URL url = null; 16 | try { 17 | url = new URL(req_url); 18 | } catch (Exception e) { 19 | return errInfo; 20 | } 21 | HttpURLConnection httpUrlConn = null; 22 | 23 | try { 24 | httpUrlConn = (HttpURLConnection) url.openConnection(); 25 | httpUrlConn.setDoOutput(false); 26 | httpUrlConn.setDoInput(true); 27 | httpUrlConn.setUseCaches(false); 28 | httpUrlConn.setRequestMethod("GET"); 29 | httpUrlConn.connect(); 30 | } catch (Exception e) { 31 | return errInfo; 32 | } 33 | 34 | try (InputStream inputStream = httpUrlConn.getInputStream(); 35 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); 36 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) { 37 | 38 | String result = null; 39 | while ((result = bufferedReader.readLine()) != null) { 40 | buffer.append(result); 41 | } 42 | } catch (Exception e) { 43 | return errInfo; 44 | } finally { 45 | httpUrlConn.disconnect(); 46 | } 47 | return buffer.toString(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/magic/mail/MailService.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.magic.ApiService; 7 | 8 | public class MailService { 9 | 10 | /** 11 | * QQ邮箱 12 | */ 13 | public static final String QQ = "qq"; 14 | 15 | /** 16 | * 企业qq邮箱 17 | */ 18 | public static final String QQEX = "qqex"; 19 | 20 | /** 21 | * 网易163 22 | */ 23 | public static final String WY163 = "wy163"; 24 | 25 | /** 26 | * sina 27 | */ 28 | public static final String SINA = "sina"; 29 | 30 | // 负责某一个邮箱的监听实例 31 | private List mailHandlers; 32 | // api代理类 33 | private ApiService handler = null; 34 | 35 | public MailService(ApiService handler) { 36 | mailHandlers = new ArrayList(); 37 | this.handler = handler; 38 | } 39 | 40 | /** 41 | * 42 | * 新建邮箱监听 43 | * 44 | * @param type 45 | * 邮箱类别 46 | * @param userName 47 | * 用户名 48 | * @param passWord 49 | * 密码 50 | */ 51 | public void addMailListener(String type, String userName, String passWord, List folders) { 52 | 53 | switch (type) { 54 | case QQ: 55 | MailInterface qqMail = new QQMailPro(handler, userName, passWord, folders); 56 | mailHandlers.add(qqMail); 57 | break; 58 | 59 | case QQEX: 60 | MailInterface qqexMail = new ExQQMail(handler, userName, passWord, folders); 61 | mailHandlers.add(qqexMail); 62 | break; 63 | 64 | case WY163: 65 | MailInterface wy163Mail = new Wy163Mail(handler, userName, passWord, folders); 66 | mailHandlers.add(wy163Mail); 67 | break; 68 | 69 | case SINA: 70 | MailInterface sinaMail = new SinaMail(handler, userName, passWord, folders); 71 | mailHandlers.add(sinaMail); 72 | break; 73 | 74 | default: 75 | break; 76 | } 77 | 78 | } 79 | 80 | /** 81 | * 检查目前 所有邮箱监听状态 82 | */ 83 | public void check() { 84 | mailHandlers.forEach(mh -> mh.check()); 85 | } 86 | 87 | /** 88 | * 关闭 所有mail的 监听 文件夹 store 89 | */ 90 | public void close() { 91 | mailHandlers.forEach(mh -> mh.close()); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/com/magic/Simulator.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | 10 | import com.magic.mail.MailService; 11 | import com.magic.util.PropertiesHelper; 12 | 13 | //启动类 14 | public class Simulator { 15 | 16 | public static void main(String[] args) { 17 | PropertiesHelper.getInstance(); 18 | // 先启一般服务 19 | ApiService apiService = new ApiService("10086");// 预留了接上托盘软件的可能性 20 | // 启动邮箱 21 | String enableMail = PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_ENABLE); 22 | if (StringUtils.isNotBlank(enableMail) && enableMail.equals("T")) { 23 | apiService.setModelText("开启邮件提醒功能", 0); 24 | List defaultFolders = new ArrayList(); 25 | defaultFolders.add("inbox"); 26 | // qq邮箱 27 | if (StringUtils.isNotBlank(PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQ_ACC))) { 28 | String qqfold = PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQ_FOL); 29 | List fold = Arrays.asList(qqfold.split(",")).stream().filter(s -> StringUtils.isNotBlank(s)) 30 | .map(s -> "其他文件夹/" + s).collect(Collectors.toList()); 31 | 32 | fold.add("inbox"); 33 | apiService.addMailListener(MailService.QQ, 34 | PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQ_ACC), 35 | PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQ_KEY), fold); 36 | } 37 | // 企业qq邮箱 38 | if (StringUtils.isNotBlank(PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQEX_ACC))) { 39 | apiService.addMailListener(MailService.QQEX, 40 | PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQEX_ACC), 41 | PropertiesHelper.getInstance().getValue(PropertiesHelper.MAIL_QQEX_KEY), defaultFolders); 42 | } 43 | } 44 | // 开始绘图 45 | ChatRobotGUI gui = new ChatRobotGUI(apiService); 46 | // 给窗口浮动开一个独立线程 47 | SingleThreadPool.getInstance().threadPool().execute(gui); 48 | apiService.setModelText("启动成功 ✧(≖ ◡ ≖✿)嘿嘿", 0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Live2dChatWidget JAVA 4 | 5 | 6 | ### 申明 7 |   本小软件使用交谈接口为[茉莉机器人][1],茉莉机器人提供了免费简单的ai服务。 8 | 9 | ### 开发原因 10 |   痴迷live2d,steam上有个神软件啊,Live2DViewerEX,详细的自己度娘吧。玩久了之后不能满足于简单的互动了,于是找了个ai接口,写了个挂件(可惜官方没有开发接口,也可能是我不知道),用java swing写页面真是蛋疼 11 | 12 | ### 本项目所用环境 13 | - java version "1.8.0_121" 14 | - 开发ide eclipse 15 | - 运行需要jre运行环境 16 | - **注意:** 目前没有打算做成傻瓜式的(那样工作量太大 看心情填坑) 17 | 18 | ### 使用方法,直接编译打成jar包即可(后期可能会把适配好的包放上来) 19 | - 直接输入文字 , 调用api接口 20 | - $shell:[shell脚本] 执行shell **小白请务必无视这个功能!!!** 21 | - 框体左上角 点击 可以隐藏/显示框体(天知道用swing写渐变有多受苦) 22 | - 更多请看源码 23 | 24 | ### 备注 25 |    有很多功能局限性很大,比如shell调用 封装的几个指令只能我自己用,~~暂时也没有做定制化的打算,看什么时候想起来填坑了吧~~ 还是开坑了。同时接口回调的 表情 和json 没有处理,~~暂时懒得引入第三方的json处理包~~。 26 | 27 | ### 2019年05月09日更新 28 | - 得到了Live2DViewerEX的接口支持,启动时,如果检测到Live2DViewerEX运行,则会默认让1号位的模型负责对话。如果没有Live2DViewerEX运行,则会像之前那样,直接在对话板上对话 29 | - Live2DViewerEX运行的情况下 ~~$菜单~~ 现在只需点击右上角菜单按钮 可以让1号模型开启菜单,内附无聊的小代码 (仅在绑定Live2DViewerEX 成功后可用) 30 | - 每隔~~5分钟~~现在是20分钟 会有一个心跳包(一颗心扑通扑通的狂跳~),这是为了让插件和Live2DViewerEX 本体保持通讯,以免失联 31 | 32 | ### 2019年05月13日更新 33 | - 初步支持qq邮箱来件提示功能(imap协议) 34 | - 已预留接口 后期可能会适配其他邮箱 35 | - 个性化适配依然是个大坑 36 | 37 | ### 2019年05月14日更新 & 补充 38 | - 突然发现之前提交的版本 把自己的邮箱账密硬编码了...于是全部重新提交了一遍... 39 | - 将之前的邮件监听实现方式重构了一下,之后想适配多种不同邮箱的话,开发起来更快吧 40 | - 邮箱提示这边有个大坑 可以说是血崩状态, qq和tx企业邮箱 用旧版本的jre运行可能会出SSL上的问题,这是java的一个bug,需要去官方下载补丁替换2个jar包,这一步我感觉对萌新来说可能....就当没有邮箱这个功能吧(具体怎么操作不说了,免得误操作玩坏了jre... 至于技术朋友handshake_failure 错误 百度一下...) 41 | - 用新版本的jre应该没啥问题 42 | - 坑:同时sina 和 网易的163邮箱目前 遇到了监听失败的问题 试着解决一下,不行就只能放弃了.... 43 | - 后期准备加上追番提示功能...看心情更新 44 | 45 | ### 2019年05月16日更新 46 | - 新增追番查看功能(目前只有b站上的新番信息,估计也不会扩展了,找接口太麻烦了....) 47 | 48 | ### 2019年05月17日更新 49 | - 个性化配置文件算是做出来了,不过目前只写了个qq邮箱的配置 50 | - 在用户的目录下 创建了一个Live2dChatPlugin 文件夹 配置文件就存在里面 51 | - mail.enable=T 52 | 是否启动邮箱监听功能 T 开启/F关闭; 默认关闭 53 | - mail.qq.account=418379149@qq.com 54 | 需要监听的qq邮箱 55 | - mail.qq.key=xxxxxxxxxxx 56 | qq邮箱授权码 , 在qq邮箱-->设置-->账户 中找到开启 imap/smtp服务后获得 57 | - mail.qq.folders=apple,steam 58 | 默认为空则只监听收件箱,如果自己创建过新的收信规则 和自定义收件箱中的话 请加上想监听的自定义文件夹,多个用 英文逗号隔开 59 | 60 | ### 2019年05月20日 ~~发现bug~~ 已解决 61 | - 保持邮件监听的线程似乎出了一些问题,在调用后监听通知会失效,换句话说就是在~~第一次调用后~~ 9分钟后 邮箱监听失效。目前在尝试解决中.... 62 | - bug已解决 已打包修复后的版本 63 | 64 | 65 | ### 2019年05月22日 66 | - 新增了一些启动时的提示 67 | - 补偿了Folder长时间监听后断开的异常,增加了断线重连机制 68 | - 增加腾讯企业邮箱的支持(不支持指定额外收件夹,只监听收件箱) 69 | 70 | ### 2019年06月04日 对应版本号-1.1.1 71 | - 修复了websocket断线重连出错的bug 72 | - 邮箱监听超长时间后(6+小时候偶尔会失效 尝试定位问题解决中...) 73 | - 增加某些特殊保留字符的替换 74 | - 调整窗体显/隐 速度 75 | 76 | ### 预览 77 | #### 总览 78 | ![总览](img/main.png) 79 | 80 | #### 隐藏 81 | ![隐藏](img/hiden.png) 82 | 83 | #### 对话 84 | ![对话](img/talk.png) 85 | ![智能对答](img/talk2.png) 86 | ![天气预报](img/talk3.png) 87 | 88 | #### 菜单 89 | ![菜单](img/menu.png) 90 | 91 | #### 不负责猜双色球 92 | ![双色球](img/lottery.png) 93 | 94 | #### 邮件提示 95 | ![邮件提示](img/mail.png) 96 | 97 | #### 番剧查询 98 | ![番剧查询](img/bangumi.png) 99 | 100 | 101 | 102 | 103 | ### 参考资料 104 | - [茉莉机器人API][1] 105 | - [Live2DViewerEX中文文档][2] 106 | 107 | [1]: http://www.itpk.cn/ 108 | [2]: http://live2d.pavostudio.com/doc/zh-cn/exapi/ 109 | 110 | ## 版权声明 111 | 112 | **API 版权属于原作者,仅供研究学习,不得用于商业用途** 113 | 114 | MIT © WhiteMagic2014 115 | -------------------------------------------------------------------------------- /src/com/magic/MagicWebSocketClient.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.Iterator; 6 | import java.util.concurrent.ScheduledFuture; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import org.java_websocket.client.WebSocketClient; 10 | import org.java_websocket.handshake.ServerHandshake; 11 | 12 | import com.alibaba.fastjson.JSONObject; 13 | 14 | /** 15 | * 与live2dviewerEX 通讯的client 16 | * 17 | * @author chenhaoyu 18 | * 19 | */ 20 | public class MagicWebSocketClient extends WebSocketClient { 21 | 22 | ApiService handle = null; 23 | ScheduledFuture future = null; 24 | 25 | public MagicWebSocketClient(String serverUri, ApiService handler) throws URISyntaxException { 26 | super(new URI(serverUri)); 27 | this.handle = handler; 28 | } 29 | 30 | @Override 31 | public void onClose(int arg0, String arg1, boolean arg2) { 32 | // 标记ws不可用 33 | handle.setWSFlag(false); 34 | // 是否由服务器关闭连接(外部断开视为意外断开) 如果是的话 就重连 35 | if (arg2) { 36 | magicReconnect(); 37 | } else { 38 | System.out.println("WebSocket onClose"); 39 | } 40 | } 41 | 42 | @Override 43 | public void onError(Exception e) { 44 | System.out.println("WebSocket onError"); 45 | handle.setWSFlag(false); 46 | e.printStackTrace(); 47 | } 48 | 49 | @Override 50 | public void onMessage(String result) { 51 | System.out.println("WebSocket onMessage " + result); 52 | JSONObject resultObj = JSONObject.parseObject(result); 53 | handle.processCallback(resultObj); 54 | } 55 | 56 | @Override 57 | public void onOpen(ServerHandshake shake) { 58 | System.out.println("WebSocket onOpen..."); 59 | for (Iterator it = shake.iterateHttpFields(); it.hasNext();) { 60 | String key = it.next(); 61 | System.out.println(key + ":" + shake.getFieldValue(key)); 62 | } 63 | handle.setWSFlag(true); 64 | // (重新)开启心跳任务 65 | startHeart(); 66 | } 67 | 68 | /** 69 | * 开始心跳任务 70 | */ 71 | public void startHeart() { 72 | future = SingleThreadPool.getInstance().scheduledThreadPool().scheduleAtFixedRate(new Runnable() { 73 | @Override 74 | public void run() { 75 | try { 76 | handle.setModelText("一颗心扑通扑通的狂跳~", 0);// 默认让第一个接受心跳 77 | System.out.println(Thread.currentThread().getName() + " ———— WebSocket Heart ———— " 78 | + System.currentTimeMillis()); 79 | } catch (Exception e) { 80 | System.out.println("心跳出错"); 81 | e.printStackTrace(); 82 | } 83 | } 84 | }, 0, 20, TimeUnit.MINUTES);// 20分钟一次心跳包 85 | } 86 | 87 | /** 88 | * 断线重连重连 89 | */ 90 | public void magicReconnect() { 91 | // 重连前 先取消之前那个心跳任务 92 | future.cancel(true); 93 | // 重连 94 | SingleThreadPool.getInstance().threadPool().submit(new Runnable() { 95 | @Override 96 | public void run() { 97 | try { 98 | boolean result = reconnectBlocking(); 99 | if (result) { 100 | System.out.println("重连成功.."); 101 | } else { 102 | System.out.println("重连失败.."); 103 | } 104 | } catch (InterruptedException e) { 105 | System.out.println("重连失败.."); 106 | e.printStackTrace(); 107 | } 108 | } 109 | }); 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/com/magic/AsciiPic.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | import java.io.OutputStreamWriter; 9 | import java.io.Writer; 10 | 11 | import javax.imageio.ImageIO; 12 | 13 | public class AsciiPic { 14 | 15 | public static void createPicFile(String picPath) { 16 | File file = new File(getFileName(picPath)); 17 | try (OutputStream out = new FileOutputStream(file); Writer writer = new OutputStreamWriter(out);) { 18 | byte[] pic = createAsciiPic(picPath, 1, 1); 19 | out.write(pic); 20 | } catch (Exception e) { 21 | } 22 | } 23 | 24 | /** 25 | * 26 | * @Description:生成字符画 27 | * @param picPath 28 | * 文件路径 29 | * @param compressX 30 | * x轴采样率 最高为1 (1:1像素采样) 31 | * @param compressY 32 | * y轴采样率 最高为1 (1:1像素采样) 33 | * @author: chenhaoyu 34 | * @time:Jan 28, 2019 4:12:13 PM 35 | */ 36 | public static void createPic(String picPath, int compressX, int compressY) { 37 | File file = new File(getFileName(picPath)); 38 | 39 | compressX = compressX != 0 ? compressX : 3; 40 | compressY = compressY != 0 ? compressY : 5; 41 | 42 | try (OutputStream out = new FileOutputStream(file); Writer writer = new OutputStreamWriter(out);) { 43 | byte[] pic = createAsciiPic(picPath, compressX, compressY); 44 | out.write(pic); 45 | } catch (Exception e) { 46 | // TODO: handle exception 47 | } 48 | } 49 | 50 | private static String getFileName(String picPath) { 51 | 52 | String[] tempArray = picPath.split("/"); 53 | String filename = tempArray[tempArray.length - 1]; 54 | if (filename.contains(".")) { 55 | String[] nameArray = filename.split("\\."); 56 | filename = nameArray[0] + "_asc.txt"; 57 | } else { 58 | filename += "_asc.txt"; 59 | } 60 | String finalname = ""; 61 | for (int i = 0; i <= tempArray.length - 2; i++) { 62 | finalname += tempArray[i] + File.separator; 63 | } 64 | finalname += filename; 65 | return finalname; 66 | } 67 | 68 | private static byte[] createAsciiPic(String path, int compressX, int compressY) { 69 | if (AsciiPic.isBlank(path)) { 70 | return null; 71 | } 72 | compressX = compressX != 0 ? compressX : 3; 73 | compressY = compressY != 0 ? compressY : 5; 74 | StringBuilder sb = new StringBuilder(); 75 | final String base = "@#&$%*o!;.";// 字符串由复杂到简单 76 | try { 77 | final BufferedImage image = ImageIO.read(new File(path)); 78 | for (int y = 0; y < image.getHeight(); y += compressY) { 79 | for (int x = 0; x < image.getWidth(); x += compressX) { 80 | final int pixel = image.getRGB(x, y); 81 | final int r = (pixel & 0xff0000) >> 16, g = (pixel & 0xff00) >> 8, b = pixel & 0xff; 82 | final float gray = 0.299f * r + 0.578f * g + 0.114f * b; 83 | final int index = Math.round(gray * (base.length() + 1) / 255); 84 | // System.out.print(index >= base.length() ? " " : 85 | // String.valueOf(base.charAt(index))); 86 | sb.append(index >= base.length() ? " " : String.valueOf(base.charAt(index))); 87 | } 88 | // System.out.println(); 89 | sb.append("\n"); 90 | } 91 | } catch (final IOException e) { 92 | e.printStackTrace(); 93 | } 94 | return sb.toString().getBytes(); 95 | } 96 | 97 | public static boolean isBlank(String str) { 98 | int strLen; 99 | if (str == null || (strLen = str.length()) == 0) { 100 | return true; 101 | } 102 | for (int i = 0; i < strLen; i++) { 103 | if ((Character.isWhitespace(str.charAt(i)) == false)) { 104 | return false; 105 | } 106 | } 107 | return true; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/com/magic/util/PropertiesHelper.java: -------------------------------------------------------------------------------- 1 | package com.magic.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.Properties; 11 | import java.util.Set; 12 | 13 | /** 14 | * 想做配置文件的 但是没有 让我想想怎么做 15 | * 16 | * @author chenhaoyu 17 | * 18 | */ 19 | public class PropertiesHelper { 20 | 21 | public static final String MAIL_ENABLE = "mail.enable"; 22 | public static final String MAIL_QQ_ACC = "mail.qq.account"; 23 | public static final String MAIL_QQ_KEY = "mail.qq.key"; 24 | public static final String MAIL_QQ_FOL = "mail.qq.folders"; 25 | 26 | 27 | public static final String MAIL_QQEX_ACC = "mail.qqex.account"; 28 | public static final String MAIL_QQEX_KEY = "mail.qqex.key"; 29 | public static final String MAIL_QQEX_FOL = "mail.qqex.folders"; 30 | 31 | 32 | private Properties properties = new Properties(); 33 | 34 | String osName = System.getProperty("os.name"); 35 | 36 | String separator = System.getProperty("file.separator"); 37 | 38 | String userPath = System.getProperty("user.home"); 39 | 40 | String folderPath = ""; 41 | String properFilePath = ""; 42 | 43 | private static PropertiesHelper instance = new PropertiesHelper(); 44 | 45 | public static PropertiesHelper getInstance() { 46 | return instance; 47 | } 48 | 49 | private PropertiesHelper() { 50 | 51 | folderPath = userPath + separator + "Live2dChatPlugin"; 52 | properFilePath = userPath + separator + "Live2dChatPlugin" + separator + "setting.properties"; 53 | 54 | File folder = new File(folderPath); 55 | File properFile = new File(properFilePath); 56 | 57 | if (folder.exists()) { 58 | if (folder.isDirectory()) { 59 | if (properFile.exists()) { 60 | System.out.println("找到配置文件"); 61 | 62 | // 读配置文件 63 | try { 64 | properties.load(new BufferedReader(new FileReader(properFile))); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | } else { 70 | createProperties(); 71 | } 72 | } else { 73 | System.out.println("the same name file exists, can not create dir"); 74 | } 75 | } else { 76 | System.out.println("创建文件夹"); 77 | folder.mkdir(); 78 | 79 | createProperties(); 80 | } 81 | 82 | } 83 | 84 | 85 | /** 86 | * 初始化配置文件 87 | */ 88 | public void createProperties(){ 89 | System.out.println("创建配置文件"); 90 | properties.setProperty(MAIL_ENABLE, "F"); 91 | 92 | properties.setProperty(MAIL_QQ_ACC, ""); 93 | properties.setProperty(MAIL_QQ_KEY, ""); 94 | properties.setProperty(MAIL_QQ_FOL, ""); 95 | 96 | properties.setProperty(MAIL_QQEX_ACC, ""); 97 | properties.setProperty(MAIL_QQEX_KEY, ""); 98 | // properties.setProperty(MAIL_QQEX_FOL, ""); 99 | 100 | try (FileOutputStream fous = new FileOutputStream(new File(properFilePath))) { 101 | properties.store(fous, null); 102 | fous.flush(); 103 | } catch (Exception e) { 104 | e.printStackTrace(); 105 | } 106 | 107 | } 108 | 109 | 110 | 111 | /* 112 | * 获得配置文件内容 113 | */ 114 | public String getValue(String key) { 115 | return properties.getProperty(key); 116 | } 117 | 118 | /** 119 | * 获得所有配置内容 120 | * 121 | * @return 122 | */ 123 | public String getAllKeyValues() { 124 | StringBuilder sb = new StringBuilder(); 125 | 126 | Set> entrySet = properties.entrySet(); 127 | for (Entry entry : entrySet) { 128 | sb.append(entry.getKey().toString()).append("=").append(entry.getValue().toString()).append("\n"); 129 | } 130 | return sb.toString(); 131 | } 132 | 133 | /** 134 | * 写入配置文件 135 | * 136 | * @param map 137 | */ 138 | public void setValue(Map map) { 139 | 140 | for (Entry entry : map.entrySet()) { 141 | properties.setProperty(entry.getKey(), entry.getValue()); 142 | } 143 | 144 | try (FileOutputStream fous = new FileOutputStream(new File(properFilePath))) { 145 | properties.store(fous, null); 146 | fous.flush(); 147 | } catch (Exception e) { 148 | e.printStackTrace(); 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/com/magic/mail/QQMail.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Properties; 7 | import java.util.concurrent.ExecutorService; 8 | 9 | import javax.mail.Folder; 10 | import javax.mail.Message; 11 | import javax.mail.MessagingException; 12 | import javax.mail.NoSuchProviderException; 13 | import javax.mail.Session; 14 | import javax.mail.Store; 15 | import javax.mail.event.MessageCountAdapter; 16 | import javax.mail.event.MessageCountEvent; 17 | 18 | import com.magic.ApiService; 19 | import com.sun.mail.iap.ProtocolException; 20 | import com.sun.mail.imap.IMAPFolder; 21 | import com.sun.mail.imap.IdleManager; 22 | import com.sun.mail.imap.protocol.IMAPProtocol; 23 | 24 | /** 25 | * qq 邮箱的监听 已废弃 现在用 @QQMailPro 26 | * 27 | * @author chenhaoyu 28 | * 29 | */ 30 | @Deprecated 31 | public class QQMail implements MailInterface { 32 | 33 | private ApiService handler; 34 | private ExecutorService es; 35 | 36 | private String userName; 37 | private String passWord; 38 | 39 | private Session session; 40 | private Store store; 41 | 42 | private IdleManager idleManager; 43 | 44 | private List folderObjects = new ArrayList(); 45 | 46 | public QQMail(ApiService handler, ExecutorService es, String userName, String passWord, List folders) { 47 | this.handler = handler; 48 | this.es = es; 49 | this.userName = userName; 50 | this.passWord = passWord; 51 | 52 | initStore(); 53 | createFoldersListen(folders); 54 | heartWork(); 55 | } 56 | 57 | /** 58 | * 初始化store 59 | */ 60 | public void initStore() { 61 | String protocol = "imap";// 使用imap协议 62 | boolean isSSL = true;// 使用SSL加密 63 | String host = "imap.qq.com";// QQ邮箱的pop3服务器 64 | int port = 993;// 端口 65 | 66 | /* 67 | * Properties是一个属性对象,用来创建Session对象 68 | */ 69 | Properties props = new Properties(); 70 | props.put("mail.imap.ssl.enable", isSSL); 71 | props.put("mail.imap.host", host); 72 | props.put("mail.imap.port", port); 73 | props.put("mail.transport.protocol", "imap"); 74 | props.put("mail.imap.usesocketchannels", "true"); 75 | 76 | /* 77 | * Session类定义了一个基本的邮件对话。 78 | */ 79 | session = Session.getDefaultInstance(props); 80 | 81 | try { 82 | store = session.getStore(protocol); 83 | store.connect(userName, passWord); 84 | 85 | idleManager = new IdleManager(session, es); 86 | 87 | // 应该增加idleManager 的连接监控 要有"心跳" 88 | 89 | } catch (NoSuchProviderException e) { 90 | e.printStackTrace(); 91 | } catch (MessagingException e) { 92 | e.printStackTrace(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | 97 | } 98 | 99 | public void createFoldersListen(List folders) { 100 | 101 | for (String folderName : folders) { 102 | try { 103 | IMAPFolder temp = (IMAPFolder) store.getFolder(folderName); 104 | temp.open(Folder.READ_ONLY);// 在这一步,收件箱所有邮件将被下载到本地 105 | 106 | System.out.println(folderName); 107 | // Message message = folder.getMessage(size);//取得最新的那个邮件 108 | System.out.println("Size:" + temp.getMessageCount()); 109 | System.out.println("unread:" + temp.getUnreadMessageCount()); 110 | System.out.println("new:" + temp.getNewMessageCount()); 111 | System.out.println(); 112 | 113 | temp.addMessageCountListener(new MessageCountAdapter() { 114 | 115 | @Override 116 | public void messagesAdded(MessageCountEvent e) { 117 | super.messagesAdded(e); 118 | 119 | IMAPFolder folder = (IMAPFolder) e.getSource(); 120 | Message[] msgs = e.getMessages(); 121 | for (int i = 0; i < msgs.length; i++) { 122 | try { 123 | handler.setModelText("有新邮件!标题:" + msgs[i].getSubject(), 0); 124 | System.out.println("add 邮件主题" + msgs[i].getSubject()); 125 | } catch (MessagingException e1) { 126 | e1.printStackTrace(); 127 | } 128 | } 129 | try { 130 | idleManager.watch(folder); 131 | } catch (MessagingException e1) { 132 | e1.printStackTrace(); 133 | } 134 | 135 | } 136 | 137 | }); 138 | idleManager.watch(temp); 139 | folderObjects.add(temp); 140 | 141 | } catch (Exception e) { 142 | // TODO Auto-generated catch block 143 | e.printStackTrace(); 144 | } 145 | 146 | } 147 | 148 | } 149 | 150 | /** 151 | * 待定的心跳检测 152 | */ 153 | public void heartWork() { 154 | es.execute(new Runnable() { 155 | @Override 156 | public void run() { 157 | 158 | while (true) { 159 | 160 | try { 161 | Thread.sleep(9 * 60 * 1000);// 9分钟一次与邮件服务器的心跳 (gmail 162 | // 超时时间比较短) 163 | 164 | for (IMAPFolder folder : folderObjects) { 165 | folder.doCommand(new IMAPFolder.ProtocolCommand() { 166 | @Override 167 | public Object doCommand(IMAPProtocol arg0) throws ProtocolException { 168 | arg0.simpleCommand("NOOP", null); 169 | return null; 170 | } 171 | }); 172 | } 173 | 174 | } catch (Exception e) { 175 | e.printStackTrace(); 176 | } 177 | 178 | } 179 | 180 | } 181 | }); 182 | } 183 | 184 | @Override 185 | public void close() { 186 | try { 187 | for (Folder folder : folderObjects) { 188 | if (folder != null) { 189 | folder.close(false); 190 | } 191 | } 192 | if (store != null) { 193 | store.close(); 194 | } 195 | if (idleManager != null && idleManager.isRunning()) { 196 | idleManager.stop(); 197 | } 198 | } catch (Exception e) { 199 | e.printStackTrace(); 200 | } 201 | } 202 | 203 | @Override 204 | public void check() { 205 | System.out.println("这边未实现"); 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/com/magic/mail/Mail.java: -------------------------------------------------------------------------------- 1 | package com.magic.mail; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Properties; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import javax.mail.Folder; 9 | import javax.mail.FolderClosedException; 10 | import javax.mail.Message; 11 | import javax.mail.MessagingException; 12 | import javax.mail.Session; 13 | import javax.mail.Store; 14 | import javax.mail.event.ConnectionEvent; 15 | import javax.mail.event.ConnectionListener; 16 | import javax.mail.event.MessageCountAdapter; 17 | import javax.mail.event.MessageCountEvent; 18 | 19 | import com.magic.ApiService; 20 | import com.magic.SingleThreadPool; 21 | import com.sun.mail.iap.ProtocolException; 22 | import com.sun.mail.imap.IMAPFolder; 23 | import com.sun.mail.imap.IdleManager; 24 | import com.sun.mail.imap.protocol.IMAPProtocol; 25 | 26 | /** 27 | * 所有mail实例的父级抽象类 统一使用imap 协议 28 | * 29 | * @author chenhaoyu 30 | * 31 | */ 32 | public abstract class Mail implements MailInterface { 33 | 34 | // handler 和 线程池 所有Mail子类公用 构造方法中直接传递 35 | protected ApiService handler; 36 | 37 | // 账号密码 38 | protected String userName; 39 | protected String passWord; 40 | 41 | // 以下 session 和store 等 独立使用 后期自己初始化 42 | protected Session session; 43 | protected Store store; 44 | protected IdleManager idleManager; 45 | protected List folderObjects; 46 | 47 | // 是否人为需要关闭 48 | protected boolean closeFlag = false; 49 | 50 | public Mail(ApiService handler, String userName, String passWord, List folders) { 51 | this.handler = handler; 52 | this.userName = userName; 53 | this.passWord = passWord; 54 | 55 | try { 56 | initStore(); 57 | createFoldersListen(folders); 58 | heartWork(); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | handler.setModelText("监听" + getMailName() + "失败", 0); 62 | } 63 | } 64 | 65 | // 初始化session store idleManager folderObjects 66 | public void initStore() throws Exception { 67 | String protocol = "imap";// 使用的协议 68 | 69 | // Properties是一个属性对象,用来创建Session对象 70 | Properties props = getProperties(); 71 | 72 | // Session类定义了一个基本的邮件对话。 73 | // getDefaultInstance得到的始终是该方法初次创建的缺省的对象,而getInstance得到的始终是新的对象 74 | // session = Session.getDefaultInstance(props); 75 | session = Session.getInstance(props); 76 | 77 | store = session.getStore(protocol); 78 | // 方便调试 加上监听 79 | store.addConnectionListener(new ConnectionListener() { 80 | @Override 81 | public void opened(ConnectionEvent e) { 82 | // handler.setModelText(getMailName() + "已经连接", 0); 83 | System.out.println("_____邮箱" + getMailName() + " opened"); 84 | } 85 | 86 | @Override 87 | public void disconnected(ConnectionEvent e) { 88 | // handler.setModelText(getMailName() + " disconnected", 0); 89 | System.out.println("_____邮箱" + getMailName() + " disconnected"); 90 | } 91 | 92 | @Override 93 | public void closed(ConnectionEvent e) { 94 | // handler.setModelText(getMailName()+" closed" , 0); 95 | System.out.println("_____邮箱" + getMailName() + " closed"); 96 | } 97 | }); 98 | store.connect(userName, passWord); 99 | 100 | idleManager = new IdleManager(session, SingleThreadPool.getInstance().threadPool()); 101 | folderObjects = new ArrayList(); 102 | }; 103 | 104 | public abstract Properties getProperties(); 105 | 106 | public abstract String getMailName(); 107 | 108 | // 文件夹watch 109 | public void createFoldersListen(List folders) throws Exception { 110 | 111 | for (String folderName : folders) { 112 | IMAPFolder temp = (IMAPFolder) store.getFolder(folderName); 113 | // 连接监听 114 | temp.addConnectionListener(new ConnectionListener() { 115 | @Override 116 | public void opened(ConnectionEvent e) { 117 | System.out.println("文件夹:" + getMailName() + folderName + " opened"); 118 | } 119 | 120 | @Override 121 | public void disconnected(ConnectionEvent e) { 122 | System.out.println("文件夹:" + getMailName() + folderName + " disconnected"); 123 | } 124 | 125 | @Override 126 | public void closed(ConnectionEvent e) { 127 | System.out.println("文件夹:" + getMailName() + folderName + " closed"); 128 | 129 | if (!closeFlag) { 130 | try { 131 | temp.open(Folder.READ_ONLY); 132 | idleManager.watch(temp); 133 | } catch (MessagingException e1) { 134 | System.out.println("文件夹:" + getMailName() + folderName + " 重启失败"); 135 | e1.printStackTrace(); 136 | } 137 | } 138 | 139 | } 140 | }); 141 | 142 | temp.open(Folder.READ_ONLY);// 在这一步,收件箱所有邮件将被下载到本地 143 | 144 | // Message message = folder.getMessage(size);//取得最新的那个邮件 145 | System.out.println("Size:" + temp.getMessageCount()); 146 | System.out.println("unread:" + temp.getUnreadMessageCount()); 147 | System.out.println("new:" + temp.getNewMessageCount()); 148 | System.out.println(); 149 | // 收件监听 150 | temp.addMessageCountListener(new MessageCountAdapter() { 151 | @Override 152 | public void messagesAdded(MessageCountEvent e) { 153 | super.messagesAdded(e); 154 | IMAPFolder folder = (IMAPFolder) e.getSource(); 155 | Message[] msgs = e.getMessages(); 156 | for (int i = 0; i < msgs.length; i++) { 157 | try { 158 | handler.setModelTextWithHoldTime(getMailName() + "有新邮件!标题:" + msgs[i].getSubject(), 0, 10); 159 | System.out.println("新邮件主题" + msgs[i].getSubject()); 160 | } catch (MessagingException e1) { 161 | e1.printStackTrace(); 162 | } 163 | } 164 | try { 165 | idleManager.watch(folder); 166 | } catch (MessagingException e2) { 167 | e2.printStackTrace(); 168 | } 169 | 170 | } 171 | 172 | }); 173 | 174 | idleManager.watch(temp); 175 | folderObjects.add(temp); 176 | 177 | handler.setModelText(getMailName() + " " + folderName + " 已关注", 0); 178 | } 179 | } 180 | 181 | /** 182 | * 文件夹心跳检测 183 | */ 184 | public void heartWork() { 185 | 186 | SingleThreadPool.getInstance().scheduledThreadPool().scheduleAtFixedRate(new Runnable() { 187 | @Override 188 | public void run() { 189 | System.out.println(Thread.currentThread().getName() + "————" + getMailName()); 190 | try { 191 | for (IMAPFolder imapFolder : folderObjects) { 192 | imapFolder.doCommand(new IMAPFolder.ProtocolCommand() { 193 | @Override 194 | public Object doCommand(IMAPProtocol arg0) throws ProtocolException { 195 | arg0.simpleCommand("NOOP", null); 196 | return null; 197 | } 198 | }); 199 | idleManager.watch(imapFolder); 200 | } 201 | } catch (Exception e) { 202 | e.printStackTrace(); 203 | } 204 | } 205 | 206 | }, 9, 9, TimeUnit.MINUTES); 207 | 208 | } 209 | 210 | // 关闭 监听 文件夹 store 211 | @Override 212 | public void close() { 213 | try { 214 | closeFlag = true; 215 | if (idleManager != null && idleManager.isRunning()) { 216 | idleManager.stop(); 217 | } 218 | for (Folder folder : folderObjects) { 219 | if (folder != null) { 220 | folder.close(false); 221 | } 222 | } 223 | if (store != null) { 224 | store.close(); 225 | } 226 | } catch (Exception e) { 227 | e.printStackTrace(); 228 | } 229 | } 230 | 231 | @Override 232 | public void check() { 233 | System.out.println(); 234 | System.out.println("####################"); 235 | System.out.println(getMailName() + " 当前状态:"); 236 | System.out.println("store是否连接: " + store.isConnected()); 237 | System.out.println("IdleManager是否运行:" + idleManager.isRunning()); 238 | folderObjects.stream().map( 239 | folder -> folder.getFullName() + ":Subscribe-" + folder.isSubscribed() + ",open-" + folder.isOpen()) 240 | .forEach(System.out::println); 241 | System.out.println("####################"); 242 | System.out.println(); 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/com/magic/ChatRobotGUI.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Font; 6 | import java.awt.FontMetrics; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.awt.event.MouseAdapter; 10 | import java.awt.event.MouseEvent; 11 | import java.awt.event.MouseMotionAdapter; 12 | 13 | import javax.swing.JButton; 14 | import javax.swing.JFrame; 15 | import javax.swing.JLabel; 16 | import javax.swing.JPanel; 17 | import javax.swing.JTextField; 18 | import javax.swing.border.MatteBorder; 19 | 20 | import com.sun.awt.AWTUtilities; 21 | 22 | public class ChatRobotGUI implements ActionListener, Runnable { 23 | 24 | public String version = "1.2.0"; 25 | 26 | ApiService apiService; 27 | 28 | JFrame fatherFrame, switchFrame; 29 | JPanel lablePanel, inputPanel, linkPanel; 30 | JTextField inputField; 31 | JLabel label; 32 | // 做拖动用的 记录的鼠标原始坐标 33 | int xOld = 0; 34 | int yOld = 0; 35 | // 做框体浮动 记录目前框体的坐标 36 | int xnow = 0; 37 | int ynow = 0; 38 | 39 | Color bg = new Color(0x1e969696, true); 40 | Color inputBorderColor = new Color(0x1eFFFAFA, true); 41 | 42 | Color bg_control = new Color(0x7d969696, true); 43 | 44 | Boolean hideFlag = true; 45 | 46 | public ChatRobotGUI(ApiService apiService) { 47 | this.apiService = apiService; 48 | // 控制开关Frame 49 | switchFrame = new JFrame(); 50 | switchFrame.addMouseListener(new MouseAdapter() { 51 | @Override 52 | public void mouseClicked(MouseEvent e) { 53 | if (hideFlag) { 54 | magicHide(); 55 | hideFlag = false; 56 | } else { 57 | magicShow(); 58 | hideFlag = true; 59 | } 60 | } 61 | }); 62 | switchFrame.setSize(20, 20); 63 | switchFrame.setUndecorated(true);// 禁用或启动用此JFrame装饰 64 | switchFrame.setBackground(bg_control); // 将背景色设置为空 65 | switchFrame.setAlwaysOnTop(true);// 窗体置顶 66 | switchFrame.setVisible(true); 67 | switchFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 68 | 69 | // 本体父窗体Frame 70 | fatherFrame = new JFrame(); 71 | fatherFrame.setLayout(new BorderLayout()); 72 | 73 | // 输出panel 74 | lablePanel = new JPanel(); 75 | lablePanel.setBackground(bg); 76 | label = new JLabel(); 77 | label.setSize(fatherFrame.getWidth(), 0); 78 | label.setForeground(Color.WHITE); 79 | label.setFont(new Font("黑体", Font.PLAIN, 18)); 80 | label.setBackground(bg); 81 | label.setVisible(true); 82 | String notice = "版本:"+version+"
AI由茉莉机器人提供
仅供娱乐学习,严禁商业使用
by Magic2014
感谢Live2DViewerEX作者"; 83 | label.setText(notice); 84 | lablePanel.add(label); 85 | fatherFrame.add(lablePanel, BorderLayout.CENTER); 86 | 87 | // 输入panel 88 | inputPanel = new JPanel(); 89 | inputPanel.setBackground(bg); 90 | inputField = new JTextField(20); 91 | inputField.setEditable(true); 92 | inputField.setEnabled(true); 93 | inputField.addActionListener(this); 94 | inputField.setBackground(bg); 95 | MatteBorder border = new MatteBorder(0, 0, 2, 0, inputBorderColor); 96 | inputField.setBorder(border); 97 | inputPanel.add(inputField); 98 | fatherFrame.add(inputPanel, BorderLayout.SOUTH); 99 | 100 | // 快捷栏panel 101 | linkPanel = new JPanel(); 102 | linkPanel.setPreferredSize(null); 103 | linkPanel.setBackground(bg); 104 | linkPanel.setVisible(true); 105 | 106 | JButton menuBtn = new JButton(); 107 | menuBtn.setForeground(Color.white); 108 | menuBtn.setText("菜
单"); 109 | menuBtn.setBackground(bg); 110 | menuBtn.addMouseListener(new MouseAdapter() { 111 | @Override 112 | public void mouseClicked(MouseEvent e) { 113 | apiService.openMenu(0); 114 | } 115 | }); 116 | menuBtn.setBorderPainted(false); 117 | menuBtn.setBorder(null); 118 | 119 | linkPanel.add(menuBtn); 120 | fatherFrame.add(linkPanel, BorderLayout.EAST); 121 | 122 | // 获取开始平移时的点击坐标 123 | fatherFrame.addMouseListener(new MouseAdapter() { 124 | @Override 125 | public void mousePressed(MouseEvent e) { 126 | xOld = e.getX();// 记录鼠标按下时的坐标 127 | yOld = e.getY(); 128 | } 129 | 130 | }); 131 | 132 | // 平移时 根据上面获取的坐标 实时计算当前坐标 同时平移 控制和聊天 2个frame 133 | fatherFrame.addMouseMotionListener(new MouseMotionAdapter() { 134 | @Override 135 | public void mouseDragged(MouseEvent e) { 136 | int xOnScreen = e.getXOnScreen(); 137 | int yOnScreen = e.getYOnScreen(); 138 | int xx = xOnScreen - xOld; 139 | int yy = yOnScreen - yOld; 140 | 141 | fatherFrame.setLocation(xx, yy);// 设置拖拽后,窗口的位置 142 | 143 | xnow = (int) fatherFrame.getLocation().getX(); 144 | ynow = (int) fatherFrame.getLocation().getY(); 145 | 146 | switchFrame.setLocation(xnow, ynow); 147 | } 148 | }); 149 | 150 | fatherFrame.setUndecorated(true);// 禁用或启动用此JFrame装饰 151 | fatherFrame.setBackground(bg); // 将背景色设置为空 152 | 153 | fatherFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 154 | 155 | fatherFrame.setSize(400, 200); 156 | fatherFrame.setBackground(bg); 157 | xnow = (int) fatherFrame.getLocation().getX(); 158 | ynow = (int) fatherFrame.getLocation().getY(); 159 | fatherFrame.setVisible(true); 160 | 161 | } 162 | 163 | /** 164 | * input 回车监听 165 | */ 166 | @Override 167 | public void actionPerformed(ActionEvent e) { 168 | if (e.getSource() == inputField) { 169 | String input = inputField.getText(); 170 | System.out.println("输入 "+input); 171 | String origin = ""; 172 | 173 | if (input.contains("$菜单")) { 174 | apiService.openMenu(0); 175 | return; 176 | } else if (input.contains("$exit")) { 177 | apiService.totalClose(); 178 | return; 179 | } else if (input.startsWith("$shell:")) { 180 | // 调用shell 181 | origin = apiService.shShell(input.replace("$shell:", "")); 182 | } else { 183 | // 请求接口 184 | origin = apiService.chat(input); 185 | } 186 | 187 | // 解析回调数据 188 | String analyzed = apiService.analysisStr(origin); 189 | // 设置文字 190 | 191 | if (apiService.getWsFlag()) { 192 | apiService.setModelText(analyzed, 0); 193 | } else { 194 | smartSetText(label, analyzed); 195 | } 196 | } 197 | } 198 | 199 | /** 200 | * 自动换行设置文字 201 | * 202 | * @param jLabel 203 | * @param longString 204 | */ 205 | public void smartSetText(JLabel jLabel, String longString) { 206 | lablePanel.setBackground(bg); 207 | StringBuilder sb = new StringBuilder(""); 208 | char[] chars = longString.toCharArray(); 209 | FontMetrics fontMetrics = jLabel.getFontMetrics(jLabel.getFont()); 210 | int start = 0; 211 | int len = 0; 212 | 213 | while (start + len < longString.length()) { 214 | while (true) { 215 | len++; 216 | if (start + len > longString.length()) 217 | break; 218 | if (fontMetrics.charsWidth(chars, start, len) > fatherFrame.getWidth()) { 219 | break; 220 | } 221 | } 222 | sb.append(chars, start, len - 1).append("
"); 223 | start = start + len - 1; 224 | len = 0; 225 | } 226 | sb.append(chars, start, longString.length() - start); 227 | 228 | sb.append(""); 229 | System.out.println(sb.toString()); 230 | 231 | jLabel.setText(sb.toString()); 232 | } 233 | 234 | /** 235 | * 窗体做正玄浮动 236 | */ 237 | @Override 238 | public void run() { 239 | // 振幅 240 | int de = fatherFrame.getHeight() / 80; 241 | boolean add = true; 242 | int i = 0; 243 | while (true) { 244 | try { 245 | Thread.sleep(350); 246 | fatherFrame.setLocation(xnow, ynow - i); 247 | 248 | switchFrame.setLocation(xnow, ynow - i); 249 | if (add) { 250 | i++; 251 | } else { 252 | i--; 253 | } 254 | if (i == de) { 255 | add = false; 256 | } else if (i == de * -1) { 257 | add = true; 258 | } 259 | } catch (InterruptedException e) { 260 | e.printStackTrace(); 261 | } 262 | } 263 | 264 | } 265 | 266 | /** 267 | * 窗体渐显 268 | * 269 | */ 270 | public void magicShow() { 271 | for (int i = 0; i < 50; i++) { 272 | try { 273 | Thread.sleep(20); 274 | } catch (Exception e) { 275 | } 276 | AWTUtilities.setWindowOpacity(fatherFrame, i * 0.02f); 277 | } 278 | } 279 | 280 | /** 281 | * 窗体渐隐 282 | * 283 | */ 284 | public void magicHide() { 285 | float opacity = 100; 286 | while (true) { 287 | if (opacity < 2) { 288 | System.out.println(); 289 | break; 290 | } 291 | opacity = opacity - 2; 292 | AWTUtilities.setWindowOpacity(fatherFrame, opacity / 100); 293 | try { 294 | Thread.sleep(20); 295 | } catch (Exception e1) { 296 | } 297 | } 298 | // this.hide(); 299 | } 300 | 301 | } 302 | -------------------------------------------------------------------------------- /src/com/magic/ApiService.java: -------------------------------------------------------------------------------- 1 | package com.magic; 2 | 3 | import java.awt.Desktop; 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.io.OutputStreamWriter; 9 | import java.io.PrintWriter; 10 | import java.net.URI; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | import java.util.stream.Collectors; 15 | 16 | import javax.swing.JFileChooser; 17 | import javax.swing.filechooser.FileFilter; 18 | import javax.swing.filechooser.FileNameExtensionFilter; 19 | 20 | import com.alibaba.fastjson.JSONArray; 21 | import com.alibaba.fastjson.JSONObject; 22 | import com.magic.mail.MailService; 23 | import com.magic.util.HttpHelper; 24 | 25 | public class ApiService { 26 | 27 | MagicWebSocketClient wsClient = null; 28 | 29 | MailService mailService = null; 30 | 31 | boolean WSFlag = false; 32 | 33 | List optionMenuList = null; 34 | 35 | JFileChooser fileChooser = null; 36 | 37 | public ApiService(String port) { 38 | try { 39 | wsClient = new MagicWebSocketClient("ws://127.0.0.1:" + port + "/api", this); 40 | wsClient.connect(); 41 | initMenu(); 42 | } catch (Exception e) { 43 | System.out.println("ws连接失败"); 44 | e.printStackTrace(); 45 | } 46 | 47 | mailService = new MailService(this); 48 | 49 | 50 | fileChooser = new JFileChooser(); 51 | FileFilter filter = new FileNameExtensionFilter("图片", "JPG", "JPEG", "GIF", "BMP", "PNG");// 设置文件过滤器,只列出JPG或GIF格式的图片 52 | fileChooser.setFileFilter(filter); 53 | } 54 | 55 | /* 56 | * 改变状态 57 | */ 58 | public void setWSFlag(boolean state) { 59 | this.WSFlag = state; 60 | } 61 | 62 | /** 63 | * 获得ws是否连接成功 64 | * 65 | * @return 66 | */ 67 | public boolean getWsFlag() { 68 | return WSFlag; 69 | } 70 | 71 | /** 72 | * 关闭插件 所有需要关闭的统一在这里关 73 | */ 74 | public void totalClose() { 75 | setModelText("插件关闭 感谢使用 ค(≖ ◡ ≖) 白白", 0); 76 | 77 | System.out.println("停止线程中的任务");// 窗体抖动 ws心跳 78 | SingleThreadPool.getInstance().close(); 79 | 80 | System.out.println("关闭mail相关监听"); 81 | mailService.close(); 82 | 83 | System.out.println("关闭websocket连接"); 84 | if (wsClient != null) { 85 | wsClient.close(); 86 | } 87 | System.exit(0); 88 | } 89 | 90 | /** 91 | * 做一个代理 把mailService封装在里面 92 | * 93 | * @param type 94 | * @param userName 95 | * @param passWord 96 | * @param folders 97 | */ 98 | public void addMailListener(String type, String userName, String passWord, List folders) { 99 | mailService.addMailListener(type, userName, passWord, folders); 100 | } 101 | 102 | /** 103 | * 让指定model说话 104 | * 105 | * @param str 106 | * @param modelId 107 | */ 108 | public void setModelText(String str, int modelId) { 109 | setModelTextWithHoldTime(str, modelId, 5); 110 | } 111 | 112 | /** 113 | * 让指定model说话 文字持续保留一段时间 114 | * 115 | * @param str 116 | * @param modelId 117 | * @param holdTime 118 | * 秒 119 | */ 120 | public void setModelTextWithHoldTime(String str, int modelId, int holdTime) { 121 | 122 | JSONObject textjson = new JSONObject(); 123 | 124 | textjson.put("msg", 11000); 125 | textjson.put("msgId", 1); 126 | JSONObject data = new JSONObject(); 127 | data.put("id", modelId); 128 | data.put("text", str); 129 | data.put("duration", holdTime * 1000); 130 | textjson.put("data", data); 131 | 132 | wsClient.send(textjson.toJSONString()); 133 | } 134 | 135 | /** 136 | * 初始化菜单 137 | */ 138 | public void initMenu() { 139 | optionMenuList = new ArrayList<>(); 140 | // optionMenuList.add(new OptionMenu() { 141 | // @Override 142 | // public String menuName() { 143 | // return "打开maven仓库"; 144 | // } 145 | // 146 | // @Override 147 | // public void execute() { 148 | // shShell("open /Users/chenhaoyu/.m2/repository/"); 149 | // } 150 | // }); 151 | // 152 | // optionMenuList.add(new OptionMenu() { 153 | // @Override 154 | // public String menuName() { 155 | // return "打开工作环境"; 156 | // } 157 | // 158 | // @Override 159 | // public void execute() { 160 | // shShell("open /Users/chenhaoyu/Documents/workspace-sts-3.9.5.RELEASE/"); 161 | // } 162 | // }); 163 | 164 | 165 | optionMenuList.add(new OptionMenu() { 166 | 167 | @Override 168 | public String menuName() { 169 | return "检查邮箱监听状态"; 170 | } 171 | 172 | @Override 173 | public void execute() { 174 | mailService.check(); 175 | } 176 | }); 177 | 178 | optionMenuList.add(new OptionMenu() { 179 | 180 | @Override 181 | public String menuName() { 182 | return "选张图,变个魔术给你看"; 183 | } 184 | 185 | @Override 186 | public void execute() { 187 | 188 | SingleThreadPool.getInstance().threadPool().submit(new Runnable() { 189 | @Override 190 | public void run() { 191 | int i = fileChooser.showOpenDialog(null);// 显示文件选择对话框 192 | if (i == JFileChooser.APPROVE_OPTION) { 193 | File selectedFile = fileChooser.getSelectedFile();// 获得选中的文件对象 194 | System.out.println(selectedFile.getAbsolutePath()); 195 | AsciiPic.createPicFile(selectedFile.getAbsolutePath()); 196 | setModelText("噔噔!去图片那看看吧~", 0); 197 | }else { 198 | setModelText("不想看我的魔术吗?", 0); 199 | } 200 | } 201 | }); 202 | } 203 | }); 204 | 205 | 206 | optionMenuList.add(new OptionMenu() { 207 | @Override 208 | public String menuName() { 209 | return "随机双色球"; 210 | } 211 | 212 | @Override 213 | public void execute() { 214 | String result = createLottery(); 215 | setModelText(result, 0); 216 | } 217 | }); 218 | optionMenuList.add(new OptionMenu() { 219 | 220 | @Override 221 | public String menuName() { 222 | return "番剧信息"; 223 | } 224 | 225 | @Override 226 | public void execute() { 227 | String bangumi = getBangumi(); 228 | setModelText(bangumi, 0); 229 | } 230 | }); 231 | optionMenuList.add(new OptionMenu() { 232 | @Override 233 | public String menuName() { 234 | return "看看本项目"; 235 | } 236 | 237 | @Override 238 | public void execute() { 239 | URI uri = URI.create("https://github.com/WhiteMagic2014/Live2dChatWidget"); 240 | Desktop dp = Desktop.getDesktop(); 241 | if (dp.isSupported(Desktop.Action.BROWSE)) { 242 | try { 243 | dp.browse(uri); 244 | } catch (IOException e) { 245 | e.printStackTrace(); 246 | } 247 | } else { 248 | setModelText("不支持呢...手动打开吧 https://github.com/WhiteMagic2014/Live2dChatWidget", 0); 249 | } 250 | } 251 | }); 252 | optionMenuList.add(new OptionMenu() { 253 | 254 | @Override 255 | public String menuName() { 256 | return "关闭插件"; 257 | } 258 | 259 | @Override 260 | public void execute() { 261 | totalClose(); 262 | } 263 | }); 264 | } 265 | 266 | /** 267 | * 让指定model打开菜单 268 | * 269 | * @param modelId 270 | */ 271 | public void openMenu(int modelId) { 272 | JSONObject textjson = new JSONObject(); 273 | 274 | textjson.put("msg", 11000); 275 | textjson.put("msgId", 1); 276 | JSONObject data = new JSONObject(); 277 | data.put("id", modelId); 278 | data.put("text", "需要我帮忙吗?"); 279 | data.put("duration", 5000); 280 | 281 | data.put("choices", optionMenuList.stream().map(menu -> menu.menuName()).collect(Collectors.toList())); 282 | textjson.put("data", data); 283 | wsClient.send(textjson.toJSONString()); 284 | } 285 | 286 | /** 287 | * 选项回调处理 288 | */ 289 | public void processCallback(JSONObject resultObj) { 290 | System.out.println(resultObj); 291 | // 选项回调 292 | if (resultObj.getIntValue("msg") == 11000) { 293 | int menuID = resultObj.getIntValue("data"); 294 | if (menuID < 0) { 295 | setModelText("✧(≖ ◡ ≖✿)嘿嘿", 0); 296 | }else { 297 | optionMenuList.get(menuID).execute(); 298 | } 299 | } 300 | } 301 | 302 | /** 303 | * 随机彩票 304 | * 305 | * @return 306 | */ 307 | public String createLottery() { 308 | StringBuilder sb = new StringBuilder(); 309 | 310 | sb.append("猜不中别怪我,猜中了请联系我赏顿饭钱!!!我开始随便猜啦~"); 311 | sb.append("红色:"); 312 | red().stream().forEach(red -> sb.append(red).append(" ")); 313 | sb.append("蓝色:").append(bule()); 314 | 315 | return sb.toString(); 316 | } 317 | 318 | private List red() { 319 | Random random = new Random(); 320 | List pool = new ArrayList<>(); 321 | List result = new ArrayList<>(); 322 | for (int i = 1; i <= 33; i++) { 323 | pool.add(i); 324 | } 325 | for (int i = 1; i <= 6; i++) { 326 | int flag = random.nextInt(pool.size()); 327 | int redtemp = pool.get(flag); 328 | result.add(redtemp); 329 | pool.remove(flag); 330 | } 331 | return result.stream().sorted(Integer::compareTo).collect(Collectors.toList()); 332 | } 333 | 334 | private Integer bule() { 335 | Random random = new Random(); 336 | return (random.nextInt(16) + 1); 337 | } 338 | 339 | /** 340 | * 解析返回的数据 json unicode等 341 | * 342 | * @param str 343 | * @return 344 | */ 345 | public String analysisStr(String str) { 346 | System.out.println(str); 347 | str = str.replace("[name]", "{$username}") 348 | .replace("[name]", "{$username}") 349 | .replace("[cqname]", "我") 350 | .replace("NULL", "= ̄ω ̄="); 351 | return str; 352 | } 353 | 354 | /** 355 | * 实执行shell 356 | * 357 | * @param command 358 | * 暂时封装了 进仓库 和工作环境 359 | * @return 360 | */ 361 | public String shShell(String command) { 362 | if (command.trim().equals("")) { 363 | return "你要我做什么呢?"; 364 | } 365 | if (command.contains("rm") || command.contains("chmod")) { 366 | return "呀屎啦你 作死?"; 367 | } else if (command.contains("top")) { 368 | return "不支持动态显示结果"; 369 | } 370 | 371 | System.out.println("shell执行记录:" + command); 372 | String returnString = ""; 373 | Process pro = null; 374 | Runtime runTime = Runtime.getRuntime(); 375 | if (runTime == null) { 376 | System.err.println("Create runtime false!"); 377 | } 378 | try { 379 | pro = runTime.exec(command); 380 | BufferedReader input = new BufferedReader(new InputStreamReader(pro.getInputStream())); 381 | PrintWriter output = new PrintWriter(new OutputStreamWriter(pro.getOutputStream())); 382 | String line; 383 | while ((line = input.readLine()) != null) { 384 | returnString = returnString + line + "\n"; 385 | } 386 | input.close(); 387 | output.close(); 388 | pro.destroy(); 389 | } catch (IOException ex) { 390 | ex.printStackTrace(); 391 | return "被玩坏了_(:з」∠)_"; 392 | } 393 | return returnString; 394 | } 395 | 396 | /** 397 | * 调用聊天接口 398 | * 399 | * @param str 400 | * @return 401 | */ 402 | public String chat(String str) { 403 | return HttpHelper.sendGet("http://i.itpk.cn/api.php?question=" + str); 404 | } 405 | 406 | /** 407 | * 番剧信息 408 | * 409 | * @return 410 | */ 411 | public String getBangumi() { 412 | String origin = HttpHelper.sendGet("https://bangumi.bilibili.com/web_api/timeline_global"); 413 | 414 | JSONObject jsonRaw = JSONObject.parseObject(origin); 415 | 416 | if (jsonRaw.getString("message").equals("success")) { 417 | 418 | StringBuilder sb = new StringBuilder(); 419 | 420 | JSONArray dateArray = jsonRaw.getJSONArray("result"); 421 | List dateList = JSONArray.parseArray(dateArray.toJSONString(), JSONObject.class); 422 | 423 | JSONObject todayData = dateList.stream().filter(date -> date.getBoolean("is_today")) 424 | .collect(Collectors.toList()).get(0); 425 | 426 | String[] dateTemp = todayData.getString("date").split("-"); 427 | String today = dateTemp[0] + "月" + dateTemp[1] + "日"; 428 | String week = todayData.getString("day_of_week"); 429 | 430 | sb.append("今天是 " + today + " 星期" + week + ".\n更新的番剧有:\n"); 431 | 432 | // System.out.println("更新的番剧有:"); 433 | List bangumiList = JSONArray.parseArray(todayData.getString("seasons"), JSONObject.class); 434 | 435 | bangumiList.stream().forEach(t -> { 436 | sb.append(t.getString("pub_time") + " " + t.getString("title") + " " + t.getString("pub_index") + "\n"); 437 | }); 438 | 439 | return sb.toString(); 440 | } else { 441 | return "获取信息失败_(:з」∠)_"; 442 | } 443 | 444 | } 445 | 446 | } 447 | --------------------------------------------------------------------------------