В OS X есть масса средств для автоматизации работы. И хоть в Apple считают, что лучше всего это делать с помощью Automator, AppleScript или Objective-C, мы пойдем другим путем и попытаемся использовать Python — потому что так привычнее и удобнее (прим. ред. — начиная с версии 10.10  (Yosemite) в OS X можно писать автоматизации на Java Script, но на момент написания статьи такой возможности не было).

Каждый обладатель компьютера Apple, считающий себя продвинутым пользователем, должен хоть раз в жизни сделать следующее: открыть программу AppleScript Editor, найти пункт Open Dictionary в меню File, а затем выбрать из списка какую-нибудь из программ, поставляющихся с системой (с ними фокус выйдет наверняка), например Finder или iTunes. Появится окно со «словарем» — так называется описание программного интерфейса Open Scripting Architecture (OSA), который каждая приличная маковская программа предоставляет для автоматизации. С его помощью любое приложение можно попросить выполнить то или иное действие или поделиться данными об открытых окнах и документах. А вот как сделать это удобнее и с наименьшей затратой усилий — еще вопрос.

При помощи OSA можно получить полный контроль над маковскими приложениями. Например, попросить почтовик создать и отправить письмо
При помощи OSA можно получить полный контроль над маковскими приложениями. Например, попросить почтовик создать и отправить письмо

Есть много способов извлечь пользу из дружелюбности OS X к любителям автоматизировать. Самый простой из них — это Automator, визуальный редактор скриптов, который входит в состав OS X и позволяет создавать незамысловатые линейные сценарии вроде переименования файлов или смены размера картинок. Для случаев посложнее существует тот самый AppleScript, редактор которого мы только что использовали для просмотра словарей.

Проблема с AppleScript заключается в том, что его авторы пытались сделать очень простой язык, освоить который могли бы люди, никогда раньше не программировавшие. В результате им все равно пользуются в основном программисты, но страдают от вычурного синтаксиса. Простые программы на AppleScript выглядят как законченные предложения на английском. Например, чтобы заставить iTunes воспроизводить музыку, можно написать:

tell application "iTunes" to play

Однако стоит попытаться написать на AppleScript что-то длиннее пары строк, как оказывается, что он лишь чинит преграды своими красивыми оборотами. Пара часов борьбы с капризами интерпретатора, и код начинает походить на пирамиду из блоков tell и end tell, пересыпанную английскими союзами и кучей скобочек. Это не значит, что AppleScript плох или что на нем нельзя сделать ничего путного, просто, программируя на нем, быстро начинаешь скучать по знакомым языкам, которые позволили бы решить все проблемы значительно быстрее.

Те же интерфейсы OSA, с которыми работает AppleScript, доступны из другого эппловского языка программирования — Objective-C (и будут доступны из Swift) через механизм под названием Scripting Bridge. К сожалению, для большинства смертных это не решит проблему, а лишь усугубит ее. Знать Objective-C хорошо, но вряд ли кто-то будет изучать его ради автоматизации повседневной работы. Swift, новый язык программирования Apple, будет чуть легче, но что, если все же захочется получить доступ к функциям маковских программ из других языков? Например, если понадобится добавить какие-нибудь вызовы в уже написанный код.

Простой метод решения этой проблемы — запускать свои скрипты из AppleScript, используя команду do shell script и далее в кавычках все, что требуется сделать из командной строки UNIX. Или наоборот — вызывать AppleScript из командной строки, используя утилиту osascript.

 

Ужасы Scripting Bridge

Для более плотной интеграции тоже существует стандартный способ, по крайней мере в случае с Python и Ruby. Начиная с Mac OS X 10.5 из этих языков можно обращаться к OSA при помощи библиотек Foundation и ScriptingBridge. Если у тебя установлен XCode, значит, они наверняка есть в системе. Вот как будет выглядеть программа на Python, запускающая воспроизведение музыки в iTunes:

from Foundation import *
from ScriptingBridge import *

iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
iTunes.playpause()

Сразу чувствуется, что тут разобраться уже сложнее, и интерфейсы не такие дружелюбные. Проблема в том, что Scripting Bridge для Python и Ruby не существует, и используется сразу два «моста»: один — к Objective-C, второй из Objective-C к OSA. То, что в AppleScript выглядело как одна строка, тут разрастается в пугающую каракатицу. Следующий скрипт на Python просит iTunes создать новый плей-лист с названием Test:

iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
p = {'name':'Test'}
playlist = iTunes.classForScriptingClass_("playlist").alloc().initWithProperties_(p)
iTunes.sources()[0].playlists().insertObject_atIndex_(playlist, 0)

