Я – офисный сотрудник. Мое рабочее место – кабинет, в котором помимо меня сидит еще 6 человек. Я давно привык, что фоном всегда играет музыка, за исключением тех рабочих процессов, в которых нужна концентрация. Слушать музыку в наушниках как-то неудобно, да и голова начинает болеть вскоре. Поэтому слушал я ее всегда так, что моим «соседям» не услышать ее было невозможно. Они меня ругали… но ругали не за то, что я мешал им самой музыкой, а за то, что слушал я неправильную музыку. Тогда у меня появилось желание угодить всем, чтобы каждый мог, не вставая со своего места, включить любую песню, даже ту, которой нет на компьютере.
Схема
На первый взгляд автоматизация должна включать следующие возможности: включение любого трека из сети онлайн, смена трека, регулировка громкости, возможность поставить проигрывание на паузу и, соответственно, снять с паузы, а также должна быть возможность включить трек, расположенный локально на компьютере. С программированием как таковым я толком не знаком, за исключением чтения мануала по AutoIT (всегда хотел уметь автоматизировать какие-либо процессы в Windows-системах). В голове сразу возникла схема: AutoIT+ICQ+Foobar+Плагин для Foobar’а, позволяющий искать и слушать музыку онлайн из социальной сети «ВКонтакте» (его окно изображено на скриншоте). Суть проста: мои коллеги шлют в определенную асю сообщения, скрипт AutoIT их «подхватывает» и, в соответствии с сообщением, выполняет манипуляции с Foobar’ом.
Реализация
Так как при работе AutoIT на экране видны все манипуляции скрипта: открытие окон, выбор трека и так далее, то изначально я планировал использовать для него виртуальную машину, но, обернувшись, увидел простаивающий компьютер недавно уволившегося сотрудника и решил, что «медиацентром» пока будет он.
Первым делом я зарегистрировал новый аккаунт ICQ для бота. Придумывание ника для него не заняло много времени – «Пульт». Затем установил на выбранный компьютер QIP 8095 – этот клиент я выбрал из-за того, что сообщения в нем хранятся в виде txt-файлов. Настроил его следующий образом: отключил сохранение истории сервисных сообщений (о том, что кто-то из контакт-листа вошел в сеть или вышел и прочее), также выключил все звуки, чтобы они не отвлекали от работы коллег. Затем установил Foobar с необходимым плагином и настроил его на работу с горячими клавишами. И в конце занес в контакт-лист бота себя и всех сотрудников, сидящих со мной в кабинете.
После завершения всех подготовительных работ приступил к написанию самого скрипта. Принцип его работы прост: он каждые 2 секунды должен проверять папку, в которой QIP хранит историю переписки, на наличие txt-файла, если файл находится, он читает из него сообщение, удаляет сам файл истории и, в соответствии с тем, что было написано в сообщении производит манипуляции с Foobar’ом.
Что получилось в итоге
Скрипт:
Func Terminate() ; Функция выключения скрипта так как он работает в бесконечном цикле
Exit 0
EndFunc
HotKeySet("{ESC}", "Terminate") ; Привязывает функцию выключения к клавиши ESC
FileChangeDir ("C:Program FilesQIPUsersXXXXXXXXXHistory"); Изменяет рабочую директорию
while 1 ; Начинает бесконечный цикл работы скрипта
$Search=FileFindFirstFile("*.txt") ; Ищет txt-файлы в рабочей директории и возвращаемое значение поиска заносим в переменную $Search
if $Search = -1 then ; Проверяет наличие файлов по содержимому переменной
Sleep(1000) ; Если файлов не найдено, ждет секунду и запускает цикл сначала
else ; Если найден txt-файл, то...
$File=FileFindNextFile($Search) ; Заносит название файла в перменную $File
$Log=FileRead ($File) ; Заносит содержимое файла в переменную $log
$Log=StringSplit ($Log, @LF) ; Так как в QIP'е одно сообщение состоит из трех строк (пометка сообщения как входящее или исходящее, имя автора/дата/время отправки сообщения и само сообщение), то делает из переменной массив, в котором каждый элемент равен одной строке
$Mess=$log[3] ; Само сообщение заносит в переменную $Mess
FileDelete($File) ; Удаляет файл истории
MsgBox ("0","", $Mess, 1) ; На секунду выводит на экран сообщение с командой, которую скрипт будет сейчас выполнять - это реализовано для отладки
WinActivate ('[REGEXPCLASS:(?i){97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}]') ; Делает активным окно Foobar'a, реализовал посредством обращения к классу, так как заголовок плеера меняется в зависимости от исполняемой композиции
WinWaitActive ('[REGEXPCLASS:(?i){97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}]') ; Ждет когда окно Foobar'a станет активным
$Check=StringInStr($Mess, "local") ; Проверяет вхождение слова "local" в текст сообщения
if $Check=1 then ; Если "local" находится в начале сообщения, то...
$Mess=StringTrimLeft($Mess, 6) ; "Отрезает" первые 6 символов в сообщении (слово local и последующий пробел)
Send("^f") ; Отправляет нажатие сочетания клавиш CTRL+F
WinWaitActive ('[REGEXPCLASS:(?i){483DF8E3-09E3-40d2-BEB8-67284CE3559F}]') ; Ждем пока откроется окно поиска трека
Send($Mess) ; Вводит в запрос содержимое сообщения
Sleep(500) ; Ждет полсекунды
Send("{TAB}") ; Отправляет нажатие клавиши TAB
Sleep(500) ; Ждет
Send("{TAB}") ; Отправляет нажатие клавиши TAB (делается активным элемент окна, в котором выводится результат поиска)
Sleep(500) ; Ждет
Send("{DOWN}") ; Отправляет нажатие клавиши DOWN (выделяется первый трек, найденный поиском)
Sleep(500) ; Ждет
Send("{ENTER}") ; Включает найденный трек
Sleep(500) ; Ждет
WinClose('[REGEXPCLASS:(?i){483DF8E3-09E3-40d2-BEB8-67284CE3559F}]') ; Закрывает окно поиска
continueloop ; Возвращается в начало бесеконечного цикла while
endif ; Если слова "local" в начале сообщеня нет, то скрипт продолжает чтение отсюда...
$Stop=StringRegExp ($Mess, "стоп") ; ... ищет вхождение слова "стоп" в сообщении
$VolUp=StringRegExp ($Mess, "громче") ; Ищет вхождение слова "громче" в сообщении
$VolDown=StringRegExp ($Mess, "тише") ; Ищет вхождение слова "тише" в сообщении
$VolMax=StringRegExp ($Mess, "громко") ; Ищет вхождение слова "громко" в сообщении
$VolMin=StringRegExp ($Mess, "тихо") ; Ищет вхождение слова "тихо" в сообщении
if $Stop=1 then ; Если отправлено слово "стоп", то..
Send ("!x") ; ... отправит сочетание клавиш ALT+X, которое ставит на паузу/продолжает проигрывание
continueloop ; Возвращается в начало бесеконечного цикла while
endif
if $VolUp=1 then ; Если отправлено слово "громче", то...
Send ("!{UP}") ; ...
Send ("!{UP}") ; ...
Send ("!{UP}") ; ...
Send ("!{UP}") ; ...
Send ("!{UP}") ; 5 раз нажимает сочетание клавиш ALT+UP, которое чуть-чуть увеличивает громкость
continueloop ; Возвращается в начало бесеконечного цикла while
endif
if $VolDown=1 then ; Если отправлено слово "громче", то...
Send ("!{DOWN}") ; ...
Send ("!{DOWN}") ; ...
Send ("!{DOWN}") ; ...
Send ("!{DOWN}") ; ...
Send ("!{DOWN}") ; 5 раз нажимает сочетание клавиш ALT+DOWN, которое чуть-чуть уменьшает громкость
continueloop ; Возвращается в начало бесеконечного цикла while
endif
if $VolMax=1 then ; Если отправлено слово "громко", то...
Send ("!c") ; ... отправит сочетание клавиш ALT+C, которое включает максимальную громкость
continueloop ; Возвращается в начало бесеконечного цикла while
endif
if $VolMin=1 then ; Если отправлено слово "тихо", то...
Send ("!z") ; ... отправит сочетание клавиш ALT+Z, которое включает минимальную громкость (не выключает совсем)
continueloop ; Возвращается в начало бесеконечного цикла while
endif
; Если не один из выстоящих if'ов не сработал, то...
Send ("^q") ; Отправляет сочетание клавиш CTRL+Q, отвечающее за открытие окна плагина Foobar'a, который ищет музыку в ВКонтакте
WinWaitActive ("vk.com audio Search") ; Ждет пока окно плагина не станет активным
ControlCommand("vk.com audio Search", "", "ComboBox1", "SetCurrentSelection", 6) ; Из выпадающего списка "В каких сервисах искать" выбирает vk.com (ВКонтакте)
Sleep(500) ; Ждет полсекунды
ControlFocus("vk.com audio Search", "", "Edit1") ; Делает активным строку ввода запроса
Sleep(500) ; Ждет
Send($Mess) ; Отправляет в строку ввода содержимое сообщения из QIP'а
Sleep(5000) ; Ждет 5 секунд, пока плагин ищет трек
while 1 ; Не знаю как иначе реализовать то, что будет дальше, кроме как с использованием бесконечного цикла
$i=ControlListView ("vk.com audio Search", "", "SysListView321", "GetItemCount") ; Заносит в переменную $i количество найденных треков
if $i=0 then ; Если треков не найдено (плагин иногда не находит результаты с первого раза)
ControlClick("vk.com audio Search", "", "Button1") ; Нажимает на кнопку "Остановить поиск"
Sleep(500) ; Ждет
ControlClick("vk.com audio Search", "", "Button1") ; Нажимает на кнопку "Поиск"
Sleep(5000) ; Ждет
exitloop ; Выходит из внутреннего бесконечного цикла while (со второго раза всегда находит)
else
exitloop ; Если не нашел с первого раза, то, скорее всего, название трека ввели неправильно и скрипт также выходит из внутреннего бесеконечного цикла while
endif
wend
ControlListView ("vk.com audio Search", "", "SysListView321", "Select", 1) ; Выбирает из результата поиска второй трек (первый зачастую почему-то бывает длительностью 00:00 и не играет)
ControlClick("vk.com audio Search", "", "Button3") ; Добавляет в плейлист второй трек
WinClose("vk.com audio Search") ; Закрывает окно плагина
WinWaitActive ('[REGEXPCLASS:(?i){97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}]') ; Ждет пока окно Foobar'а станет активным
Sleep(500) ; Ждет полсекунды
Send ("{END}") ; Отправляет
Sleep(500) ; Ждет
Send ("{ENTER}") ; Отправляет нажатие клавиши ENTER, что включает трек
endif
wend ; Возвращается в начало бесеконечного цикла
Как это работает
Перед началом работы в плейлист Foobar’a необходимо добавить локальную библиотеку музыки. Если кто-то пишет просто: «metallica fade to black», то скрипт «находит» эту песню в ВКонтакте и включает ее. Если кто-то написал: «local joe satriani crowd chant», то скрипт находит трек в своем плейлисте, а затем его включает. Также доступны команды: «тихо», «громко», «тише», «громче» и «стоп».
Заключение
Делал это я несколько часов и знаю, что скрипт далеко неидеален, в нем много недоработок, например: следовало бы как-то сократить код (наверняка можно переиграть отлов команд более правильным способом) или, если человек со словом «local» запрашивает трек, которого нет в плейлисте, то его надо искать в онлайне и так далее. Я не программист совсем, поэтому, если не сложно, напишите о ошибках построения кода, буду благодарен.