Initial commit
This commit is contained in:
commit
27e2312eed
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/build/
|
||||||
|
/dist/
|
||||||
|
/nbproject/private/
|
73
build.xml
Normal file
73
build.xml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- You may freely edit this file. See commented blocks below for -->
|
||||||
|
<!-- some examples of how to customize the build. -->
|
||||||
|
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||||
|
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||||
|
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||||
|
<!-- the Compile on Save feature is turned off for the project. -->
|
||||||
|
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||||
|
<!-- in the project's Project Properties dialog box.-->
|
||||||
|
<project name="SamobotVK" default="default" basedir=".">
|
||||||
|
<description>Builds, tests, and runs the project SamobotVK.</description>
|
||||||
|
<import file="nbproject/build-impl.xml"/>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
There exist several targets which are by default empty and which can be
|
||||||
|
used for execution of your tasks. These targets are usually executed
|
||||||
|
before and after some main targets. They are:
|
||||||
|
|
||||||
|
-pre-init: called before initialization of project properties
|
||||||
|
-post-init: called after initialization of project properties
|
||||||
|
-pre-compile: called before javac compilation
|
||||||
|
-post-compile: called after javac compilation
|
||||||
|
-pre-compile-single: called before javac compilation of single file
|
||||||
|
-post-compile-single: called after javac compilation of single file
|
||||||
|
-pre-compile-test: called before javac compilation of JUnit tests
|
||||||
|
-post-compile-test: called after javac compilation of JUnit tests
|
||||||
|
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||||
|
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||||
|
-pre-jar: called before JAR building
|
||||||
|
-post-jar: called after JAR building
|
||||||
|
-post-clean: called after cleaning build products
|
||||||
|
|
||||||
|
(Targets beginning with '-' are not intended to be called on their own.)
|
||||||
|
|
||||||
|
Example of inserting an obfuscator after compilation could look like this:
|
||||||
|
|
||||||
|
<target name="-post-compile">
|
||||||
|
<obfuscate>
|
||||||
|
<fileset dir="${build.classes.dir}"/>
|
||||||
|
</obfuscate>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
For list of available properties check the imported
|
||||||
|
nbproject/build-impl.xml file.
|
||||||
|
|
||||||
|
|
||||||
|
Another way to customize the build is by overriding existing main targets.
|
||||||
|
The targets of interest are:
|
||||||
|
|
||||||
|
-init-macrodef-javac: defines macro for javac compilation
|
||||||
|
-init-macrodef-junit: defines macro for junit execution
|
||||||
|
-init-macrodef-debug: defines macro for class debugging
|
||||||
|
-init-macrodef-java: defines macro for class execution
|
||||||
|
-do-jar: JAR building
|
||||||
|
run: execution of project
|
||||||
|
-javadoc-build: Javadoc generation
|
||||||
|
test-report: JUnit report generation
|
||||||
|
|
||||||
|
An example of overriding the target for project execution could look like this:
|
||||||
|
|
||||||
|
<target name="run" depends="SamobotVK-impl.jar">
|
||||||
|
<exec dir="bin" executable="launcher.exe">
|
||||||
|
<arg file="${dist.jar}"/>
|
||||||
|
</exec>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
Notice that the overridden target depends on the jar target and not only on
|
||||||
|
the compile target as the regular run target does. Again, for a list of available
|
||||||
|
properties which you can use, check the target you are overriding in the
|
||||||
|
nbproject/build-impl.xml file.
|
||||||
|
|
||||||
|
-->
|
||||||
|
</project>
|
3
manifest.mf
Normal file
3
manifest.mf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
X-COMMENT: Main-Class will be added automatically by build
|
||||||
|
|
1419
nbproject/build-impl.xml
Normal file
1419
nbproject/build-impl.xml
Normal file
File diff suppressed because it is too large
Load Diff
8
nbproject/genfiles.properties
Normal file
8
nbproject/genfiles.properties
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
build.xml.data.CRC32=85dd5378
|
||||||
|
build.xml.script.CRC32=e9039a67
|
||||||
|
build.xml.stylesheet.CRC32=8064a381@1.79.0.48
|
||||||
|
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||||
|
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||||
|
nbproject/build-impl.xml.data.CRC32=85dd5378
|
||||||
|
nbproject/build-impl.xml.script.CRC32=5f7e4b67
|
||||||
|
nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.0.48
|
76
nbproject/project.properties
Normal file
76
nbproject/project.properties
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
annotation.processing.enabled=true
|
||||||
|
annotation.processing.enabled.in.editor=false
|
||||||
|
annotation.processing.processors.list=
|
||||||
|
annotation.processing.run.all.processors=true
|
||||||
|
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||||
|
application.title=SamobotVK
|
||||||
|
application.vendor=dns1
|
||||||
|
build.classes.dir=${build.dir}/classes
|
||||||
|
build.classes.excludes=**/*.java,**/*.form
|
||||||
|
# This directory is removed when the project is cleaned:
|
||||||
|
build.dir=build
|
||||||
|
build.generated.dir=${build.dir}/generated
|
||||||
|
build.generated.sources.dir=${build.dir}/generated-sources
|
||||||
|
# Only compile against the classpath explicitly listed here:
|
||||||
|
build.sysclasspath=ignore
|
||||||
|
build.test.classes.dir=${build.dir}/test/classes
|
||||||
|
build.test.results.dir=${build.dir}/test/results
|
||||||
|
# Uncomment to specify the preferred debugger connection transport:
|
||||||
|
#debug.transport=dt_socket
|
||||||
|
debug.classpath=\
|
||||||
|
${run.classpath}
|
||||||
|
debug.test.classpath=\
|
||||||
|
${run.test.classpath}
|
||||||
|
# \u0424\u0430\u0439\u043b\u044b \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 build.classes.dir, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0430\u0440\u0445\u0438\u0432\u0430 jar
|
||||||
|
dist.archive.excludes=
|
||||||
|
# This directory is removed when the project is cleaned:
|
||||||
|
dist.dir=dist
|
||||||
|
dist.jar=${dist.dir}/SamobotVK.jar
|
||||||
|
dist.javadoc.dir=${dist.dir}/javadoc
|
||||||
|
endorsed.classpath=
|
||||||
|
excludes=
|
||||||
|
includes=**
|
||||||
|
jar.compress=false
|
||||||
|
javac.classpath=
|
||||||
|
# Space-separated list of extra javac options
|
||||||
|
javac.compilerargs=
|
||||||
|
javac.deprecation=false
|
||||||
|
javac.external.vm=false
|
||||||
|
javac.processorpath=\
|
||||||
|
${javac.classpath}
|
||||||
|
javac.source=1.8
|
||||||
|
javac.target=1.8
|
||||||
|
javac.test.classpath=\
|
||||||
|
${javac.classpath}:\
|
||||||
|
${build.classes.dir}
|
||||||
|
javac.test.processorpath=\
|
||||||
|
${javac.test.classpath}
|
||||||
|
javadoc.additionalparam=
|
||||||
|
javadoc.author=false
|
||||||
|
javadoc.encoding=${source.encoding}
|
||||||
|
javadoc.noindex=false
|
||||||
|
javadoc.nonavbar=false
|
||||||
|
javadoc.notree=false
|
||||||
|
javadoc.private=false
|
||||||
|
javadoc.splitindex=true
|
||||||
|
javadoc.use=true
|
||||||
|
javadoc.version=false
|
||||||
|
javadoc.windowtitle=
|
||||||
|
main.class=holdfast.samobot.ControlFrame
|
||||||
|
manifest.file=manifest.mf
|
||||||
|
meta.inf.dir=${src.dir}/META-INF
|
||||||
|
mkdist.disabled=false
|
||||||
|
platform.active=default_platform
|
||||||
|
run.classpath=\
|
||||||
|
${javac.classpath}:\
|
||||||
|
${build.classes.dir}
|
||||||
|
# Space-separated list of JVM arguments used when running the project.
|
||||||
|
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
|
||||||
|
# To set system properties for unit tests define test-sys-prop.name=value:
|
||||||
|
run.jvmargs=
|
||||||
|
run.test.classpath=\
|
||||||
|
${javac.test.classpath}:\
|
||||||
|
${build.test.classes.dir}
|
||||||
|
source.encoding=UTF-8
|
||||||
|
src.dir=src
|
||||||
|
test.src.dir=test
|
15
nbproject/project.xml
Normal file
15
nbproject/project.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||||
|
<type>org.netbeans.modules.java.j2seproject</type>
|
||||||
|
<configuration>
|
||||||
|
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||||
|
<name>SamobotVK</name>
|
||||||
|
<source-roots>
|
||||||
|
<root id="src.dir"/>
|
||||||
|
</source-roots>
|
||||||
|
<test-roots>
|
||||||
|
<root id="test.src.dir"/>
|
||||||
|
</test-roots>
|
||||||
|
</data>
|
||||||
|
</configuration>
|
||||||
|
</project>
|
18
src/commands.txt
Normal file
18
src/commands.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Лена-бот
|
||||||
|
|
||||||
|
Команды:
|
||||||
|
- выбери: выбирает из списка случайное значение (выбери пункт1, пункт2, ..., пунктN)
|
||||||
|
- курс / валюта: текущий курс валют
|
||||||
|
- ответ: поиск определения или расчёт выражений в гугле (ответ 10+50/15)
|
||||||
|
- фото: поиск картинок (фото Miami Green Diamond)
|
||||||
|
- текст: текст песни (текст Ария - Беспечный Ангел)
|
||||||
|
- boobs / сиськи / сиси: показывает сиськи из oboobs.ru
|
||||||
|
- butts / попа: показывает попы из obutts.ru
|
||||||
|
- пони / неко / пеппа / аниме: спечиализированный поиск картинок в вк
|
||||||
|
- пирожки: выводит стихи-пирожки с сайта perashki.ru
|
||||||
|
- инфа: подсчитывает вероятность чего-либо (инфа пойти спать)
|
||||||
|
- аудио / музыка / песню: поиск песен в вк (музыка Slipknot / аудио Disturbed - Inside The Fire)
|
||||||
|
- вкфото: поиск картинок в вк (вкфото авто)
|
||||||
|
- видео / видос: поиск видео в вк (видос концерт Parkway Drive)
|
||||||
|
- стата / статистика: выводит статистику о работе бота
|
||||||
|
- когда: определяет дату того или иного события (когда я пойду спать?)
|
16
src/holdfast/samobot/Config.java
Normal file
16
src/holdfast/samobot/Config.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author HoldFast
|
||||||
|
*/
|
||||||
|
public class Config {
|
||||||
|
|
||||||
|
// https://oauth.vk.com/authorize?client_id=APP_ID&scope=photos,messages,notifications,wall,audio,video&redirect_uri=https://oauth.vk.com/blank.html&display=page&v=5.34&response_type=token
|
||||||
|
|
||||||
|
public static final String access_token = "";
|
||||||
|
|
||||||
|
public static final String BOT_NAMES = "лена|леночка"; // обращение
|
||||||
|
public static final String ANSWER_PREFIX = "";//"[Вадос] "; // префикс перед выводом сообщения бота
|
||||||
|
|
||||||
|
}
|
108
src/holdfast/samobot/ControlFrame.java
Normal file
108
src/holdfast/samobot/ControlFrame.java
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class ControlFrame extends JFrame {
|
||||||
|
|
||||||
|
private static final String TITLE = "Лена-бот";
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
EventQueue.invokeLater(() -> new ControlFrame().setVisible(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlFrame() {
|
||||||
|
super(TITLE);
|
||||||
|
|
||||||
|
final JMenuBar menu = new JMenuBar();
|
||||||
|
final JMenu botMenu = new JMenu("Бот");
|
||||||
|
final JMenuItem launchMenuItem = new JMenuItem("Запустить");
|
||||||
|
final JMenuItem exitMenuItem = new JMenuItem("Выход");
|
||||||
|
botMenu.add(launchMenuItem);
|
||||||
|
botMenu.add(exitMenuItem);
|
||||||
|
menu.add(botMenu);
|
||||||
|
final JMenu helpMenu = new JMenu("Помощь");
|
||||||
|
final JMenuItem commandsMenuItem = new JMenuItem("Команды");
|
||||||
|
helpMenu.add(commandsMenuItem);
|
||||||
|
menu.add(helpMenu);
|
||||||
|
setJMenuBar(menu);
|
||||||
|
|
||||||
|
setLocationByPlatform(true);
|
||||||
|
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
|
setPreferredSize(new Dimension(450, 320));
|
||||||
|
|
||||||
|
final JTabbedPane tabbedPane = new JTabbedPane();
|
||||||
|
final JPanel controlPanel = new JPanel();
|
||||||
|
controlPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||||
|
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.PAGE_AXIS));
|
||||||
|
controlPanel.add(new JLabel("Текст сообщения:"));
|
||||||
|
final JTextArea messageArea = new JTextArea(5, 20);
|
||||||
|
messageArea.setFont(messageArea.getFont().deriveFont(14));
|
||||||
|
controlPanel.add(new JScrollPane(messageArea));
|
||||||
|
controlPanel.add(new JLabel("ID беседы:"));
|
||||||
|
final JTextField chatIdField = new JTextField("2");
|
||||||
|
chatIdField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
|
||||||
|
controlPanel.add(chatIdField);
|
||||||
|
final JButton sendButton = new JButton("Отправить");
|
||||||
|
controlPanel.add(sendButton);
|
||||||
|
tabbedPane.addTab("Отправить сообщение", controlPanel);
|
||||||
|
|
||||||
|
final JTextPane chatLog = new JTextPane();
|
||||||
|
chatLog.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||||
|
tabbedPane.addTab("Лог чата", new JScrollPane(chatLog));
|
||||||
|
|
||||||
|
final JTextPane queryLog = new JTextPane();
|
||||||
|
queryLog.setFont(chatLog.getFont());
|
||||||
|
tabbedPane.addTab("Лог запросов", new JScrollPane(queryLog));
|
||||||
|
|
||||||
|
final JTextPane errorsLog = new JTextPane();
|
||||||
|
errorsLog.setFont(new Font("Monospaced", Font.PLAIN, 10));
|
||||||
|
tabbedPane.addTab("Лог ошибок", new JScrollPane(errorsLog));
|
||||||
|
|
||||||
|
add(tabbedPane);
|
||||||
|
pack();
|
||||||
|
|
||||||
|
Log.init(chatLog, queryLog, errorsLog);
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
launchMenuItem.addActionListener((e) -> {
|
||||||
|
if (!MainThread.run) {
|
||||||
|
StatisticsProcessor.init();
|
||||||
|
new Thread(new MainThread(true)).start();
|
||||||
|
launchMenuItem.setText("Остановить");
|
||||||
|
setTitle(TITLE + " - Работает");
|
||||||
|
} else {
|
||||||
|
MainThread.run = false;
|
||||||
|
launchMenuItem.setText("Запустить");
|
||||||
|
setTitle(TITLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
exitMenuItem.addActionListener((e) -> System.exit(0));
|
||||||
|
commandsMenuItem.addActionListener((e) -> {
|
||||||
|
try {
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
IOUtil.readResponse(getClass().getResourceAsStream("/commands.txt")),
|
||||||
|
TITLE, JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sendButton.addActionListener((e) -> {
|
||||||
|
final String message = messageArea.getText();
|
||||||
|
final int chatId = Integer.parseInt(chatIdField.getText());
|
||||||
|
new Thread( () -> {
|
||||||
|
VK.sendMessage(message, null, chatId, 0);
|
||||||
|
EventQueue.invokeLater(() -> messageArea.setText(""));
|
||||||
|
}).start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
117
src/holdfast/samobot/IOUtil.java
Normal file
117
src/holdfast/samobot/IOUtil.java
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class IOUtil {
|
||||||
|
|
||||||
|
public static String get(String link) {
|
||||||
|
try {
|
||||||
|
final URL url = new URL(link);
|
||||||
|
return readResponse(url.openStream());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getWithUserAgent(String address) throws IOException {
|
||||||
|
URL urls = new URL(address);
|
||||||
|
HttpURLConnection http = (HttpURLConnection) urls.openConnection();
|
||||||
|
http.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||||
|
http.setRequestProperty("Charset", "UTF-8");
|
||||||
|
return readResponse(http.getInputStream());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String upload(String link, String params, byte[] data, String ext) {
|
||||||
|
try {
|
||||||
|
final URL url = new URL(link);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||||
|
con.setRequestMethod("POST");
|
||||||
|
con.setDoOutput(true);
|
||||||
|
final String boundary = Long.toHexString(System.currentTimeMillis());
|
||||||
|
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||||
|
|
||||||
|
try (DataOutputStream writer = new DataOutputStream(con.getOutputStream())) {
|
||||||
|
writer.write(params.getBytes());
|
||||||
|
writer.write( ("\r\n--" + boundary + "\r\n").getBytes() );
|
||||||
|
writer.write( ("Content-Disposition: form-data; name=\"file\"; filename=\"file." + ext + "\"\r\n").getBytes() );
|
||||||
|
writer.write( ("Content-Type: image/" + ext + "\r\n").getBytes());
|
||||||
|
writer.write("Content-Transfer-Encoding: binary\r\n\r\n".getBytes());
|
||||||
|
writer.write(data);
|
||||||
|
writer.write( ("\r\n--" + boundary + "--\r\n").getBytes() );
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
return readResponse(con.getInputStream());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] download(String link) {
|
||||||
|
ByteArrayOutputStream uploadParams = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
final URL url = new URL(link);
|
||||||
|
try (InputStream is = url.openStream()) {
|
||||||
|
byte[] byteChunk = new byte[4096];
|
||||||
|
int n;
|
||||||
|
while ((n = is.read(byteChunk)) > 0) {
|
||||||
|
uploadParams.write(byteChunk, 0, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) { }
|
||||||
|
return uploadParams.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String post(String link, byte[] data) {
|
||||||
|
try {
|
||||||
|
final URL url = new URL(link);
|
||||||
|
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||||
|
con.setRequestMethod("POST");
|
||||||
|
con.setDoOutput(true);
|
||||||
|
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
|
||||||
|
wr.write(data);
|
||||||
|
wr.flush();
|
||||||
|
}
|
||||||
|
return readResponse(con.getInputStream());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readResponse(InputStream is) throws IOException {
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
|
||||||
|
String inputLine;
|
||||||
|
while ((inputLine = in.readLine()) != null) {
|
||||||
|
response.append(inputLine).append(Util.NEW_LINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String stackTraceToString(Throwable t) {
|
||||||
|
try (
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
) {
|
||||||
|
t.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
src/holdfast/samobot/Log.java
Normal file
97
src/holdfast/samobot/Log.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import javax.swing.JTextPane;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import javax.swing.text.Style;
|
||||||
|
import javax.swing.text.StyleConstants;
|
||||||
|
import javax.swing.text.StyledDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Log {
|
||||||
|
|
||||||
|
public static final String NORMAL = "normal";
|
||||||
|
public static final String SMALL = "small";
|
||||||
|
public static final String RED = "red";
|
||||||
|
public static final String GREEN = "green";
|
||||||
|
public static final String BLUE = "blue";
|
||||||
|
|
||||||
|
private static StyledDocument chat, query, errors;
|
||||||
|
|
||||||
|
public static void init(JTextPane chatPane, JTextPane queryPane, JTextPane errorsPane) {
|
||||||
|
Log.chat = chatPane.getStyledDocument();
|
||||||
|
Log.query = queryPane.getStyledDocument();
|
||||||
|
Log.errors = errorsPane.getStyledDocument();
|
||||||
|
addStyles(chatPane);
|
||||||
|
addStyles(queryPane);
|
||||||
|
addStyles(errorsPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addStyles(JTextPane pane) {
|
||||||
|
Style normal = pane.addStyle(NORMAL, null);
|
||||||
|
|
||||||
|
StyleConstants.setFontSize(pane.addStyle(SMALL, normal), 8);
|
||||||
|
StyleConstants.setForeground(pane.addStyle(RED, normal), Color.RED);
|
||||||
|
StyleConstants.setForeground(pane.addStyle(GREEN, normal), Color.GREEN);
|
||||||
|
StyleConstants.setForeground(pane.addStyle(BLUE, normal), new Color(0xFF2E217B));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(Throwable throwable) {
|
||||||
|
insertTo(errors, IOUtil.stackTraceToString(throwable) + "\n\n", RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void chatln(String text) {
|
||||||
|
chat(text + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void chatln(String text, String style) {
|
||||||
|
chat(text + "\n", style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void chat(String text) {
|
||||||
|
chat(text, NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void chat(String text, String style) {
|
||||||
|
insertTo(chat, text, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void queryln(String text) {
|
||||||
|
query(text + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void queryln(String text, String style) {
|
||||||
|
query(text + "\n", style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void query(String text) {
|
||||||
|
query(text, NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void query(String text, String style) {
|
||||||
|
insertTo(query, text, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void insertTo(StyledDocument doc, String text, String style) {
|
||||||
|
try {
|
||||||
|
doc.insertString(doc.getLength(), text, doc.getStyle(style));
|
||||||
|
} catch (BadLocationException ex) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final boolean LOG = true;
|
||||||
|
|
||||||
|
public static void println(int value) {
|
||||||
|
if (LOG) {
|
||||||
|
System.out.println(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void println(String text) {
|
||||||
|
if (LOG) {
|
||||||
|
System.out.println(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
src/holdfast/samobot/MainThread.java
Normal file
123
src/holdfast/samobot/MainThread.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import holdfast.samobot.commands.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author HoldFast
|
||||||
|
*/
|
||||||
|
public class MainThread implements Runnable {
|
||||||
|
|
||||||
|
private static final String[] MESSAGES = {
|
||||||
|
"Ору с вас!", "Проигрываю", "Славка, го осу", "Олег, рисуй!", "Эд, го кодить",
|
||||||
|
"Листочек, потри мне сосочек", "Пойду вскроюсь", "Не за надпись"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int ACCOUNT_ID = 258220262;
|
||||||
|
public static boolean run = false;
|
||||||
|
|
||||||
|
private final Command[] commands;
|
||||||
|
private int lastChatId = 2;
|
||||||
|
|
||||||
|
public MainThread(boolean run) {
|
||||||
|
MainThread.run = run;
|
||||||
|
commands = new Command[] {
|
||||||
|
new PhotoSearch(),
|
||||||
|
new VkPhotoSearch(),
|
||||||
|
new VkAudioSearch(),
|
||||||
|
new VkVideoSearch(),
|
||||||
|
new LyricSearch(),
|
||||||
|
new GoogleAnswer(),
|
||||||
|
new GooglePhotoSearch(),
|
||||||
|
new Oboobs(),
|
||||||
|
new Obutts(),
|
||||||
|
new Chooser(),
|
||||||
|
new Possibility(),
|
||||||
|
new SendMessage(),
|
||||||
|
new Pirozhki(),
|
||||||
|
new Currency(),
|
||||||
|
new Stats(),
|
||||||
|
new When(),
|
||||||
|
|
||||||
|
new AnnimonResponse()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
int countEmptyUnread = 0;
|
||||||
|
int pts = VK.getLastPTS();
|
||||||
|
while (run) {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
|
||||||
|
String obj = VK.getUnread(pts);
|
||||||
|
if (obj.isEmpty()) {
|
||||||
|
countEmptyUnread++;
|
||||||
|
if (countEmptyUnread >= 4) {
|
||||||
|
pts = VK.getLastPTS();
|
||||||
|
countEmptyUnread = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject response = new JSONObject(obj).getJSONObject("response");
|
||||||
|
pts = response.getInt("new_pts");
|
||||||
|
JSONArray messages = response.getJSONArray("messages");
|
||||||
|
JSONArray profiles = response.getJSONArray("profiles");
|
||||||
|
final int messagesLength = messages.length();
|
||||||
|
if (messagesLength == 1 && Util.random(80) == 5) {
|
||||||
|
String message;
|
||||||
|
if (Util.random(6) == 2) {
|
||||||
|
message = MESSAGES[Util.random(MESSAGES.length)];
|
||||||
|
} else {
|
||||||
|
message = AnnimonResponse.getResponse("jhgjh");
|
||||||
|
}
|
||||||
|
VK.sendMessage(message, null, lastChatId, 0);
|
||||||
|
} else {
|
||||||
|
for (int i = 1; i < messagesLength; i++) {
|
||||||
|
final JSONObject profile = profiles.getJSONObject(i - 1);
|
||||||
|
if (profile.getInt("uid") != ACCOUNT_ID) {
|
||||||
|
final JSONObject currentMessage = messages.getJSONObject(i);
|
||||||
|
answer(currentMessage, profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
new Thread(this).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void answer(JSONObject currentMessage, JSONObject profile) throws Exception {
|
||||||
|
String message = currentMessage.getString("body");
|
||||||
|
final int forward = currentMessage.getInt("mid");
|
||||||
|
final int chatId = lastChatId = currentMessage.optInt("chat_id", currentMessage.getInt("uid"));
|
||||||
|
final boolean toUser = !currentMessage.has("chat_id");
|
||||||
|
final String userName = profile.getString("first_name");
|
||||||
|
|
||||||
|
|
||||||
|
Matcher match = Pattern.compile("^("+Config.BOT_NAMES + "),? ?(.+)", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE).matcher(message);
|
||||||
|
if (!match.matches()) return;
|
||||||
|
|
||||||
|
message = match.group(2).trim();
|
||||||
|
final String[] words = message.split("\\s+");
|
||||||
|
if (words.length == 0) return;
|
||||||
|
|
||||||
|
final String cmd = words[0].toLowerCase();
|
||||||
|
for (Command command : commands) {
|
||||||
|
if (!command.match(cmd)) continue;
|
||||||
|
if (command.execute(chatId, toUser, forward, userName, words, message)) {
|
||||||
|
Log.chatln(String.format("(%s): %s", userName, message));
|
||||||
|
StatisticsProcessor.updateUsername(userName);
|
||||||
|
StatisticsProcessor.updateAnswersCounter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/holdfast/samobot/StatisticsProcessor.java
Normal file
74
src/holdfast/samobot/StatisticsProcessor.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class StatisticsProcessor {
|
||||||
|
|
||||||
|
private static Instant startTime;
|
||||||
|
private static long answers, photosUploaded;
|
||||||
|
private static Map<String, Integer> usersActivity;
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
startTime = Instant.now();
|
||||||
|
usersActivity = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instant getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void updateAnswersCounter() {
|
||||||
|
answers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getAnswers() {
|
||||||
|
return answers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updatePhotosUploadedCounter() {
|
||||||
|
photosUploaded++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getPhotosUploaded() {
|
||||||
|
return photosUploaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateUsername(String name) {
|
||||||
|
usersActivity.put(name, usersActivity.getOrDefault(name, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String asString() {
|
||||||
|
final Duration duration = Duration.between(startTime, Instant.now());
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Время работы: ");
|
||||||
|
long time;
|
||||||
|
time = duration.toHours();
|
||||||
|
if (time != 0) sb.append(time).append(" ч. ");
|
||||||
|
time = duration.toMinutes() % 60;
|
||||||
|
if (time != 0) sb.append(time).append(" мин. ");
|
||||||
|
time = duration.getSeconds() % 60;
|
||||||
|
if (time != 0) sb.append(time).append(" сек. ");
|
||||||
|
sb.append('\n');
|
||||||
|
|
||||||
|
sb.append("Отправлено сообщений: ").append(answers).append('\n');
|
||||||
|
sb.append("Загружено фотографий: ").append(photosUploaded).append('\n');
|
||||||
|
|
||||||
|
sb.append("Активные пользователи:\n");
|
||||||
|
sb.append(usersActivity.entrySet().stream()
|
||||||
|
.sorted((a, b) -> Integer.compare(b.getValue(), a.getValue()))
|
||||||
|
.limit(5)
|
||||||
|
.map(e -> String.format("%s: %d сообщений\n", e.getKey(), e.getValue()))
|
||||||
|
.collect(Collectors.joining()));
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
49
src/holdfast/samobot/Util.java
Normal file
49
src/holdfast/samobot/Util.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Util {
|
||||||
|
|
||||||
|
public static final String NEW_LINE = System.lineSeparator();
|
||||||
|
|
||||||
|
private static final String[] MONTH = {
|
||||||
|
"января", "февраля", "марта", "апреля", "мая", "июня",
|
||||||
|
"июля", "августа", "сентября", "октября", "ноября", "декабря"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Random rnd = new Random();
|
||||||
|
|
||||||
|
public static int random(int max) {
|
||||||
|
return rnd.nextInt(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int random(int min, int max) {
|
||||||
|
return min + rnd.nextInt(max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateToString(Date date) {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(date);
|
||||||
|
return String.format(Locale.getDefault(), "%02d %s %d",
|
||||||
|
cal.get(Calendar.DAY_OF_MONTH),
|
||||||
|
MONTH[cal.get(Calendar.MONTH)],
|
||||||
|
cal.get(Calendar.YEAR));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateToString(LocalDate date) {
|
||||||
|
return String.format(Locale.getDefault(), "%02d %s %d",
|
||||||
|
date.getDayOfMonth(),
|
||||||
|
MONTH[date.getMonthValue() - 1],
|
||||||
|
date.getYear());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
157
src/holdfast/samobot/VK.java
Normal file
157
src/holdfast/samobot/VK.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package holdfast.samobot;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author HoldFast
|
||||||
|
*/
|
||||||
|
public class VK {
|
||||||
|
|
||||||
|
public static String url = "https://api.vk.com/method/";
|
||||||
|
|
||||||
|
public static void sendMessage(String text, String attachment, int chatId, int forward) {
|
||||||
|
sendMessage(text, attachment, chatId, (chatId > 10000), forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(String text, String attachment, int chatId, boolean toUser, int forward) {
|
||||||
|
Log.chatln("(Лена): " + text, Log.BLUE);
|
||||||
|
StringBuilder query = new StringBuilder();
|
||||||
|
query.append(toUser ? "user_id=" : "chat_id=").append(chatId);
|
||||||
|
try {
|
||||||
|
query.append("&message=").append(URLEncoder.encode(Config.ANSWER_PREFIX + text, "UTF-8"));
|
||||||
|
} catch (IOException ioe) { }
|
||||||
|
if (attachment != null) {
|
||||||
|
query.append("&attachment=").append(attachment);
|
||||||
|
}
|
||||||
|
if (forward != 0) {
|
||||||
|
query.append("&forward_messages=").append(forward);
|
||||||
|
}
|
||||||
|
VK.query("messages.send", query.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String query(String method, String params) {
|
||||||
|
params = "access_token=" + Config.access_token + "&" + params;
|
||||||
|
Log.queryln(" > " + url + method + "?" + params, Log.BLUE);
|
||||||
|
String res = IOUtil.post(url + method, params.getBytes());
|
||||||
|
Log.query(" < ");
|
||||||
|
Log.queryln(res, Log.SMALL);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getLastPTS() {
|
||||||
|
String query = query("messages.getLongPollServer", "v=5.34&use_ssl=0&need_pts=1");
|
||||||
|
Log.queryln(" > get last pts");
|
||||||
|
Log.query(" < get last pts: ");
|
||||||
|
Log.queryln(query, Log.SMALL);
|
||||||
|
return (new JSONObject(query).getJSONObject("response")).getInt("pts");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getUploadServer() {
|
||||||
|
return (new JSONObject(query("photos.getMessagesUploadServer", "v=5.37")).getJSONObject("response")).getString("upload_url");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getUnread(int pts) {
|
||||||
|
String result = VK.query("messages.getLongPollHistory", "pts=" + pts);
|
||||||
|
Log.queryln(" > get unread " + pts, Log.GREEN);
|
||||||
|
Log.query(" < get unread: ");
|
||||||
|
Log.queryln(result, Log.SMALL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRandomPhoto(String query, int count, int offset) {
|
||||||
|
try {
|
||||||
|
String obj = VK.query("photos.search", "q=" + URLEncoder.encode(query.trim(), "UTF-8") + "&count=" + count + "&offset=" + offset);
|
||||||
|
Log.queryln(" > get photo " + query, Log.GREEN);
|
||||||
|
Log.query(" < get photo: ");
|
||||||
|
Log.queryln(obj, Log.SMALL);
|
||||||
|
JSONObject json = new JSONObject(obj);
|
||||||
|
JSONArray response = json.getJSONArray("response");
|
||||||
|
if (response.length() <= 1) return null;
|
||||||
|
|
||||||
|
JSONObject photo = response.getJSONObject(1);
|
||||||
|
return "photo" + photo.get("owner_id") + "_" + photo.get("pid");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRandomAudio(String query, int count) {
|
||||||
|
try {
|
||||||
|
String obj = VK.query("audio.search", "q=" + URLEncoder.encode(query.trim(), "UTF-8") + "&auto_complete=1&count=" + count);
|
||||||
|
Log.queryln(" > get audio " + query, Log.GREEN);
|
||||||
|
Log.query(" < get audio: ");
|
||||||
|
Log.queryln(obj, Log.SMALL);
|
||||||
|
JSONObject json = new JSONObject(obj);
|
||||||
|
JSONArray response = json.getJSONArray("response");
|
||||||
|
if (response.length() < 1) return null;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i < response.length(); i++) {
|
||||||
|
JSONObject audio = response.getJSONObject(i);
|
||||||
|
sb.append("audio").append(audio.get("owner_id")).append('_').append(audio.get("aid"));
|
||||||
|
sb.append(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.substring(0, sb.length() - 1);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRandomVideo(String query, int count) {
|
||||||
|
try {
|
||||||
|
String obj = VK.query("video.search", "q=" + URLEncoder.encode(query.trim(), "UTF-8") + "&adult=0&count=" + count);
|
||||||
|
Log.queryln(" > get video " + query, Log.GREEN);
|
||||||
|
Log.query(" < get video: ");
|
||||||
|
Log.queryln(obj, Log.SMALL);
|
||||||
|
JSONObject json = new JSONObject(obj);
|
||||||
|
JSONArray response = json.getJSONArray("response");
|
||||||
|
if (response.length() < 1) return null;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i < response.length(); i++) {
|
||||||
|
JSONObject video = response.getJSONObject(i);
|
||||||
|
sb.append("video").append(video.get("owner_id")).append('_').append(video.get("id"));
|
||||||
|
sb.append(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.substring(0, sb.length() - 1);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String uploadPhoto(String photoUrl) {
|
||||||
|
String uploadServer = getUploadServer();
|
||||||
|
Log.queryln(" > upload photo to " + uploadServer);
|
||||||
|
|
||||||
|
String uploadResultRaw = IOUtil.upload(uploadServer, "photo=", IOUtil.download(photoUrl), getExtension(photoUrl));
|
||||||
|
Log.query(" < upload photo result: ");
|
||||||
|
Log.queryln(uploadResultRaw, Log.SMALL);
|
||||||
|
JSONObject uploadResult = new JSONObject(uploadResultRaw);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("server=").append(uploadResult.get("server"));
|
||||||
|
sb.append("&photo=").append(uploadResult.get("photo"));
|
||||||
|
sb.append("&hash=").append(uploadResult.get("hash"));
|
||||||
|
|
||||||
|
String photoRaw = VK.query("photos.saveMessagesPhoto", sb.toString());
|
||||||
|
Log.query(" < saveMessagesPhoto result: ");
|
||||||
|
Log.queryln(photoRaw, Log.SMALL);
|
||||||
|
JSONObject photo = new JSONObject(photoRaw).getJSONArray("response").getJSONObject(0);
|
||||||
|
StatisticsProcessor.updatePhotosUploadedCounter();
|
||||||
|
return "photo" + photo.get("owner_id") + "_" + photo.get("pid");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getExtension(String link) {
|
||||||
|
if (link.endsWith(".png")) return "png";
|
||||||
|
return "jpg";
|
||||||
|
}
|
||||||
|
}
|
52
src/holdfast/samobot/commands/AnnimonResponse.java
Normal file
52
src/holdfast/samobot/commands/AnnimonResponse.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import holdfast.samobot.Log;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class AnnimonResponse extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(String cmd) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
String response = getResponse(message);
|
||||||
|
if (response == null) return false;
|
||||||
|
|
||||||
|
send(userName + ", " + response);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getResponse(String query) {
|
||||||
|
try {
|
||||||
|
String response = IOUtil.get("https://query.yahooapis.com/v1/public/yql?q="
|
||||||
|
+ "select%20*%20from%20htmlpost%20where%20url%3D"
|
||||||
|
+ "\"http%3A%2F%2Fannimon.com%2Fjson%2Fbot_vk.php\""
|
||||||
|
+ "%20and%20postdata%3D\"%26text%3D" + URLEncoder.encode(query, "UTF-8") + "%26\""
|
||||||
|
+ "%20and%20xpath%3D\"*\"&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
|
||||||
|
return new JSONObject(response)
|
||||||
|
.getJSONObject("query")
|
||||||
|
.getJSONObject("results")
|
||||||
|
.getJSONObject("postresult")
|
||||||
|
.getJSONObject("html")
|
||||||
|
.getString("body");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/holdfast/samobot/commands/Chooser.java
Normal file
27
src/holdfast/samobot/commands/Chooser.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Chooser extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "выбери" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
message = message.substring(words[0].length());
|
||||||
|
|
||||||
|
final String[] args = message.split(",\\s?");
|
||||||
|
final int index = Util.random(args.length);
|
||||||
|
|
||||||
|
send(userName + ", я выбираю " + args[index]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
55
src/holdfast/samobot/commands/Command.java
Normal file
55
src/holdfast/samobot/commands/Command.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Log;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public abstract class Command {
|
||||||
|
|
||||||
|
protected String[] words;
|
||||||
|
protected boolean toUser;
|
||||||
|
protected int chatId;
|
||||||
|
protected int forward;
|
||||||
|
|
||||||
|
public boolean match(String cmd) {
|
||||||
|
for (String command : command()) {
|
||||||
|
if (cmd.equalsIgnoreCase(command)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean execute(int chatId, boolean toUser, int forward, String userName, String[] words, String message) {
|
||||||
|
this.chatId = chatId;
|
||||||
|
this.toUser = toUser;
|
||||||
|
this.words = words;
|
||||||
|
this.forward = forward;
|
||||||
|
try {
|
||||||
|
return execute(message, userName);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String[] command();
|
||||||
|
|
||||||
|
protected abstract boolean execute(String message, String userName) throws IOException;
|
||||||
|
|
||||||
|
protected void send(String text) throws IOException {
|
||||||
|
send(text, null, forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void send(String text, String attachment) throws IOException {
|
||||||
|
send(text, attachment, forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void send(String text, String attachment, int forward) throws IOException {
|
||||||
|
VK.sendMessage(text, attachment, chatId, toUser, forward);
|
||||||
|
}
|
||||||
|
}
|
71
src/holdfast/samobot/commands/Currency.java
Normal file
71
src/holdfast/samobot/commands/Currency.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import static holdfast.samobot.Util.NEW_LINE;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class Currency extends Command {
|
||||||
|
|
||||||
|
private static final String API_URL = "https://query.yahooapis.com/v1/public/yql?q=select+*+from+yahoo.finance.xchange+where+pair+=+%22USDRUB,EURRUB,USDUAH,EURUAH,UAHRUB%22&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "курс", "валюта" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
String raw = IOUtil.get(API_URL);
|
||||||
|
JSONArray array = new JSONObject(raw).getJSONObject("query").getJSONObject("results").getJSONArray("rate");
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Курс валют:");
|
||||||
|
for (int i = 0; i < array.length(); i++) {
|
||||||
|
Rate rate = new Rate(array.optJSONObject(i));
|
||||||
|
sb.append(NEW_LINE).append(rate.getReadableString());
|
||||||
|
}
|
||||||
|
|
||||||
|
send(sb.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class Rate {
|
||||||
|
|
||||||
|
private static final Map<String, String> readableName;
|
||||||
|
|
||||||
|
static {
|
||||||
|
readableName = new HashMap<>();
|
||||||
|
readableName.put("USDRUB", "Доллар: %f рублей");
|
||||||
|
readableName.put("EURRUB", "Евро: %f рублей");
|
||||||
|
readableName.put("USDUAH", "Доллар: %f гривен");
|
||||||
|
readableName.put("EURUAH", "Евро: %f гривен");
|
||||||
|
readableName.put("UAHRUB", "Гривна: %f рублей");
|
||||||
|
}
|
||||||
|
|
||||||
|
String id;
|
||||||
|
double rate;
|
||||||
|
|
||||||
|
public Rate(String id, double rate) {
|
||||||
|
this.id = id;
|
||||||
|
this.rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rate(JSONObject json) {
|
||||||
|
this.id = json.getString("id");
|
||||||
|
this.rate = json.getDouble("Rate");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReadableString() {
|
||||||
|
return String.format(readableName.get(id), rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
src/holdfast/samobot/commands/GoogleAnswer.java
Normal file
83
src/holdfast/samobot/commands/GoogleAnswer.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import holdfast.samobot.Log;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class GoogleAnswer extends Command {
|
||||||
|
|
||||||
|
private static String GOOGLE_URL = "https://www.google.ru/search?hl=ru&ie=UTF-8&q=";
|
||||||
|
private static final String[] SKIP_RESULTS = {
|
||||||
|
"Похожие запросы", "Показаны результаты", "Поиск рядом"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "ответ" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
message = message.substring(words[0].length());
|
||||||
|
|
||||||
|
String fact = getFact(message);
|
||||||
|
if (fact == null) return false;
|
||||||
|
|
||||||
|
send(fact);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String getFact(String query) {
|
||||||
|
try {
|
||||||
|
URL urls = new URL(GOOGLE_URL + URLEncoder.encode(query, "UTF-8"));
|
||||||
|
HttpURLConnection http = (HttpURLConnection) urls.openConnection();
|
||||||
|
http.setRequestProperty("User-Agent", "Opera/9.80 (J2ME/MIDP; Opera Mini/4.4.29476/27.1573; U; id) Presto/2.8.119 Version/11.10");
|
||||||
|
http.setRequestProperty("Charset", "UTF-8");
|
||||||
|
|
||||||
|
String fact = IOUtil.readResponse(http.getInputStream());
|
||||||
|
|
||||||
|
if (fact.contains("<div style=\"padding:5px 0 5px 2px;font-weight:bold\">")) {
|
||||||
|
String left = fact.substring(fact.indexOf("<div style=\"padding:5px 0 5px 2px;font-weight:bold\">") + 52);
|
||||||
|
String right = left.substring(0, left.indexOf("</div>"));
|
||||||
|
right = right.replaceAll("\\<[^>]*>", "\n").replaceAll("\n{2,}", "\n").replace(" ", "").trim();
|
||||||
|
if (!right.isEmpty()) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int index = 0;
|
||||||
|
while (true) {
|
||||||
|
index = fact.indexOf("onebox_result\">", index + 1);
|
||||||
|
if (index == -1) return null;
|
||||||
|
|
||||||
|
String left = fact.substring(index + 15);
|
||||||
|
String right = left.substring(0, left.indexOf("</div>"));
|
||||||
|
final String block = right
|
||||||
|
.replace("<sup>", "^")
|
||||||
|
.replace("</sup>", "")
|
||||||
|
.replaceAll("\\<[^>]*>", "\n")
|
||||||
|
.replaceAll("\n{2,}", "\n")
|
||||||
|
.replace(" ", "").trim();
|
||||||
|
if (block.isEmpty()) continue;
|
||||||
|
|
||||||
|
if (Arrays.stream(SKIP_RESULTS)
|
||||||
|
.noneMatch(s -> block.startsWith(s))) {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.error(ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
45
src/holdfast/samobot/commands/GooglePhotoSearch.java
Normal file
45
src/holdfast/samobot/commands/GooglePhotoSearch.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class GooglePhotoSearch extends Command {
|
||||||
|
|
||||||
|
private static final String API_URL = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&q=";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "фото", "покажи" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
final String query = message.substring(words[0].length());
|
||||||
|
|
||||||
|
String json = IOUtil.get(API_URL + URLEncoder.encode(query, "UTF-8"));
|
||||||
|
String photoUrl = new JSONObject(json).getJSONObject("responseData").getJSONArray("results").getJSONObject(Util.random(8)).getString("url");
|
||||||
|
|
||||||
|
String photo;
|
||||||
|
try {
|
||||||
|
photo = VK.uploadPhoto(photoUrl);
|
||||||
|
} catch (Exception e) {
|
||||||
|
photo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (photo == null) {
|
||||||
|
send(userName + ", ничего не найдено :(");
|
||||||
|
} else {
|
||||||
|
send(userName, photo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
126
src/holdfast/samobot/commands/LyricSearch.java
Normal file
126
src/holdfast/samobot/commands/LyricSearch.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class LyricSearch extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "текст" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
message = message.substring(words[0].length());
|
||||||
|
String[] title = message.split(" - | — ");
|
||||||
|
if (title.length > 1) {
|
||||||
|
send(userName + ", \n" + getText(title[0].trim(), title[1].trim()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String ucwords(String str) {
|
||||||
|
if (str == null || str.isEmpty()) return "";
|
||||||
|
|
||||||
|
str = str.trim();
|
||||||
|
if (str.contains(" ")) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
while (str.contains(" ")) {
|
||||||
|
String tmp = str.substring(0, str.indexOf(" "));
|
||||||
|
if (!tmp.trim().isEmpty()) {
|
||||||
|
sb.append(Character.toUpperCase(tmp.charAt(0))).append(tmp.substring(1, tmp.length()).toLowerCase()).append(' ');
|
||||||
|
}
|
||||||
|
str = str.substring(str.indexOf(" ") + 1, str.length());
|
||||||
|
}
|
||||||
|
sb.append(Character.toUpperCase(str.charAt(0))).append(str.substring(1, str.length()).toLowerCase());
|
||||||
|
str = sb.toString().trim();
|
||||||
|
} else {
|
||||||
|
str = Character.toUpperCase(str.charAt(0)) + str.substring(1, str.length()).toLowerCase();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getTextWithCorrectArtistName(String artist, String title) throws JSONException, IOException {
|
||||||
|
try {
|
||||||
|
String data = IOUtil.getWithUserAgent("https://lyrics.wikia.com/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=" + URLEncoder.encode(artist, "UTF-8"));
|
||||||
|
json = new JSONObject(data);
|
||||||
|
String name = json.getJSONObject("query").getJSONObject("pages").names().get(0).toString();
|
||||||
|
JSONObject r = new JSONObject(json.getJSONObject("query").getJSONObject("pages").getJSONObject(name).getJSONArray("revisions").get(0).toString());
|
||||||
|
artist = r.get("*").toString().trim();
|
||||||
|
|
||||||
|
if (artist.toUpperCase().contains("#REDIRECT")) {
|
||||||
|
artist = artist.substring(artist.indexOf("[[") + 2, artist.indexOf("]]"));
|
||||||
|
}
|
||||||
|
System.out.println(artist);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return giveText(artist, title);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getRedirect(String redirect) throws JSONException {
|
||||||
|
json = new JSONObject(redirect);
|
||||||
|
String name = json.getJSONObject("query").getJSONObject("pages").names().get(0).toString();
|
||||||
|
JSONObject r = new JSONObject(json.getJSONObject("query").getJSONObject("pages").getJSONObject(name).getJSONArray("revisions").get(0).toString());
|
||||||
|
name = r.get("*").toString().trim();
|
||||||
|
if (!name.equals("")) {
|
||||||
|
name = name.substring(name.indexOf("[[") + 2, name.indexOf("]]"));
|
||||||
|
try {
|
||||||
|
return IOUtil.getWithUserAgent("https://lyrics.wikia.com/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=" + URLEncoder.encode(name, "UTF-8"));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return redirect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extractText(String data) throws JSONException {
|
||||||
|
if (!data.contains("<lyrics>")) return "";
|
||||||
|
json = new JSONObject(data);
|
||||||
|
String name = json.getJSONObject("query").getJSONObject("pages").names().get(0).toString();
|
||||||
|
JSONObject r = new JSONObject(json.getJSONObject("query").getJSONObject("pages").getJSONObject(name).getJSONArray("revisions").get(0).toString());
|
||||||
|
data = r.get("*").toString().trim();
|
||||||
|
data = data.substring(data.indexOf("<lyrics>") + 8, data.indexOf("</lyrics>"));
|
||||||
|
return data.trim();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String giveText(String artist, String title) throws IOException, JSONException {
|
||||||
|
String data = IOUtil.getWithUserAgent("https://lyrics.wikia.com/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=" + URLEncoder.encode(artist, "UTF-8") + ':' + URLEncoder.encode(title, "UTF-8"));
|
||||||
|
String text = extractText(data);
|
||||||
|
if (data.contains("#REDIRECT [[")) {
|
||||||
|
text = getRedirect(data);
|
||||||
|
text = extractText(text);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getText(String artist, String title) {
|
||||||
|
try {
|
||||||
|
artist = ucwords(artist);
|
||||||
|
title = ucwords(title);
|
||||||
|
String text = giveText(artist, title);
|
||||||
|
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
text = getTextWithCorrectArtistName(artist, title);
|
||||||
|
}
|
||||||
|
return (text.trim().equals("")) ? "я таких песен не знаю" : text;
|
||||||
|
} catch (Exception jex) {
|
||||||
|
return "я таких песен не знаю";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private static JSONObject json = null;
|
||||||
|
}
|
37
src/holdfast/samobot/commands/Oboobs.java
Normal file
37
src/holdfast/samobot/commands/Oboobs.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class Oboobs extends Command {
|
||||||
|
|
||||||
|
private static final String API_URL = "http://api.oboobs.ru/noise";
|
||||||
|
private static final String URL = "http://media.oboobs.ru/";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "boobs", "сиськи", "сиси" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
String raw = IOUtil.get(API_URL);
|
||||||
|
JSONObject obj = new JSONArray(raw).getJSONObject(0);
|
||||||
|
|
||||||
|
String photo = VK.uploadPhoto(URL + obj.getString("preview"));
|
||||||
|
if (photo == null) {
|
||||||
|
send(userName + ", не смогла :(");
|
||||||
|
} else {
|
||||||
|
send(userName, photo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/holdfast/samobot/commands/Obutts.java
Normal file
37
src/holdfast/samobot/commands/Obutts.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class Obutts extends Command {
|
||||||
|
|
||||||
|
private static final String API_URL = "http://api.obutts.ru/noise";
|
||||||
|
private static final String URL = "http://media.obutts.ru/";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "butts", "попа" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
String raw = IOUtil.get(API_URL);
|
||||||
|
JSONObject obj = new JSONArray(raw).getJSONObject(0);
|
||||||
|
|
||||||
|
String photo = VK.uploadPhoto(URL + obj.getString("preview"));
|
||||||
|
if (photo == null) {
|
||||||
|
send(userName + ", не смогла :(");
|
||||||
|
} else {
|
||||||
|
send(userName, photo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/holdfast/samobot/commands/PhotoSearch.java
Normal file
41
src/holdfast/samobot/commands/PhotoSearch.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class PhotoSearch extends Command {
|
||||||
|
|
||||||
|
private static final Map<String, String> SEARCH_KEYWORDS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
SEARCH_KEYWORDS = new HashMap<>();
|
||||||
|
SEARCH_KEYWORDS.put("пони", "MLP art");
|
||||||
|
SEARCH_KEYWORDS.put("неко", "неко кошкодевочки");
|
||||||
|
SEARCH_KEYWORDS.put("пеппа", "peppa pig");
|
||||||
|
SEARCH_KEYWORDS.put("аниме", "anime");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "пони", "неко", "пеппа", "аниме" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
System.out.println("Photo: " + message);
|
||||||
|
String photo = VK.getRandomPhoto(SEARCH_KEYWORDS.get(message), 1, Util.random(2900));
|
||||||
|
if (photo == null) {
|
||||||
|
send(userName + ", ничего не найдено :(");
|
||||||
|
} else {
|
||||||
|
send(userName, photo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
34
src/holdfast/samobot/commands/Pirozhki.java
Normal file
34
src/holdfast/samobot/commands/Pirozhki.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.IOUtil;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class Pirozhki extends Command {
|
||||||
|
|
||||||
|
private static final String URL = "http://perashki.ru/Piro/Random/";
|
||||||
|
private static final String TAG_BEGIN = "<div class=\"Text\">";
|
||||||
|
private static final String TAG_END = "</div>";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "пирожки" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
String rawHtml = IOUtil.get(URL);
|
||||||
|
|
||||||
|
int startIndex = rawHtml.indexOf(TAG_BEGIN) + TAG_BEGIN.length();
|
||||||
|
int endIndex = rawHtml.indexOf(TAG_END, startIndex);
|
||||||
|
if (endIndex <= startIndex || endIndex <= 0) return false;
|
||||||
|
|
||||||
|
String text = rawHtml.substring(startIndex, endIndex);
|
||||||
|
send(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
src/holdfast/samobot/commands/Possibility.java
Normal file
28
src/holdfast/samobot/commands/Possibility.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Possibility extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "инфа" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
message = message.substring(words[0].length());
|
||||||
|
|
||||||
|
int salt = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) +
|
||||||
|
Calendar.getInstance().get(Calendar.HOUR);
|
||||||
|
int percentage = (message.toLowerCase() + salt).hashCode() % 100;
|
||||||
|
|
||||||
|
send(userName + ", инфа " + Math.abs(percentage) + "%");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
72
src/holdfast/samobot/commands/SendMessage.java
Normal file
72
src/holdfast/samobot/commands/SendMessage.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class SendMessage extends Command {
|
||||||
|
|
||||||
|
private static final int ADMIN_ID = 18800138;
|
||||||
|
private static final Map<String, Integer> namesId;
|
||||||
|
|
||||||
|
static {
|
||||||
|
namesId = new HashMap<>();
|
||||||
|
namesId.put("эд", 152102072);
|
||||||
|
namesId.put("эдуард", 152102072);
|
||||||
|
namesId.put("слава", 312584128);
|
||||||
|
namesId.put("славка", 312584128);
|
||||||
|
namesId.put("анна", 203160951);
|
||||||
|
namesId.put("азат", 203160951);
|
||||||
|
namesId.put("кальтер", 203160951);
|
||||||
|
namesId.put("федя", 139948561);
|
||||||
|
namesId.put("витя", 18800138);
|
||||||
|
namesId.put("виктор", 18800138);
|
||||||
|
namesId.put("сергей", 296528453);
|
||||||
|
namesId.put("листок", 296528453);
|
||||||
|
namesId.put("листочек", 296528453);
|
||||||
|
namesId.put("виталя", 186862489);
|
||||||
|
namesId.put("игорь", 28420405);
|
||||||
|
namesId.put("ксакеп", 28420405);
|
||||||
|
namesId.put("кса", 28420405);
|
||||||
|
namesId.put("конфа", 1);
|
||||||
|
namesId.put("ботоконфа", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "отправь" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
// if (toUser && chatId != 18800138) return false;
|
||||||
|
|
||||||
|
message = message.substring(words[0].length()); // cut command
|
||||||
|
final String lastWord = words[words.length - 1].trim();
|
||||||
|
message = message.substring(0, message.length() - lastWord.length() - 1); // cut id
|
||||||
|
|
||||||
|
int id;
|
||||||
|
try {
|
||||||
|
id = Integer.parseInt(lastWord);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (!namesId.containsKey(lastWord.toLowerCase())) return false;
|
||||||
|
id = namesId.get(lastWord.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Разрешаем отправлять только заданным в namesId аккаунтам
|
||||||
|
// Исключение - админ
|
||||||
|
if ( (chatId != ADMIN_ID) && !namesId.containsValue(id)) return false;
|
||||||
|
|
||||||
|
toUser = (id > 10000);
|
||||||
|
chatId = id;
|
||||||
|
forward = 0;
|
||||||
|
|
||||||
|
send(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
src/holdfast/samobot/commands/Stats.java
Normal file
23
src/holdfast/samobot/commands/Stats.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.StatisticsProcessor;
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class Stats extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "стата", "статистика" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
send(StatisticsProcessor.asString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
32
src/holdfast/samobot/commands/VkAudioSearch.java
Normal file
32
src/holdfast/samobot/commands/VkAudioSearch.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class VkAudioSearch extends Command {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "аудио", "музыка", "песню" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
final String query = message.substring(words[0].length());
|
||||||
|
|
||||||
|
String audio = VK.getRandomAudio(query, 10);
|
||||||
|
if (audio == null) {
|
||||||
|
send(userName + ", ничего не найдено :(");
|
||||||
|
} else {
|
||||||
|
send(userName, audio);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/holdfast/samobot/commands/VkPhotoSearch.java
Normal file
31
src/holdfast/samobot/commands/VkPhotoSearch.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class VkPhotoSearch extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "вкфото" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
final String query = message.substring(words[0].length());
|
||||||
|
|
||||||
|
String photo = VK.getRandomPhoto(query, 1, Util.random(100));
|
||||||
|
if (photo == null) {
|
||||||
|
send(userName + ", ничего не найдено :(");
|
||||||
|
} else {
|
||||||
|
send(userName, photo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/holdfast/samobot/commands/VkVideoSearch.java
Normal file
31
src/holdfast/samobot/commands/VkVideoSearch.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.VK;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class VkVideoSearch extends Command {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "видео", "видос" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String message, String userName) throws IOException {
|
||||||
|
final String query = message.substring(words[0].length());
|
||||||
|
|
||||||
|
String video = VK.getRandomVideo(query, 10);
|
||||||
|
if (video == null) {
|
||||||
|
send(userName + ", ничего не найдено :(");
|
||||||
|
} else {
|
||||||
|
send(userName, video);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/holdfast/samobot/commands/When.java
Normal file
55
src/holdfast/samobot/commands/When.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package holdfast.samobot.commands;
|
||||||
|
|
||||||
|
import holdfast.samobot.Util;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class When extends Command {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] command() {
|
||||||
|
return new String[] { "когда" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(String message, String userName) throws IOException {
|
||||||
|
message = message.substring(words[0].length());
|
||||||
|
if (!message.trim().endsWith("?")) return false;
|
||||||
|
|
||||||
|
int salt = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) +
|
||||||
|
Calendar.getInstance().get(Calendar.HOUR);
|
||||||
|
int seed = (message.toLowerCase() + salt).hashCode();
|
||||||
|
|
||||||
|
send(userName + ", " + getDateMessage(seed));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDateMessage(int seed) {
|
||||||
|
final Random random = new Random(seed);
|
||||||
|
switch (random.nextInt(5)) {
|
||||||
|
case 0:
|
||||||
|
LocalDate date = LocalDate.now();
|
||||||
|
date = date.minusDays(random.nextInt(2000));
|
||||||
|
return String.format("Это событие уже было %s года.", Util.dateToString(date));
|
||||||
|
case 1:
|
||||||
|
return "Через " + (4+random.nextInt(15)) + " часов.";
|
||||||
|
case 2:
|
||||||
|
return "Через " + (1+random.nextInt(40)) + " дней.";
|
||||||
|
case 3:
|
||||||
|
return "Через " + (1+random.nextInt(12)) + " месяцев.";
|
||||||
|
case 4:
|
||||||
|
date = LocalDate.now();
|
||||||
|
date = date.plusDays(random.nextInt(2000));
|
||||||
|
return String.format("Это событие произойдет %s года.", Util.dateToString(date));
|
||||||
|
default:
|
||||||
|
return "Этого никогда не будет.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1061
src/org/json/JSONArray.java
Normal file
1061
src/org/json/JSONArray.java
Normal file
File diff suppressed because it is too large
Load Diff
43
src/org/json/JSONException.java
Normal file
43
src/org/json/JSONException.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package org.json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||||
|
*
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2014-05-03
|
||||||
|
*/
|
||||||
|
public class JSONException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 0;
|
||||||
|
private Throwable cause;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a JSONException with an explanatory message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* Detail about the reason for the exception.
|
||||||
|
*/
|
||||||
|
public JSONException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new JSONException with the specified cause.
|
||||||
|
* @param cause The cause.
|
||||||
|
*/
|
||||||
|
public JSONException(Throwable cause) {
|
||||||
|
super(cause.getMessage());
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cause of this exception or null if the cause is nonexistent
|
||||||
|
* or unknown.
|
||||||
|
*
|
||||||
|
* @return the cause of this exception or null if the cause is nonexistent
|
||||||
|
* or unknown.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Throwable getCause() {
|
||||||
|
return this.cause;
|
||||||
|
}
|
||||||
|
}
|
1779
src/org/json/JSONObject.java
Normal file
1779
src/org/json/JSONObject.java
Normal file
File diff suppressed because it is too large
Load Diff
18
src/org/json/JSONString.java
Normal file
18
src/org/json/JSONString.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package org.json;
|
||||||
|
/**
|
||||||
|
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||||
|
* method so that a class can change the behavior of
|
||||||
|
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||||
|
* and <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||||
|
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||||
|
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||||
|
*/
|
||||||
|
public interface JSONString {
|
||||||
|
/**
|
||||||
|
* The <code>toJSONString</code> method allows a class to produce its own JSON
|
||||||
|
* serialization.
|
||||||
|
*
|
||||||
|
* @return A strictly syntactically correct JSON text.
|
||||||
|
*/
|
||||||
|
public String toJSONString();
|
||||||
|
}
|
78
src/org/json/JSONStringer.java
Normal file
78
src/org/json/JSONStringer.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package org.json;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2006 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONStringer provides a quick and convenient way of producing JSON text.
|
||||||
|
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||||
|
* added, so the results are ready for transmission or storage. Each instance of
|
||||||
|
* JSONStringer can produce one JSON text.
|
||||||
|
* <p>
|
||||||
|
* A JSONStringer instance provides a <code>value</code> method for appending
|
||||||
|
* values to the
|
||||||
|
* text, and a <code>key</code>
|
||||||
|
* method for adding keys before values in objects. There are <code>array</code>
|
||||||
|
* and <code>endArray</code> methods that make and bound array values, and
|
||||||
|
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||||
|
* object values. All of these methods return the JSONWriter instance,
|
||||||
|
* permitting cascade style. For example, <pre>
|
||||||
|
* myString = new JSONStringer()
|
||||||
|
* .object()
|
||||||
|
* .key("JSON")
|
||||||
|
* .value("Hello, World!")
|
||||||
|
* .endObject()
|
||||||
|
* .toString();</pre> which produces the string <pre>
|
||||||
|
* {"JSON":"Hello, World!"}</pre>
|
||||||
|
* <p>
|
||||||
|
* The first method called must be <code>array</code> or <code>object</code>.
|
||||||
|
* There are no methods for adding commas or colons. JSONStringer adds them for
|
||||||
|
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||||
|
* <p>
|
||||||
|
* This can sometimes be easier than using a JSONObject to build a string.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2008-09-18
|
||||||
|
*/
|
||||||
|
public class JSONStringer extends JSONWriter {
|
||||||
|
/**
|
||||||
|
* Make a fresh JSONStringer. It can be used to build one JSON text.
|
||||||
|
*/
|
||||||
|
public JSONStringer() {
|
||||||
|
super(new StringWriter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the JSON text. This method is used to obtain the product of the
|
||||||
|
* JSONStringer instance. It will return <code>null</code> if there was a
|
||||||
|
* problem in the construction of the JSON text (such as the calls to
|
||||||
|
* <code>array</code> were not properly balanced with calls to
|
||||||
|
* <code>endArray</code>).
|
||||||
|
* @return The JSON text.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return this.mode == 'd' ? this.writer.toString() : null;
|
||||||
|
}
|
||||||
|
}
|
446
src/org/json/JSONTokener.java
Normal file
446
src/org/json/JSONTokener.java
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
package org.json;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2002 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||||
|
* it. It is used by the JSONObject and JSONArray constructors to parse
|
||||||
|
* JSON source strings.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2014-05-03
|
||||||
|
*/
|
||||||
|
public class JSONTokener {
|
||||||
|
|
||||||
|
private long character;
|
||||||
|
private boolean eof;
|
||||||
|
private long index;
|
||||||
|
private long line;
|
||||||
|
private char previous;
|
||||||
|
private Reader reader;
|
||||||
|
private boolean usePrevious;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from a Reader.
|
||||||
|
*
|
||||||
|
* @param reader A reader.
|
||||||
|
*/
|
||||||
|
public JSONTokener(Reader reader) {
|
||||||
|
this.reader = reader.markSupported()
|
||||||
|
? reader
|
||||||
|
: new BufferedReader(reader);
|
||||||
|
this.eof = false;
|
||||||
|
this.usePrevious = false;
|
||||||
|
this.previous = 0;
|
||||||
|
this.index = 0;
|
||||||
|
this.character = 1;
|
||||||
|
this.line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from an InputStream.
|
||||||
|
* @param inputStream The source.
|
||||||
|
*/
|
||||||
|
public JSONTokener(InputStream inputStream) throws JSONException {
|
||||||
|
this(new InputStreamReader(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a JSONTokener from a string.
|
||||||
|
*
|
||||||
|
* @param s A source string.
|
||||||
|
*/
|
||||||
|
public JSONTokener(String s) {
|
||||||
|
this(new StringReader(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Back up one character. This provides a sort of lookahead capability,
|
||||||
|
* so that you can test for a digit or letter before attempting to parse
|
||||||
|
* the next number or identifier.
|
||||||
|
*/
|
||||||
|
public void back() throws JSONException {
|
||||||
|
if (this.usePrevious || this.index <= 0) {
|
||||||
|
throw new JSONException("Stepping back two steps is not supported");
|
||||||
|
}
|
||||||
|
this.index -= 1;
|
||||||
|
this.character -= 1;
|
||||||
|
this.usePrevious = true;
|
||||||
|
this.eof = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hex value of a character (base16).
|
||||||
|
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||||
|
* between 'a' and 'f'.
|
||||||
|
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||||
|
*/
|
||||||
|
public static int dehexchar(char c) {
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
if (c >= 'A' && c <= 'F') {
|
||||||
|
return c - ('A' - 10);
|
||||||
|
}
|
||||||
|
if (c >= 'a' && c <= 'f') {
|
||||||
|
return c - ('a' - 10);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean end() {
|
||||||
|
return this.eof && !this.usePrevious;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the source string still contains characters that next()
|
||||||
|
* can consume.
|
||||||
|
* @return true if not yet at the end of the source.
|
||||||
|
*/
|
||||||
|
public boolean more() throws JSONException {
|
||||||
|
this.next();
|
||||||
|
if (this.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next character in the source string.
|
||||||
|
*
|
||||||
|
* @return The next character, or 0 if past the end of the source string.
|
||||||
|
*/
|
||||||
|
public char next() throws JSONException {
|
||||||
|
int c;
|
||||||
|
if (this.usePrevious) {
|
||||||
|
this.usePrevious = false;
|
||||||
|
c = this.previous;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
c = this.reader.read();
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new JSONException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c <= 0) { // End of stream
|
||||||
|
this.eof = true;
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.index += 1;
|
||||||
|
if (this.previous == '\r') {
|
||||||
|
this.line += 1;
|
||||||
|
this.character = c == '\n' ? 0 : 1;
|
||||||
|
} else if (c == '\n') {
|
||||||
|
this.line += 1;
|
||||||
|
this.character = 0;
|
||||||
|
} else {
|
||||||
|
this.character += 1;
|
||||||
|
}
|
||||||
|
this.previous = (char) c;
|
||||||
|
return this.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume the next character, and check that it matches a specified
|
||||||
|
* character.
|
||||||
|
* @param c The character to match.
|
||||||
|
* @return The character.
|
||||||
|
* @throws JSONException if the character does not match.
|
||||||
|
*/
|
||||||
|
public char next(char c) throws JSONException {
|
||||||
|
char n = this.next();
|
||||||
|
if (n != c) {
|
||||||
|
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
|
||||||
|
n + "'");
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next n characters.
|
||||||
|
*
|
||||||
|
* @param n The number of characters to take.
|
||||||
|
* @return A string of n characters.
|
||||||
|
* @throws JSONException
|
||||||
|
* Substring bounds error if there are not
|
||||||
|
* n characters remaining in the source string.
|
||||||
|
*/
|
||||||
|
public String next(int n) throws JSONException {
|
||||||
|
if (n == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] chars = new char[n];
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < n) {
|
||||||
|
chars[pos] = this.next();
|
||||||
|
if (this.end()) {
|
||||||
|
throw this.syntaxError("Substring bounds error");
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next char in the string, skipping whitespace.
|
||||||
|
* @throws JSONException
|
||||||
|
* @return A character, or 0 if there are no more characters.
|
||||||
|
*/
|
||||||
|
public char nextClean() throws JSONException {
|
||||||
|
for (;;) {
|
||||||
|
char c = this.next();
|
||||||
|
if (c == 0 || c > ' ') {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the characters up to the next close quote character.
|
||||||
|
* Backslash processing is done. The formal JSON format does not
|
||||||
|
* allow strings in single quotes, but an implementation is allowed to
|
||||||
|
* accept them.
|
||||||
|
* @param quote The quoting character, either
|
||||||
|
* <code>"</code> <small>(double quote)</small> or
|
||||||
|
* <code>'</code> <small>(single quote)</small>.
|
||||||
|
* @return A String.
|
||||||
|
* @throws JSONException Unterminated string.
|
||||||
|
*/
|
||||||
|
public String nextString(char quote) throws JSONException {
|
||||||
|
char c;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
c = this.next();
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
throw this.syntaxError("Unterminated string");
|
||||||
|
case '\\':
|
||||||
|
c = this.next();
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
sb.append('\b');
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
sb.append('\t');
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
sb.append('\n');
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
sb.append('\f');
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
sb.append('\r');
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
sb.append(c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw this.syntaxError("Illegal escape.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c == quote) {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text up but not including the specified character or the
|
||||||
|
* end of line, whichever comes first.
|
||||||
|
* @param delimiter A delimiter character.
|
||||||
|
* @return A string.
|
||||||
|
*/
|
||||||
|
public String nextTo(char delimiter) throws JSONException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
char c = this.next();
|
||||||
|
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||||
|
if (c != 0) {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text up but not including one of the specified delimiter
|
||||||
|
* characters or the end of line, whichever comes first.
|
||||||
|
* @param delimiters A set of delimiter characters.
|
||||||
|
* @return A string, trimmed.
|
||||||
|
*/
|
||||||
|
public String nextTo(String delimiters) throws JSONException {
|
||||||
|
char c;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (;;) {
|
||||||
|
c = this.next();
|
||||||
|
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
||||||
|
c == '\n' || c == '\r') {
|
||||||
|
if (c != 0) {
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||||
|
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||||
|
* @throws JSONException If syntax error.
|
||||||
|
*
|
||||||
|
* @return An object.
|
||||||
|
*/
|
||||||
|
public Object nextValue() throws JSONException {
|
||||||
|
char c = this.nextClean();
|
||||||
|
String string;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
return this.nextString(c);
|
||||||
|
case '{':
|
||||||
|
this.back();
|
||||||
|
return new JSONObject(this);
|
||||||
|
case '[':
|
||||||
|
this.back();
|
||||||
|
return new JSONArray(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle unquoted text. This could be the values true, false, or
|
||||||
|
* null, or it can be a number. An implementation (such as this one)
|
||||||
|
* is allowed to also accept non-standard forms.
|
||||||
|
*
|
||||||
|
* Accumulate characters until we reach the end of the text or a
|
||||||
|
* formatting character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||||
|
sb.append(c);
|
||||||
|
c = this.next();
|
||||||
|
}
|
||||||
|
this.back();
|
||||||
|
|
||||||
|
string = sb.toString().trim();
|
||||||
|
if ("".equals(string)) {
|
||||||
|
throw this.syntaxError("Missing value");
|
||||||
|
}
|
||||||
|
return JSONObject.stringToValue(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip characters until the next character is the requested character.
|
||||||
|
* If the requested character is not found, no characters are skipped.
|
||||||
|
* @param to A character to skip to.
|
||||||
|
* @return The requested character, or zero if the requested character
|
||||||
|
* is not found.
|
||||||
|
*/
|
||||||
|
public char skipTo(char to) throws JSONException {
|
||||||
|
char c;
|
||||||
|
try {
|
||||||
|
long startIndex = this.index;
|
||||||
|
long startCharacter = this.character;
|
||||||
|
long startLine = this.line;
|
||||||
|
this.reader.mark(1000000);
|
||||||
|
do {
|
||||||
|
c = this.next();
|
||||||
|
if (c == 0) {
|
||||||
|
this.reader.reset();
|
||||||
|
this.index = startIndex;
|
||||||
|
this.character = startCharacter;
|
||||||
|
this.line = startLine;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
} while (c != to);
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new JSONException(exception);
|
||||||
|
}
|
||||||
|
this.back();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a JSONException to signal a syntax error.
|
||||||
|
*
|
||||||
|
* @param message The error message.
|
||||||
|
* @return A JSONException object, suitable for throwing
|
||||||
|
*/
|
||||||
|
public JSONException syntaxError(String message) {
|
||||||
|
return new JSONException(message + this.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a printable string of this JSONTokener.
|
||||||
|
*
|
||||||
|
* @return " at {index} [character {character} line {line}]"
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return " at " + this.index + " [character " + this.character + " line " +
|
||||||
|
this.line + "]";
|
||||||
|
}
|
||||||
|
}
|
327
src/org/json/JSONWriter.java
Normal file
327
src/org/json/JSONWriter.java
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
package org.json;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2006 JSON.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
The Software shall be used for Good, not Evil.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONWriter provides a quick and convenient way of producing JSON text.
|
||||||
|
* The texts produced strictly conform to JSON syntax rules. No whitespace is
|
||||||
|
* added, so the results are ready for transmission or storage. Each instance of
|
||||||
|
* JSONWriter can produce one JSON text.
|
||||||
|
* <p>
|
||||||
|
* A JSONWriter instance provides a <code>value</code> method for appending
|
||||||
|
* values to the
|
||||||
|
* text, and a <code>key</code>
|
||||||
|
* method for adding keys before values in objects. There are <code>array</code>
|
||||||
|
* and <code>endArray</code> methods that make and bound array values, and
|
||||||
|
* <code>object</code> and <code>endObject</code> methods which make and bound
|
||||||
|
* object values. All of these methods return the JSONWriter instance,
|
||||||
|
* permitting a cascade style. For example, <pre>
|
||||||
|
* new JSONWriter(myWriter)
|
||||||
|
* .object()
|
||||||
|
* .key("JSON")
|
||||||
|
* .value("Hello, World!")
|
||||||
|
* .endObject();</pre> which writes <pre>
|
||||||
|
* {"JSON":"Hello, World!"}</pre>
|
||||||
|
* <p>
|
||||||
|
* The first method called must be <code>array</code> or <code>object</code>.
|
||||||
|
* There are no methods for adding commas or colons. JSONWriter adds them for
|
||||||
|
* you. Objects and arrays can be nested up to 20 levels deep.
|
||||||
|
* <p>
|
||||||
|
* This can sometimes be easier than using a JSONObject to build a string.
|
||||||
|
* @author JSON.org
|
||||||
|
* @version 2011-11-24
|
||||||
|
*/
|
||||||
|
public class JSONWriter {
|
||||||
|
private static final int maxdepth = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The comma flag determines if a comma should be output before the next
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
private boolean comma;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current mode. Values:
|
||||||
|
* 'a' (array),
|
||||||
|
* 'd' (done),
|
||||||
|
* 'i' (initial),
|
||||||
|
* 'k' (key),
|
||||||
|
* 'o' (object).
|
||||||
|
*/
|
||||||
|
protected char mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object/array stack.
|
||||||
|
*/
|
||||||
|
private final JSONObject stack[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stack top index. A value of 0 indicates that the stack is empty.
|
||||||
|
*/
|
||||||
|
private int top;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The writer that will receive the output.
|
||||||
|
*/
|
||||||
|
protected Writer writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
||||||
|
*/
|
||||||
|
public JSONWriter(Writer w) {
|
||||||
|
this.comma = false;
|
||||||
|
this.mode = 'i';
|
||||||
|
this.stack = new JSONObject[maxdepth];
|
||||||
|
this.top = 0;
|
||||||
|
this.writer = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a value.
|
||||||
|
* @param string A string value.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the value is out of sequence.
|
||||||
|
*/
|
||||||
|
private JSONWriter append(String string) throws JSONException {
|
||||||
|
if (string == null) {
|
||||||
|
throw new JSONException("Null pointer");
|
||||||
|
}
|
||||||
|
if (this.mode == 'o' || this.mode == 'a') {
|
||||||
|
try {
|
||||||
|
if (this.comma && this.mode == 'a') {
|
||||||
|
this.writer.write(',');
|
||||||
|
}
|
||||||
|
this.writer.write(string);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
if (this.mode == 'o') {
|
||||||
|
this.mode = 'k';
|
||||||
|
}
|
||||||
|
this.comma = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Value out of sequence.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin appending a new array. All values until the balancing
|
||||||
|
* <code>endArray</code> will be appended to this array. The
|
||||||
|
* <code>endArray</code> method must be called to mark the array's end.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the nesting is too deep, or if the object is
|
||||||
|
* started in the wrong place (for example as a key or after the end of the
|
||||||
|
* outermost array or object).
|
||||||
|
*/
|
||||||
|
public JSONWriter array() throws JSONException {
|
||||||
|
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||||
|
this.push(null);
|
||||||
|
this.append("[");
|
||||||
|
this.comma = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End something.
|
||||||
|
* @param mode Mode
|
||||||
|
* @param c Closing character
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If unbalanced.
|
||||||
|
*/
|
||||||
|
private JSONWriter end(char mode, char c) throws JSONException {
|
||||||
|
if (this.mode != mode) {
|
||||||
|
throw new JSONException(mode == 'a'
|
||||||
|
? "Misplaced endArray."
|
||||||
|
: "Misplaced endObject.");
|
||||||
|
}
|
||||||
|
this.pop(mode);
|
||||||
|
try {
|
||||||
|
this.writer.write(c);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
this.comma = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End an array. This method most be called to balance calls to
|
||||||
|
* <code>array</code>.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If incorrectly nested.
|
||||||
|
*/
|
||||||
|
public JSONWriter endArray() throws JSONException {
|
||||||
|
return this.end('a', ']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End an object. This method most be called to balance calls to
|
||||||
|
* <code>object</code>.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If incorrectly nested.
|
||||||
|
*/
|
||||||
|
public JSONWriter endObject() throws JSONException {
|
||||||
|
return this.end('k', '}');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a key. The key will be associated with the next value. In an
|
||||||
|
* object, every value must be preceded by a key.
|
||||||
|
* @param string A key string.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the key is out of place. For example, keys
|
||||||
|
* do not belong in arrays or if the key is null.
|
||||||
|
*/
|
||||||
|
public JSONWriter key(String string) throws JSONException {
|
||||||
|
if (string == null) {
|
||||||
|
throw new JSONException("Null key.");
|
||||||
|
}
|
||||||
|
if (this.mode == 'k') {
|
||||||
|
try {
|
||||||
|
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
|
||||||
|
if (this.comma) {
|
||||||
|
this.writer.write(',');
|
||||||
|
}
|
||||||
|
this.writer.write(JSONObject.quote(string));
|
||||||
|
this.writer.write(':');
|
||||||
|
this.comma = false;
|
||||||
|
this.mode = 'o';
|
||||||
|
return this;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JSONException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin appending a new object. All keys and values until the balancing
|
||||||
|
* <code>endObject</code> will be appended to this object. The
|
||||||
|
* <code>endObject</code> method must be called to mark the object's end.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the nesting is too deep, or if the object is
|
||||||
|
* started in the wrong place (for example as a key or after the end of the
|
||||||
|
* outermost array or object).
|
||||||
|
*/
|
||||||
|
public JSONWriter object() throws JSONException {
|
||||||
|
if (this.mode == 'i') {
|
||||||
|
this.mode = 'o';
|
||||||
|
}
|
||||||
|
if (this.mode == 'o' || this.mode == 'a') {
|
||||||
|
this.append("{");
|
||||||
|
this.push(new JSONObject());
|
||||||
|
this.comma = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new JSONException("Misplaced object.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop an array or object scope.
|
||||||
|
* @param c The scope to close.
|
||||||
|
* @throws JSONException If nesting is wrong.
|
||||||
|
*/
|
||||||
|
private void pop(char c) throws JSONException {
|
||||||
|
if (this.top <= 0) {
|
||||||
|
throw new JSONException("Nesting error.");
|
||||||
|
}
|
||||||
|
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||||
|
if (m != c) {
|
||||||
|
throw new JSONException("Nesting error.");
|
||||||
|
}
|
||||||
|
this.top -= 1;
|
||||||
|
this.mode = this.top == 0
|
||||||
|
? 'd'
|
||||||
|
: this.stack[this.top - 1] == null
|
||||||
|
? 'a'
|
||||||
|
: 'k';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an array or object scope.
|
||||||
|
* @param jo The scope to open.
|
||||||
|
* @throws JSONException If nesting is too deep.
|
||||||
|
*/
|
||||||
|
private void push(JSONObject jo) throws JSONException {
|
||||||
|
if (this.top >= maxdepth) {
|
||||||
|
throw new JSONException("Nesting too deep.");
|
||||||
|
}
|
||||||
|
this.stack[this.top] = jo;
|
||||||
|
this.mode = jo == null ? 'a' : 'k';
|
||||||
|
this.top += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append either the value <code>true</code> or the value
|
||||||
|
* <code>false</code>.
|
||||||
|
* @param b A boolean.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
|
public JSONWriter value(boolean b) throws JSONException {
|
||||||
|
return this.append(b ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a double value.
|
||||||
|
* @param d A double.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the number is not finite.
|
||||||
|
*/
|
||||||
|
public JSONWriter value(double d) throws JSONException {
|
||||||
|
return this.value(new Double(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a long value.
|
||||||
|
* @param l A long.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
|
public JSONWriter value(long l) throws JSONException {
|
||||||
|
return this.append(Long.toString(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append an object value.
|
||||||
|
* @param object The object to append. It can be null, or a Boolean, Number,
|
||||||
|
* String, JSONObject, or JSONArray, or an object that implements JSONString.
|
||||||
|
* @return this
|
||||||
|
* @throws JSONException If the value is out of sequence.
|
||||||
|
*/
|
||||||
|
public JSONWriter value(Object object) throws JSONException {
|
||||||
|
return this.append(JSONObject.valueToString(object));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user