Initial commit

This commit is contained in:
Victor 2015-08-22 21:25:26 +03:00
commit 27e2312eed
41 changed files with 6988 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/build/
/dist/
/nbproject/private/

73
build.xml Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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
View 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
View 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)
- стата / статистика: выводит статистику о работе бота
- когда: определяет дату того или иного события (когда я пойду спать?)

View 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 = "";//"[Вадос] "; // префикс перед выводом сообщения бота
}

View 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();
});
}
}

View 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 "";
}
}
}

View 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);
}
}
}

View 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;
}
}
}
}

View 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();
}
}

View 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());
}
}

View 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";
}
}

View 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;
}
}
}

View 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;
}
}

View 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);
}
}

View 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);
}
}
}

View 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("&nbsp;", "").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("&nbsp;", "").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;
}
}

View 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;
}
}

View 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;
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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();
}

View 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;
}
}

View 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>&nbsp;<small>(double quote)</small> or
* <code>'</code>&nbsp;<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 + "]";
}
}

View 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));
}
}