Обрати внимание на вызов alloc() — это и есть тяжелое наследие Objective-C. Советовать такой интерфейс в качестве упрощения было бы издевательством — лучше уж выучить AppleScript. С документацией тоже не все ладно: таким методом пользуются мало (что неудивительно), и сказать, что интернет полон примеров, было бы сильным преувеличением. На портале Apple есть справка по Scripting Bridge, а еще информацию можно добывать при помощи питоновской команды help(). В нашем случае можно запустить интерактивную оболочку Python в командной строке, создать и проинициализировать объект iTunes, как показано в примере, и написать help(iTunes), чтобы получить полный список доступных функций.

 

Appscript спешит на помощь

Ситуация была бы совсем грустной, если бы не выручило сообщество. Вместо развесистых стандартных интерфейсов можно использовать надстройку под названием appscript. С ней все становится куда интереснее. К примеру, запустить воспроизведение в iTunes даже проще, чем в AppleScript:

from appscript import *
app['iTunes'].play()

А вот эта строка выдаст ссылку на сайт, открытый в текущем окне Safari:

app('Safari').windows[0].document.URL.get()

О подробной документации, как всегда, остается только мечтать, но, если порыться в папке с исходниками appscript, можно найти каталог sample с примерами использования большинства стандартных приложений.

Одно время перспективы appscript были неясными: автор изначальной реализации объявил, что из-за изменений в OS X все его труды вот-вот пойдут насмарку и дальнейшая поддержка проекта не имеет смысла. К счастью, быстро нашлись желающие поддерживать код дальше, так что катастрофа откладывается на неопределенный срок. На GitHub можно найти актуальный форк.

 

Системные сервисы своими руками

Помимо OSA, в OS X есть еще один механизм, крайне полезный для автоматизации, — это системные сервисы. В главном меню каждой программы есть пункт Services со списком доступных сервисов. В зависимости от содержимого окна они разные — одни работают с файлами, другие — с текстом, третьи — с веб-страницами, четвертые — с картинками. Попробуй выделить кусочек текста в текстовом редакторе и заглянуть в Services — там появятся пункты, позволяющие искать в Google, смотреть в словаре, отправлять цитату по электронной почте и так далее. Сервисы можно создавать самостоятельно. Как? Конечно же, в XCode и на Objective-C! Но энтузиасты, как всегда, нашли лазейку, сильно облегчающую жизнь. Качаем программу ThisService и сколько душе угодно пишем сервисы на Python, Perl, Ruby или даже JavaScript (если в системе есть Node.js).

С виду ThisService очень прост. На деле — тоже
С виду ThisService очень прост. На деле — тоже

Первое, что нужно сделать после скачивания программы, — скачать еще и файл Starting Points. Это архив с шаблонами скриптов. Здесь на выбор есть разные языки и типы сервисов (выбор типа зависит от того, что сервис делает с текстом: принимает, выдает или пропускает через себя, внося изменения). Все, что будет происходить с текстом, нужно вписывать в функцию main(), входная переменная называется input_text, выходная — output_text, а между ними — огромный простор для творчества.

Закончив с редактированием скрипта, запускаем ThisService, перетягиваем файл с кодом в поле Script, задаем название и параметры (можно задать значок, указать приложения, в которых будет появляться сервис, указать время, отведенное на исполнение скрипта, и еще некоторые опции). Жмем Test Service, балуемся, сколько потребуется, вводя разные входные строки, и смотрим, все ли правильно работает. Кнопка Finish Testing and Create Service запакует скрипт, отправит его в папку ~/Library/Services и заодно активирует его в настройках системы. Чтобы деактивировать сервис или задать ему сочетание клавиш, нужно зайти в системные настройки, выбрать настройки клавиатуры и пункт Services во вкладке, посвященной горячим клавишам. В списке слева должен быть наш сервис.

В настройках системы есть специальный раздел, где сервисам можно задавать горячие клавиши
В настройках системы есть специальный раздел, где сервисам можно задавать горячие клавиши

Вдохновение или готовые сервисы можно черпать на сайте ThisService: там есть готовые сокращалки веб-адресов, сервисы для работы с распространенными маковскими программами и тому подобные полезные вещи.

 

1 комментарий

  1. 09.01.2015 at 11:37

    «Пара часов борьбы с капризами интерпретатора, и код начинает походить на
    пирамиду из блоков tell и end tell, пересыпанную английскими союзами и
    кучей скобочек. Это не значит, что AppleScript плох» — вот именно это и значит.

Оставить мнение

Check Also

Эксплоиты в десятку. Обзор самых интересных докладов с мировых ИБ-конференций

В последние годы мы отучились воспринимать Windows как нечто невероятно дырявое. Эта опера…