Выложенный вчера скрипт принес некоторое количество вопросов в комментариях, в том числе по части устройства и работы бота. Как и обещал - выкладываю подробнейшее описание каждой функции, надеюсь это поможет вам в реализации собственных идей
Демо: https://golos.rubtc.info/bot.html
Из инструментов нужен только браузер и текстовый редактор с поддержкой html и js
Создайте у себя папку с произвольным именем, далее создайте в ней два файла:
bot.html
и golos.js
например используя notepad++ или другой текстовый редактор откройте оба файла.
В файл bot.html
вам необходимо вставить html со страницы
http://pastebin.com/raw/VgimfAwC
А в файл golos.js
вставьте код со страницы
https://raw.githubusercontent.com/ontofractal/golosjs/master/dist/golos.min.js
Теперь можете открыть страницу bot.html у себя в браузере и используя форму задать скрипту условия алгоритма действий, он будет работать. Понять как именно все работает я помогу ниже.
Шаблон страницы
В основе у нас минимальная html5 разметка, мы не будем уделять ей много времени, об этом в сети очень много информации, это одна из основ web.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>BotBro</title>
<style></style>
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script src="golos.js"></script>
</head>
<body>
<script></script>
</body>
</html>
meta name="viewport"
не обязательный параметр, он нужен для удобного отображения страницы на маленьких дисплеях, телефон, планшет и т.д.
<script src="golos.js"></script>
- Это у нас подключенный javascript помогающий подключаться к блокчейну голоса. Скрипт в редакции @ontofractal
<style></style>
Между этих тегов мы вставим наш CSS стиль (Опишем цвета, размеры, анимации и т.д.)
После тега <body>
мы добавим форму на 5 опций:
<form>
<input id="account" type="text" name="account" placeholder="Логин">
<input id="k" type="password" name="password" placeholder="Постинг ключ">
<input id="username" type="text" name="username" placeholder="Куратор - цель">
<input id="minutes" type="number" name="text" placeholder="Прошло минут">
<input id="votepower" type="number" name="text" placeholder="Сила от ...%">
</form>
- Ваш логин - ID поля формы
account
- Ваш постинг ключ - ID
k
- Логин цели, за которой повторить голоса - ID
username
- Количество прошедших минут, которые нужно учесть - ID
minutes
- Минимальная сила голоса с которой следует повторять - ID
votepower
В форме не хватает кнопки отправки, разместим ее ниже под формой
<button onclick="broBot()" class="signin">Запуск голосования</button>
И добавим еще один блок в котором будет отражаться ход голосования
<div id="nicedata"> </div>
JavaScript
Перед нижним </body>
мы разместим между тегами <script> </script>
наш скрипт, который будет выполнять всю работу.
И начнем мы с указаний переменных и написания основной функции
Обратите внимание на форму, которая описана ранее, каждое из полей ввода имеет свое ID, а кнопка
button onclick="broBot()"
вызывает функцию broBot
при клике.
Таким образом, весь код внутри функции broBot()
будет выполнен только при нажатии кнопки.
За пределами функции у нас объявлена только одна глобальная переменная:
var votepower = 0;
- это значит, что если вы оставите поле с id votepower пустым, то минимальная сила голоса будет начинаться от нуля. И бот будет повторять все голоса куратора не меньше 0.
Если вы зададите в поле формы 50 (например), то бот будет игнорировать голоса менее 50% силы, а повторять только голоса, в которых куратор указал силу от 50%.
После объявления этой переменной, создадим основную функцию
function broBot() {
// Тут будет остальной код
}
И уже внутри функции продолжаем задавать переменные для 5-ти полей формы
var account = document.getElementById("account").value,
k = document.getElementById("k").value,
username = document.getElementById("username").value,
minutes = document.getElementById("minutes").value,
votepower = document.getElementById("votepower").value;
В каждую из переменных попадает значение с поля формы благодаря функции
document.getElementById("ID-элемента").value
Так как изначально форма не заполнена, а переменные находятся внутри функции broBot()
- заполнение произойдет после нажатия кнопки.
Далее у нас будет еще одна функция внутри broBot()
, назовем ее followVote()
, но перед этим объявим еще несколько глобальных переменных для того, что бы могли в будущем влиять на их содержимое изнутри других функций
var time,
starttime,
utime,
start,
t = 1000, // Просто сокращение.
period = minutes * 60; // Переводим указанные в поле минуты в формат unix time
Начинаем писать после followVote(){
var count = true; // переменная - выключатель.
steem.api.getDynamicGlobalProperties(function(err, result) {
starttime = Date.parse(result.time) / t;
});
Тут произошло наше первое обращение к БЧ голоса, мы получили глобальные текущие данные, которые записали в ответ result
.
Из всего этого нам нужно знать только текущее время указанное в БЧ и записать его в переменную starttime
.
Выбираем time из объекта так: result.time
, что даст нам такой формат "2017-02-17T18:37:24". Такой формат удобно читать человеку, но не удобно оперировать как математической единицей, мы переведем его unix time (общепринятый формат времени, который исчисляется как количество секунд прошедших с начала эпохи юникс - 1970 год)
Date.parse(result.time) / t;
- если помните, t у нас равняется 1000, т.е. unix time мы получили поделив результат функции Date.parse на 1000, что дало нам 1487356644 секунд. Именно в таком формате мы будем записывать стартовое время нажатия кнопки запуска бота.
Это время будет храниться в переменной starttime
и обновляться на текущее с каждым нажатием кнопки запуска.
Сканируем ВСЕ голоса куратора-цели
Было бы логичней сканировать не все, а только часть голосов с лимитом по дате или количеству, но в нынешнем api объекты внутри массива отсортированы странным образом, потому мы будем загружать всю историю голосования куратора, а уже дальше сортировать его голоса по "давности".
Сперва мы делаем запрос в БЧ голоса
steem.api.getAccountVotes(username, function(err, result) {
username
- это переменная, в которой хранится имя куратора, которое мы задали в поле формы с одноименным id.
Делаем заготовку для массива, в который мы вставим полученные объекты
var a = [];
Обращение к api с запросом getAccountVotes выдаст нам массив объектов с данными о исходящих голосах username
Каждый голос пронумерован, однако, нумерация идет странным порядком, в который стоило бы вникнуть, но было лень) Суть в том, что последний голос не имеет последний порядковый номер или ближайшую дату. Они как-то вперемешку... Но нам точно известно их количество благодаря length (видно на скрине). Это число можно получить обратившись к result.length
внутри getAccountVotes
Мы сделаем вот такую петлю:
for (var i = 0; i < result.length; i++) {
// Здесь мы будем формировать список всех исходящих голосов
}
В этой петле выведется содержимое каждого из 443 объекта (в нашем случае)
Например содержимое моего 400-го голоса выглядит вот так
Запомните, что i
для каждой строки будет равно своему порядковому номеру. От нуля до общего количества голосов length.
Пропишем еще некоторые переменные
var arr = result,
Все содержимое объектов теперь в arr.
Зададим время старта для бота задним числом. Например собрать голоса выбранного куратора за прошедший час.
start = starttime - period,
- Если помните, в начале скрипта
startime
содержит время запуска бота period
у нас =minutes * 60
minutes
у нас = задаваемое вами значение в минутах в поле формы с одноименным ID.
Таким образом в переменную start мы запишем указанные вами минуты переведенные в формат секунд (unix time). Поскольку starttime у нас равно сейчас 1487356644
- вычтем из него 60 минут (60min*60=3600sec) и мы получим
1487356644 - 3600 = 1487353044.
Это и будет наш старт для бота задним числом (час назад)
Для голосования нам нужно 3 значения логин, ссылка, сила.
Например, что бы проголосовать за мой пост, нужно
vik
, bot-bro-wser-ne-trebuyushii-servera-navykov
,1000
Но в нашем объекте все хранится так:
authorperm = vik/bot-bro-wser-ne-trebuyushii-servera-navykov
percent = 1000
Нам потребуется из этого объекта достать 3 отдельных значения. Ссылку на пост, логин автора и силу голоса в процентах X100. Но просто получить это в переменные не получится, так как логин склеен с ссылкой.
Решить это можно некоторыми манипуляциями в переменных
ap = arr[i].authorperm,
Выше мы записали в переменную ap
нашу строку вида vik/bot-bro-wser-ne-trebuyushii-...
И теперь в переменную author
запишем только логин из строки. Для этого обрежем все начиная с /
и оставит только то, что до косой.
author = ap.substring(0, ap.indexOf('/')), // Теперь тут vik
Почти то же сделаем с ссылкой на пост. Обрежем все до /
и оставим только текст после /
permlink = ap.substring(ap.indexOf('/')).substring(1), // Тут ссылка на пост
Логин и ссылку получили, теперь запишем в переменные силу, и время совершения апвота.
power = arr[i].percent, // 1000 для 100%, или 500 для 50% и т.д.
time = arr[i].time; // Время в человеческом формате
utime = Date.parse(time) / t; // Переводим в unixtime
Теперь, когда наши переменные с автором, ссылкой и силой готовы для каждого голоса для username, мы воспользуемся благом ставить лимит на срок давности голоса который хотим повторить.
Создаем условие если : utime
больше start
.
- utime - дата на каждом совершенном голосе
- start - заданное нами отправное время для бота
if (utime > start) {
// Тут будет массив с переменными
}
Теперь внутри условия будет заполняться массив a
, который мы объявили чуть раньше var a = [];
a.push({
author: author, // vik
permlink: permlink, // Ссылка на пост
power: power, // 1000
utime: utime, // не обязательно
start: start // не обязательно
});
Все заполнено и мы можем обратиться к массиву a
за данными о голосах username, только тех которые позднее нашего времени в переменной start.
Теперь у нас своего рода список голосов за некоторый период и мы хотим за все проголосовать.
Если мы пошлем в голос запрос на голосование за все посты разом - фактически проголосовать удастся лишь за один пост, так как действует ограничение в blockchain - только один голос за 3 секунды. Стало быть нам нужно взять наш список, порой внушительный, и заставить бот голосовать по одному голосу с интервалом в 3 секунды. Есть у нас решение и для этого
Объявим 2 переменные.
summ
- будем хранить число - количество голосов, которые нужно повторить.
i
- будет нулем
var summ = a.length;
var i = 0;
Теперь создадим функцию в переменной goVote
var goVote = setInterval(function() {
// Все что внутри, выполняется с интервалом в 3 секунды
}, 3000);
Внутрь поместим условия
if (count && summ > 0 && a[i].power / 100 >= votepower) {
}
Если count = true
(вкл), а оно у нас true в самом вверху и будет таковым, пока мы сами не переключим в false(выкл). И если summ
больше 0
- то есть если наш полученный массив a
содержит голоса. Ведь может и не содержать! Например вы выбрали глубину в 30 минут. А куратор голосовал последний раз еще вчера - не будет голосов тогда.
И наконец a[i].power / 100
больше или равно переменной которая есть поле с id votepower
в форме вверху. В поле мы указываем силу голоса вида 100% а голосуем в формате, где 100% = 1000. Потому делим нашу силу голоса на 100. Только для того, что бы вам было удобнее задавать ее в форме.
Голосование
steem.broadcast.vote(k, account, a[i].author, a[i].permlink, a[i].power, function(err, result) {
console.log(err,result);
});
Передаваемые параметры в блокчейн это
k
- Постинг ключ владельца бота
account
- логин владельца бота
a[i].author
- логин куратора за которым следуем
a[i].permlink
- ссылка на пост
a[i].power
- сила
Обратили внимание на i
? Мы задали выше, что i = 0, наш список целевых голосов в массиве a
начинается с 0
(первый голос это не 1, это 0. Особенности array и object в js).
Так же помним, что мы в 3-х секундном интервале.
Добавляем в код внутри интервала возрастающую при каждом запуске переменную:
i++;
Теперь, у нас с каждым циклом в 3 секунды переменная i увеличится на 1.
Первый запуск выдернет из массива a
первый голос
a[0].author a[0].permlink a[0].power
Второй запуск выдернет второй голос из массива
a[1].author a[1].permlink a[1].power
И так далее:
a[2].author a[2].permlink a[2].power
Таким образом с интервалом в 3 секунды мы перебираем строку за строкой в списке голосов username. Перебираем и отправляем голос
steem.broadcast.vote(k, account, a[i].author, a[i].permlink, a[i].power, function());
Можем закрыть первое условие...
В этом месте у меня еще необязательная косметическая функция
itemShow()
- делает появление голосов анимированным.
Назад в будущее. Второе условие.
Мы все еще не будем закрывать скобки нашего интервала и напишем второе условие внутри 3-х секундного интервала:
if (i == summ) {
count = false;
period = 4;
clearInterval(goVote);
followVote();
}
Если i
- оно же номер голоса равно summ
- сумма голосов в массиве a
, то значит, что мы перебрали весь массив и нам нужно остановить слать голоса в никуда.
Внутри условия произойдет следующее
Мы меняем в переменной count
значение true
на false
, что будет значить, что мы запретим теперь выполнять предыдущее условие if (count)
в котором функция отправки голоса. Запрещаем по причине того, что список голосов уже обработан ботом.
Так же мы сбрасываем указанное start
время до времени настоящего минус 4 секунды.
period = 4;
Таким образом, бот отработал указанное вами "прошлое" куратора, начинает отрабатывать настоящее.
Так же мы сбрасываем (отключаем) интервал goVote
.
И в завершение... Все по новой - мы снова запускаем 'followVote();' - что по сути своей делает почти тоже что и нажатие кнопки старта бота broBot()
, но с тем условием, что теперь глубина ретроспективы равна не тому, что у вас в поле формы, а 4 секундам, так как заданное в форме уже было обработано и нет смысла начинать по новой с того старого периода. Теперь бот работает с тем же интервалом в 3 секунды и ждет новых голосов от вашей цели.
Косметические функции
Внутри интервала голосования мы не только посылаем голоса, но и выводим-отображаем список этих голосов. В переменную votehtml
мы поместили логин, ссылку на пост и силу голоса (тысячи правильно поделили на проценты)
votehtml = '<div id="item" class="myJson"><a href="https://golos.io/@' + a[i].author + '"><strong>' + a[i].author + '</strong> ' + a[i].permlink + ' <i>' + a[i].power / 100 + '%</i> </a></div>';
Далее мы выводим переменную в блок c id nicedata
document.getElementById('nicedata').insertAdjacentHTML('afterbegin', votehtml);
При этом в css у нас эти элементы описаны так:
#item{
transition:1s all ease;
transform:translate3d(0px, -100px, 0px);
position:absolute;
opacity:0;
}
Изначально они появляются невидимыми и на 100px выше. Но в наше интервале есть функция itemShow()
которая добавляет элементам с id item класс anim
function itemShow() {
setTimeout(function() {
document.getElementById("item").classList.add('anim');
}, 200);
}
А класс anim
у нас уже описан в CSS иначе
#item.anim{
transform:translate3d(0px, 0px, 0px);
opacity:1;
transition:1s all ease;
position:relative;
}
Плавно, с transition:1s all ease;
спустились на 100px в нормальное положение и прозрачность.
Весь css можно посмотреть в исходнике
http://pastebin.com/raw/VgimfAwC
Охапку дров и плов бот готов :)
Прошлые посты по теме:
Как вы меня бесите все со своими ботами...
Для чего вам голос? Для чего? Люди душу вкладывают в тексты пишут стараются а вашему бездушному боту пофиг, он будет апать даже говно на палочке... Руками слабо открыть прочитать поддержать...
Давайте все наделаем ботов и будут они нам всем бабло намывать а мы и писать ничего не будем. зачем париться публикуешь пост в котором 3 точки к примеру и все погнали роботы за них голосовать. ПОГУБИТЕ ГОЛОС СВОИМИ РОБОТАМИ!!!
А если по делу, то задача избавиться от роботов выглядит как не имеющая смысла, в дополнение еще и не решаемая. Правильный вопрос - как сделать так, чтобы боты были полезны. Посмотрите на Slack, Reddit, Telegram.
Ну я вот лично о таком применении не думал, странно, что такая коварная мысль зародилась именно в вашей голове :)
Для этого существуют флаги. Очищайте ряды :)
@vik У вас бот сейчас работает? У меня перестал работать.
Может какие-то изменения произошли?
Бот показывает, что проголосовал, но на самом деле голоса нет.
Только что проверил - работает. Вот апвоты сделанные ботом golosdb.com/@vik
Вы посмотрите лог в консоли браузера, там если есть ошибки - они будут отображены.
Благодарю за подсказку - я так понял, что время сбилось на пару минут.
Поправил, и сейчас всё работает!
Че-то я запустил у себя скрипт, а он не пашет :(
Ща, попробую прямую ссылку
Попробуйте запустить бот в другом браузере. У меня в Опере бот отказывался "следить" за новыми постами автора. Использование Хрома решило проблему.
В консоли браузера выводятся ошибки.
Вы могли указать неверно какой-то из параметров или ошибиться с постинг ключом.
Обращаю внимание! Постинг-ключ это не ваш пароль, это отдельный ограниченный ключ. Это разные с паролем ключи, основной пароль использовать не нужно. Постинг ключ начинается на 5 всегда.
@vik
А можно ли так повторять голоса за несколькими пользователями?
Подскажите, какие изменения нужно внести в бот?
И можно ли установить свою фиксированную силу голоса, например 20%, а не повторять за автором?
А что значит "сколько прошедших минут учесть?"
Это значение отправной точки для скрипта. Например вы выбрали следовать за academy, если поставите 0 прошедших минут - бот будет ждать только новые голоса в настоящем времени, не оглядываясь назад. Если поставите допустим 100 - бот начнет анализировать голоса цели заглянув в прошлое на 100 минут и повторит голоса из прошлого.
А у вас случайно не завалялось скрипта, которым бы можно было не повторять за кем-то а самому настроить список авторов и время, через которое ставить голос? :)
Скрипт не сложно написать под конкретную задачу. Только опишите желаемый алгоритм как можно подробнее.
Вы хотите задать некий список авторов, за недавние посты которых хотите проголосовать? Укажите все нюансы в свободной форме и попробуем сделать для этого алгоритм.
Хочется что типа https://steemvoter.com/
Т.е. я задаю типа конфига:
Т.е. автор, который будет в списке пишет новый пост, а скрипт автоматически ставит лайк через время, которое я укажу
@vik Да, такой вариант скрипта был бы очень полезен!
Например, я точно знаю, что за большинство постов определенных пользователей я буду голосовать, но далеко не всегда получается проголосовать с максимальной для себя пользой (на какой-то там минуте, вроде между 25 и 30 мин. после публикации поста).
Так вот, если скрипт решит эту проблему, то было бы замечательно!
Даже если после того, как я прочитаю посты, за которые я голосовал ботом, и они мне по какой-то причине мне не понравятся, то всегда есть возможность убрать апвоут задним числом.
в коде bot.html стоит
script src="https://golos.rubtc.info/wp-content/plugins/golos/golos.js"></script
то есть он скачивает скрипт, файл golos.js вообще не нужен, у меня без него заработал =)
Привет!
Этот пост был выбран Академией Голоса и попал в список программы поддержки качественных образовательных постов.
Ссылка на твой пост будет опубликована в отчете Академии.
Спасибо за полезный контент (ノ◕ヮ◕)ノ*:・゚✧
@vik, Поздравляю!,
Ваш пост был упомянут в моем хит-параде в следующей категории:
..так как я один хрен ничего не понял, то продолжу голосовать душой...))))))...
если нужно за несколькими пользователями голосовать? через запятую их прописывать?
ручками голосовать надо, ручками. после прочтения
Спасибо за разжёвывание, очень полезно.
@vik, сейчас нет времени втыкать в весь пост, я правильно понял что по ссылке https://golos.rubtc.info/bot.html можно использовать свой логин, ключ и вперед?
Да. На странице стоит tls шифрование, ваш ключ никто не увидит. В теории я могу изменить скрипт и украсть ваш ключ и проголосовать вместо вас, потому и предлагается использовать свою локальную версию по инструкции. На практике мне это не нужно)
Пока не заблокирована такая возможность нужно использовать. Яростно кормлю дельфина.
то чувство, когда ты повар :)
<html lang="ru">
хотелось бы видеть до тега<head>
, согласно W3CВот она, вот она рыба моей мечты!Ё!))
Доступно и хотя и не все понятно. В в вебе не силен.
ожидаем бота-автора
Бот-автор может быть назойливым :)
Но если все поворачивать во благо - можно сделать отложенный постинг с помощью бота.
Или комментарий под постами в которых есть упоминание некоего слова-фразы. Например бот может ойкать и возмущаться при упоминании пиписьки в посте :)
Но меня заинтересовала больше идея с твиттером. У него гибкий api, можно сделать так, что после каждого действия, будет соответствующий твит в вашем твиттере. А учитывая, что можно подписаться на твиттер и разрешить смс - то можно делать смс рассылку с golos средствами twitter ))
Вик, в этом плане нам лучше сделать интеграцию, например с IFTTT.
Эта интеграция исключительно на нашей стороне возможна или, например, тебе тоже?
Благодарю за пост. Он будет иметь резонанс!
Надеюсь, что твой ценный опыт даст начало массе других модифицированных и более полезных ботов.
Я как раз тоже пишу своего, но чуток более полезного для пользователя бота. Вначале опробую его на своих подписчиках)
много текста.
А нельзя сделать это все одним файлом?))
Одним файлом и было сделано. И он размещен в тексте:
http://pastebin.com/raw/VgimfAwC