Clip2net: unix-way или «Сделай сам»

На Хабре уже писали о сервисе Clip2Net (Clip2net — очень быстрая публикация в Сеть). Это довольно удобный сервис для публикации скриншотов (и вообще любых файлов) в сети. Цитата из описания:
Clip2net – это инструмент загрузки информации в сеть с акцентом на публикацию изображения с экрана компьютера. Основной момент – скорость, минимум операций, универсальность применения. На выходе программа дает ссылку на опубликованную информацию, которую можно использовать где угодно в Сети – будь-то сообщения по e-mail/IM или свой блог/сайт.
У проекта есть недостатки, главный из которых (на мой взгляд ;) — отсутствие клиента под Linux. Попытаемся исправить эту оплошность, а также продемонстрируем на конкретном примере всю прелесть операционных систем GNU/Linux, — философию «Unix-way».
Философия UNIX гласит:
Взято отсюда: http://ru.wikipedia.org/wiki/Философия_UNIX
- Пишите программы, которые делают одну вещь и делают её хорошо.
- Пишите программы, которые бы работали вместе.
- Пишите программы, которые бы поддерживали текстовые потоки, поскольку это универсальный интерфейс.
В этой статье речь пойдёт непосредственно о сервисе clip2net.com, но применить данный подход к любому сервису с загрузкой файлов будет несложно.
И сразу же оговорюсь: я не имею к сервису clip2net.com никакого отношения.
Постановка задачи
Для начала давайте поставим задачу — определимся, какой функционал нам необходим для комфортной работы с сервисом Clip2Net:
- снятие скриншота всего экрана, всего окна текущей программы или произвольной области экрана (выделение мышью)
- выбор файла, который мы хотим отправить
- автоматическая отправка скриншота/файла на сервер clip2net
- получение ссылки на отправленный скриншот/файл, отображение её и копирование в буфер обмена
Программа Clip2Net, которую нам предлагают скачать с сайта (Windows-only) имеет ещё несколько режимов работы (например, «запись видео» или «публикация интернет-ссылки»), но нам они не интересны.
Функционал
Итак, в соответствии с философией «Unix-way», разобьём функционал нашей будущей «программы» на элеменратные действия:
- снятие скриншота всего экрана
- снятие скриншота окна текущей программы
- снятие скриншота произвольной области экрана
- выбор файла
- закачивание файла на удалённый сервер
- отображение произвольных сообщений
- копирование произвольного текста в буфер обмена
Инструменты
А теперь определимся с инструментарием, который мы будем использовать для решения поставленной перед нами задачи:
Cнятие скриншота всего экрана, окна текущей программы и произвольной области экрана:
C этими задачами лучше всего справляется программа scrot (http://freshmeat.net/projects/scrot/) — она умеет делать снимки экрана и сохранять их в файл.
Здесь и далее я буду описывать процесс установки и настройки для Ubuntu Linux. Для других ОС отличия минимальны — за деталями обратитесь к man'ам, к Google'у или к знакомым линуксоидам =)
Устанавливаем программу:
> sudo apt-get install scrotЧитаем man:
> man scrotДелаем выводы. Для реализации нашего функционала нам потребуется три команды:
> scrot -q 100Делает скриншот всего рабочего стола. Параметр -q позволяет задать качество полученной картинки (1-100). По умолчанию параметр -q равен 75, — если вас устраивает это качество, то этот параметр можно опустить. Если вы хотите сэкономить трафик, то можно поставить значение поменьше.
> scrot -q 100 -u -bДелает скриншот текущего активного окна. Параметр -b говорит программе о том, что в скриншот нужно включить оформление («рамку») окна. Если рамка вам не нужна — опустите этот параметр.
> scrot -q 100 -sДелает скриншот выбранной пользователем области. Выбор происходит с помощью мыши — после запуска команды, необходимо выбрать произвольную прямоугольную область экрана — именно она будет сохранена в файл.
Файл сохраняется в домашнюю директорию текущего пользователя. Для того, чтобы над полученным изображением выполнить какие-либо действия, у программы scrot есть специальный параметр -e:
> scrot -q 100 -u -b -e 'ls -l $f'сделает скриншот активного окна с рамкой и с максимальным качеством и выполнит команду «ls -l» на сохранённом файле.
Выбор файла и отображение произвольных сообщений
Cпециально для таких целей была создана программа zenity (http://freshmeat.net/projects/zenity) — с помощью этой программы можно показать диалог выбора файла, вывести произвольный текст в окне и многое другое.
Устанавливаем программу (если она не установлена):
> sudo apt-get install zenityЧитаем man:
> man zenityДля реализации нашего функционала нам потребуется следующие команды:
> zenity --title='Clip2net' --entry --text='Отправка успешна. Скопировать ссылку на файл в буфер обмена?' --entry-text='здесь будет ссылка'выводит окно, с текстом, полем input и кнопками «OK» и «Cancel» — мы воспользуемся им для вывода полученной ссылки и запроса копирования этой ссылки в буфер обмена. Попробуйте запустить эту команду в консоли. Обратите внимание, что после нажатия на кнопку «OK» программа вернёт текст, который был в поле ввода, а после нажатия на кнопку «Cancel» — не вернёт ничего.

> zenity --title='Clip2net' --file-selectionВыводит окно выбора файла со списком файлов и кнопками «OK» и «Cancel». После нажатия на кнопку «OK» программа вернёт полный путь к файлу, а после нажатия на кнопку «Cancel» — не вернёт ничего.
> zenity --title='Clip2net' --info --text='info text'Выводит окно с сообщением и кнопкой «OK».
> zenity --title='Clip2net' --question --text='question text'Выводит окно с сообщением и кнопками «OK» и «Cancel».
> zenity --title='Clip2net' --error --text='error text'Выводит окно ошибки с текстом ошибки и кнопкой «OK».
Копирование произвольного текста в буфер обмена
Программа xclip как раз предназначена для работы с буфером обмена. Я уже писал о ней на Хабре: Работа с буфером обмена в Linux: теория и практика, поэтому мы не будем останавливаться на ней подробно.
Устанавливаем программу (если она не установлена):
> sudo apt-get install xclipЧитаем man:
> man xclipИспользование (копируем текст «Test text» в буфер обмена):
> echo "Test text" | xclipЗакачивание файла на удалённый сервер
Мне не удалось найти программы, которая имела бы подобный функционал и подходила бы для наших целей, поэтому я набросал скриптик на языке Perl, который выполняет эту часть работы. Но прежде чем писать скрипт, нам необходимо выяснить, что, как и куда передаёт Windows-версия программы clip2net, т.е. провести реверс-инжиниринг (http://ru.wikipedia.org/wiki/реверс-инжиниринг).
Скрипт загрузчика файла на удалённый сервер
Итак, проанализируем протокол обмена данными программы clip2net с сервером clip2net.com. Для подобных целей на моём компьютере стоит виртуальная машина с ОС Windows, на которой установлена программа Wireshark. Устанавливаем на виртуальную машину программу clip2net, скачав её с официального сайта, запускаем Wireshark в режиме перехвата данных и отправляем скриншот с помощью программы clip2net на сайт. Анализируем полученные данные:
- Скриншот отправляется через обычный HTTP-протокол POST-запросом на сайт clip2net.com по адресу clip2net.com/upload/
- Для авторизации на сайте используется обычная basic-авторизация.
- Интересные факты: Данные на сайт отправляются дважды — первый раз отправляется запрос без авторизации, на него приходит ответ «401 Unauthorized» («Authentification requred»), и второй раз те же данные отправляются с авторизацией. При этом оба раза отправляется файл, который мы хотим передать на сайт, что выглядит странным — если мы передаём, к примеру, десятимегабайтный файл, то он будет передан два раза. Это влечёт за собой увеличение трафика и времени передачи файла в два раза. Кроме того, после передачи файла программа подгружает страницу с файлом, включая все JS, CSS, картинки и прочее. В целом, после анализа передаваемых данных складывается впечатление, что у разработчиков данного сервиса понятие «скорость» означает что-то иное, нежели быстродействие.
- Определим параметры, которые передаются в POST-запросе:
— language = «Russian» (язык выбранный в программе)
— mode = «upload»
— title = "" (название скриншота)
— folder = "" (папка на сайте, куда помещается скриншот)
— expire = "" (дата, когда нужно удалить загруженный файл)
— key = "" (непонятный параметр)
— hwid = «A00A-AA00» (уникальный ID компьютера)
— width = «0» (ширина изображения)
— height = «0» (высота изображения)
— extract = «0» (ещё один непонятный параметр)
— orig_file = «clip.png» (название оригинального файла)
— file (собственно, сам файл)
Фактически мы передаём лишь пять параметров: language, mode, hwid, orig_file и file. Проведя несколько экспериментов, я пришёл к выводу, что обязательными параметрами являются только mode и file. - Пишем скрипт для передачи произвольного файла на сервер clip2net.com (скачать файл):
#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
use HTTP::Request::Common;
use constant USAGE => "Usage: clip2net-uploader USERNAME PASSWORD FILE\n";
# получаем параметры из командной строки
my $username = shift || undef;
my $password = shift || undef;
my $file = shift || undef;
# если не заданы имя пользователя или пароль - выходим
unless (defined $username && defined $password) {
print "Error: no username or password\n".USAGE;
exit 0;
}
# если файл не найден, выводим соответствующую ошибку и выходим
unless (defined $file && -e $file) {
print "Error: no file passed or file not exists\n".USAGE;
exit 0;
}
# создаём объект браузера
my $ua = LWP::UserAgent->new('agent' => 'Linux clip2net uploader');
# создаём объект для POST-запроса
my $req = POST('http://clip2net.com/upload/',
'Content_Type' => 'form-data',
'Content' => [
'mode' => 'upload',
'file' => [$file],
]
);
# задаём данные для авторизации
$req->authorization_basic($username, $password);
# выполняем POST-запрос и проверяем ответ
my $res = $ua->request($req);
if ($res->is_success) {
if ($res->content =~ /<url>(http:\/\/clip2net\.com\/.+?)<\/url>/s) {
# выводим на экран ссылку на закачанный файл и выходим
print "$1\n";
exit 1;
}
}
# получаем ошибку, выводим её на экран и выходим
my $error = $res->content;
chomp $error;
print "$error\n";
exit 0;
Скрипт откомментирован, поэтому разобраться в нём не составит труда. При необходимости, нужно будет поставить модули LWP::UserAgent и HTTP::Request::Common, это можно сделать через cpan (читать: man cpan).
Создаём файл /usr/local/bin/clip2net-uploader с приведённым выше кодом, ставим на файл права на запуск (sudo chmod +x /usr/local/bin/clip2net-uploader) и запускаем его, передав в качестве параметра логин, пароль на сайте clip2net и любой файл, который вы хотите выложить на сервер. Например, картинку:
> clip2net-uploader user password example.jpeg
В случае, если файл будет передан корректно, программа выдаст ссылку на файл, например:
> user@local:~$ clip2net-uploader user password example.jpeg
> clip2net.com/blah-blah-blah/example.jpeg
> user@local:~$
Если в процессе передачи файла возникнет ошибка, программа выдаст ошибку:
> user@local:~$ clip2net-uploader user password example.jpeg
> Incorrect username/password. Please check application settings.
> user@local:~$
Собираем всё вместе
Итак, мы имеем все необходимые инструменты для того, чтобы выполнить поставленную задачу. Собираем всё воедино (скачать файл):
#!/bin/bash
QUALITY="-q 80"
USERNAME="username"
PASSWORD="password"
PARAM=""
FILE=""
REMOVE=
if [ -z "$1" ]; then
echo "Error: please, select mode (--help for more info)"
exit
elif [ "$1" == "--help" ]; then
echo "Usage: clip2net MODE [FILENAME]"
echo "Mode is:"
echo " --screen - send whole screen"
echo " --window - send active window"
echo " --area - send area, selected with mouse"
echo " --file - show file selection dialog and send selected file"
echo " --file FILENAME - send file FILENAME"
exit
elif [ "$1" = "--file" ]; then
if [ -z "$2" ]; then
FILE=`zenity --title='Clip2net' --file-selection` || exit
elif [ -f "$2" ]; then
FILE=$2
else
echo "Error: file is not exists"
exit
fi
else
REMOVE=1
if [ "$1" = "--screen" ]; then
CONFIRM="Отправить скриншот всего экрана на сайт clip2net.com?"
PARAM=""
elif [ "$1" = "--window" ]; then
CONFIRM="Отправить скриншот окна текущей программы на сайт clip2net.com?"
PARAM="-q -b"
elif [ "$1" = "--area" ]; then
CONFIRM="Отправить скриншот выделенной области на сайт clip2net.com?"
PARAM="-s"
zenity --title='Clip2net' --info --text="Выделите область на экране для отправки на сайт clip2net. Для отмены нажмите любую кнопку клавиатуры"
else
echo "Error: please, select correct mode (--help for more info)"
exit
fi
FILE=`scrot $PARAM $QUALITY -e 'echo -n $f'` || exit
zenity --title='Clip2net' --question --text="$CONFIRM" || exit
fi
if [ -z "$FILE" ]; then
echo "Error: no file to send"
exit
fi
RES=`clip2net-uploader $USERNAME $PASSWORD $FILE`
if [ $? -eq 1 ]; then
zenity --title='Clip2net' --entry --text="Отправка успешна. Скопировать ссылку на файл в буфер обмена?" --entry-text="$RES" | xclip
else
zenity --title='Clip2net' --error --text="$RES"
fi
echo $RES
if [ $REMOVE -eq 1 ]; then
rm $FILE
fi
Создаём файл /usr/local/bin/clip2net с приведённым выше кодом, ставим на файл права на запуск (sudo chmod +x /usr/local/bin/clip2net) и правим настройки в самом начале файла: качество изображения (переменная QUALITY), логин и пароль на сайте clip2net.com (переменные USERNAME и PASSWORD). Если у вас нет логина и пароля — нужно зарегистрироваться на сайте.
В этом месте я хотел бы сделать небольшое замечание: мне удобно хранить свои скрипты в директории ~/.bin/ — так я не боюсь их потерять (ежедневно создаётся резервная копия домашней директории).
По умолчанию исполняемые файлы пользователя хранятся в директории ~/bin/, которой может и не быть. Это поведение задаётся в файле ~/.profile следующими строками:
> if [ -d "$HOME/bin" ] ; then
> PATH="$HOME/bin:$PATH"
> fi
Для того, чтобы скрипты хранились в директории ~/.bin/ меняем эти строки на:
> if [ -d "$HOME/.bin" ] ; then
> PATH="$HOME/.bin:$PATH"
> fi
и создаём эту директорию:
> user@local:~$ mkdir ~/.bin/
Теперь вы можете сохранять исполняемые файлы (свои скрипты) в домашней директории и они будут находится системой без указания полного пути к ним.
Режимы работы
Краткую подсказку по использованию этого файла можно получить, набрав команду «clip2net --help». Чуть более подробно:
> clip2net --screenСделает скриншот всего экрана, выведет окно с запросом подтверждения отправки его на сайт clip2net.com и в случае положительного ответа отправит файл.

> clip2net --windowСделает скриншот текущего окна, выведет окно с запросом и отправит скриншот на сайт.

> clip2net --areaВыдаст окно с информацией о том, что нужно выделить мышкой область на экране, дождётся выделения и покажет окно с запросом отправки файла на сайт. Отправит скриншот в случае утвердительного ответа.


> clip2net --fileвыведет окно со списком файлов и отправит выбранный пользователем файл на сайт без предупреждения (в случае нажатия кнопки «ОК»).

> clip2net --file /home/user/pictures/example.jpegотправит файл /home/user/pictures/example.jpeg на сайт (без показа подтверждающего окна).

В случае возникновения ошибки, программа выдаст окно с ошибкой либо выдаст ошибку в STDOUT (если ошибка низкого уровня).
Управление
Открывать консоль и набирать нужную команду — это, конечно, «тру», но в повседневной работе это не всегда удобно. Можно сделать кнопки на панели задач, либо повесить сочетания клавиш на эти действия.
Дальше речь пойдёт о менеджере окон «Gnome».
Для настройки в KDE обратитесь к документации, гуглу или знакомому линуксоиду.
Для настройки в Awesome (а я использую именно его) обратитесь ко мне ;)
Для того, чтобы добавить кнопку на панель задач, нужно кликнуть на ней правой кнопкой и выбрать пункт «Добавить на панель...», выбрать апплет «Пользовательская кнопка запуска» и настроить запускаемое приложение (задать название, исполняемый файл и иконку). Например:

Для добавления горячей кнопки выбираем меню «Система->Параметры->Комбинации клавиш клавиатуры», нажимаем «Добавить» в открывшемся окне и вводим название команды и исполняемый файл:

Далее, выбираем новую команду, кликнув на ней мышью и нажимаем нужное сочетание клавиш. Всё, настройка закончена.
Что дальше?
Это всего лишь пример подхода к решению возникшей задачи с помощью инструментов ОС *NIX. Тем не менее, это вполне живой и рабочий пример, — я пользуюсь этой программой практически каждый день.
Совсем не обязательно ждать у моря погоды или писать разработчикам программы просьбы портировать её под Linux (тем более, что разработчикам это, зачастую, просто не нужно). Читайте маны, изучайте инструментарий и подходите с фантазией к любой задаче — и вы сможете решить её просто, быстро и элегантно.
Надеюсь, статья будет полезна как новичкам, так и продвинутым пользователям.
_________
Текст подготовлен в редакторе VIM ;)



комментарии (51)